Parent

Facter::Util::Resolution

Constants

INTERPRETER

Attributes

code[RW]
interpreter[RW]
name[RW]
timeout[RW]

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 72
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 117
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

  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' unless expanded_code
  rescue Errno::ENOENT => detail
    # command not found on Windows
    return nil
  rescue => detail
    $stderr.puts detail
    return nil
  end

  if out == ""
    return nil
  else
    return out
  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 92
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 162
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 19
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 36
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

Public Instance Methods

confine(confines) click to toggle source

Add a new confine to the resolution mechanism.

# File lib/facter/util/resolution.rb, line 151
def confine(confines)
  confines.each do |fact, values|
    @confines.push Facter::Util::Confine.new(fact, *values)
  end
end
has_weight(weight) click to toggle source
# File lib/facter/util/resolution.rb, line 157
def has_weight(weight)
  @weight = weight
end
interpreter=(interp) click to toggle source
# File lib/facter/util/resolution.rb, line 205
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 182
def limit
  @timeout
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 187
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 211
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 219
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 224
def 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
    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
    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 171
def weight
  if @weight
    @weight
  else
    @confines.length
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.