Parent

Class/Module Index [+]

Quicksearch

Facter::Util::Resolution

Constants

INTERPRETER

Attributes

code[RW]
interpreter[RW]
name[RW]
timeout[RW]
value[W]
weight[W]

Public Class Methods

absolute_path?(path, platform=nil) click to toggle source

Determine in a platform-specific way whether a path is absolute. This defaults to the local platform if none is specified.

# File lib/facter/util/resolution.rb, line 73
def self.absolute_path?(path, platform=nil)
  # Escape once for the string literal, and once for the regex.
  slash = '[\\/]'
  name = '[^\\/]+'
  regexes = {
    :windows => %^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!,
    :posix   => %^/!,
  }
  platform ||= Facter::Util::Config.is_windows? ? :windows : :posix

  !! (path =~ regexes[platform])
end
exec(code, interpreter = nil) click to toggle source

Execute a program and return the output of that program.

Returns nil if the program can’t be found, or if there is a problem executing the code.

# File lib/facter/util/resolution.rb, line 151
def self.exec(code, interpreter = nil)
  Facter.warnonce "The interpreter parameter to 'exec' is deprecated and will be removed in a future version." if interpreter

  ## Set LANG to force i18n to C for the duration of this exec; this ensures that any code that parses the
  ## output of the command can expect it to be in a consistent / predictable format / locale
  with_env "LANG" => "C" do
    
    if expanded_code = expand_command(code)
      # if we can find the binary, we'll run the command with the expanded path to the binary
      code = expanded_code
    else
      # if we cannot find the binary return nil on posix. On windows we'll still try to run the
      # command in case it is a shell-builtin. In case it is not, windows will raise Errno::ENOENT
      return nil unless Facter::Util::Config.is_windows?
      return nil if absolute_path?(code)
    end
    
    out = nil

    begin
      out = %{#{code}}.chomp
      Facter.warnonce "Using Facter::Util::Resolution.exec with a shell built-in is deprecated. Most built-ins can be replaced with native ruby commands. If you really have to run a built-in, pass \"cmd /c your_builtin\" as a command (command responsible for this message was \"#{code}\")" unless expanded_code
    rescue Errno::ENOENT => detail
      # command not found on Windows
      return nil
    rescue => detail
      Facter.warn(detail)
      return nil
    end
    
    if out == ""
      return nil
    else
      return out
    end
  end
end
expand_command(command) click to toggle source

Expand the executable of a commandline to an absolute path. The executable is the first word of the commandline. If the executable contains spaces, it has be but in double quotes to be properly recognized.

Returns the commandline with the expanded binary or nil if the binary can’t be found. If the path to the binary contains quotes, the whole binary is put in quotes.

# File lib/facter/util/resolution.rb, line 93
def self.expand_command(command)
  if match = /^"(.+?)"(?:\s+(.*))?/.match(command)
    exe, arguments = match.captures
    exe = which(exe) and [ "\"#{exe}\"", arguments ].compact.join(" ")
  elsif match = /^'(.+?)'(?:\s+(.*))?/.match(command) and not Facter::Util::Config.is_windows?
    exe, arguments = match.captures
    exe = which(exe) and [ "'#{exe}'", arguments ].compact.join(" ")
  else
    exe, arguments = command.split(/ /,2)
    if exe = which(exe)
      # the binary was not quoted which means it contains no spaces. But the
      # full path to the binary may do so.
      exe = "\"#{exe}\"" if exe =~ /\s/ and Facter::Util::Config.is_windows?
      exe = "'#{exe}'" if exe =~ /\s/ and not Facter::Util::Config.is_windows?
      [ exe, arguments ].compact.join(" ")
    end
  end
end
new(name) click to toggle source

Create a new resolution mechanism.

# File lib/facter/util/resolution.rb, line 201
def initialize(name)
  @name = name
  @confines = []
  @value = nil
  @timeout = 0
  @weight = nil
end
search_paths() click to toggle source

Returns the locations to be searched when looking for a binary. This is currently determined by the PATH environment variable plus /sbin and /usr/sbin when run on unix

# File lib/facter/util/resolution.rb, line 20
def self.search_paths
  if Facter::Util::Config.is_windows?
    ENV['PATH'].split(File::PATH_SEPARATOR)
  else
    # Make sure facter is usable even for non-root users. Most commands
    # in /sbin (like ifconfig) can be run as non priviledged users as
    # long as they do not modify anything - which we do not do with facter
    ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/sbin', '/usr/sbin' ]
  end
end
which(bin) click to toggle source

Determine the full path to a binary. If the supplied filename does not already describe an absolute path then different locations (determined by self.search_paths) will be searched for a match.

Returns nil if no matching executable can be found otherwise returns the expanded pathname.

# File lib/facter/util/resolution.rb, line 37
def self.which(bin)
  if absolute_path?(bin)
    return bin if File.executable?(bin)
    if Facter::Util::Config.is_windows? and File.extname(bin).empty?
      exts = ENV['PATHEXT']
      exts = exts ? exts.split(File::PATH_SEPARATOR) : ].COM .EXE .BAT .CMD]
      exts.each do |ext|
        destext = bin + ext
        if File.executable?(destext)
          Facter.warnonce("Using Facter::Util::Resolution.which with an absolute path like #{bin} but no fileextension is deprecated. Please add the correct extension (#{ext})")
          return destext
        end
      end
    end
  else
    search_paths.each do |dir|
      dest = File.join(dir, bin)
      if Facter::Util::Config.is_windows?
        dest.gsub!(File::SEPARATOR, File::ALT_SEPARATOR)
        if File.extname(dest).empty?
          exts = ENV['PATHEXT']
          exts = exts ? exts.split(File::PATH_SEPARATOR) : ].COM .EXE .BAT .CMD]
          exts.each do |ext|
            destext = dest + ext
            return destext if File.executable?(destext)
          end
        end
      end
      return dest if File.executable?(dest)
    end
  end
  nil
end
with_env(values) click to toggle source

Call this method with a block of code for which you would like to temporarily modify one or more environment variables; the specified values will be set for the duration of your block, after which the original values (if any) will be restored.

values

a Hash containing the key/value pairs of any environment variables that you

would like to temporarily override

# File lib/facter/util/resolution.rb, line 119
def self.with_env(values)
  old = {}
  values.each do |var, value|
    # save the old value if it exists
    if old_val = ENV[var]
      old[var] = old_val
    end
    # set the new (temporary) value for the environment variable
    ENV[var] = value
  end
  # execute the caller's block, capture the return value
  rv = yield
# use an ensure block to make absolutely sure we restore the variables
ensure
  # restore the old values
  values.each do |var, value|
    if old.include?(var)
      ENV[var] = old[var]
    else
      # if there was no old value, delete the key from the current environment variables hash
      ENV.delete(var)
    end
  end
  # return the captured return value
  rv
end

Public Instance Methods

confine(confines) click to toggle source

Add a new confine to the resolution mechanism.

# File lib/facter/util/resolution.rb, line 190
def confine(confines)
  confines.each do |fact, values|
    @confines.push Facter::Util::Confine.new(fact, *values)
  end
end
flush() click to toggle source

flush executes the block, if any, stored by the {on_flush} method

@see Facter::Util::Fact#flush @see Facter::Util::Resolution#on_flush

@api private

# File lib/facter/util/resolution.rb, line 266
def flush
  @on_flush_block.call if @on_flush_block
end
has_weight(weight) click to toggle source
# File lib/facter/util/resolution.rb, line 196
def has_weight(weight)
  @weight = weight
end
interpreter=(interp) click to toggle source
# File lib/facter/util/resolution.rb, line 275
def interpreter=(interp)
  Facter.warnonce "The 'Facter::Util::Resolution.interpreter=' method is deprecated and will be removed in a future version."
  @interpreter = interp
end
limit() click to toggle source

We need this as a getter for ‘timeout’, because some versions of ruby seem to already have a ‘timeout’ method and we can’t seem to override the instance methods, somehow.

# File lib/facter/util/resolution.rb, line 221
def limit
  @timeout
end
on_flush(&block) click to toggle source

on_flush accepts a block and executes the block when the resolution's value is flushed. This makes it possible to model a single, expensive system call inside of a Ruby object and then define multiple dynamic facts which resolve by sending messages to the model instance. If one of the dynamic facts is flushed then it can, in turn, flush the data stored in the model instance to keep all of the dynamic facts in sync without making multiple, expensive, system calls.

Please see the Solaris zones fact for an example of how this feature may be used.

@see Facter::Util::Fact#flush @see Facter::Util::Resolution#flush

@api public

# File lib/facter/util/resolution.rb, line 255
def on_flush(&block)
  @on_flush_block = block
end
setcode(string = nil, interp = nil, &block) click to toggle source

Set our code for returning a value.

# File lib/facter/util/resolution.rb, line 226
def setcode(string = nil, interp = nil, &block)
  Facter.warnonce "The interpreter parameter to 'setcode' is deprecated and will be removed in a future version." if interp
  if string
    @code = string
    @interpreter = interp || INTERPRETER
  else
    unless block_given?
      raise ArgumentError, "You must pass either code or a block"
    end
    @code = block
  end
end
suitable?() click to toggle source

Is this resolution mechanism suitable on the system in question?

# File lib/facter/util/resolution.rb, line 281
def suitable?
  unless defined? @suitable
    @suitable = ! @confines.detect { |confine| ! confine.true? }
  end

  return @suitable
end
to_s() click to toggle source
# File lib/facter/util/resolution.rb, line 289
def to_s
  return self.value()
end
value() click to toggle source

How we get a value for our resolution mechanism.

# File lib/facter/util/resolution.rb, line 294
def value
  return @value if @value
  result = nil
  return result if @code == nil

  starttime = Time.now.to_f

  begin
    Timeout.timeout(limit) do
      if @code.is_a?(Proc)
        result = @code.call()
      else
        result = Facter::Util::Resolution.exec(@code)
      end
    end
  rescue Timeout::Error => detail
    Facter.warn "Timed out seeking value for %s" % self.name

    # This call avoids zombies -- basically, create a thread that will
    # dezombify all of the child processes that we're ignoring because
    # of the timeout.
    Thread.new { Process.waitall }
    return nil
  rescue => details
    Facter.warn "Could not retrieve %s: %s" % [self.name, details]
    return nil
  end

  finishtime = Time.now.to_f
  ms = (finishtime - starttime) * 1000
  Facter.show_time "#{self.name}: #{"%.2f" % ms}ms"

  return nil if result == ""
  return result
end
weight() click to toggle source

Return the importance of this resolution.

# File lib/facter/util/resolution.rb, line 210
def weight
  if @weight
    @weight
  else
    @confines.length
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.