Class: Facter::Util::Resolution

### Home Classes Methods

### In Files

- lib/facter/util/resolution.rb

### Parent

Object

### Methods

- ::absolute_path?
- ::exec
- ::expand_command
- ::new
- ::search_paths
- ::which
- ::with_env
- #confine
- #flush
- #has_weight
- #interpreter=
- #limit
- #on_flush
- #setcode
- #suitable?
- #to_s
- #value
- #weight

### Files

- LICENSE
- Rakefile
- THANKS

### Class/Module Index

Quicksearch

- Facter
- Facter::Application
- Facter::Manufacturer
- Facter::Memory
- Facter::NetMask
- Facter::Util
- Facter::Util::CFPropertyList
- Facter::Util::CFPropertyList::CFArray
- Facter::Util::CFPropertyList::CFBoolean
- Facter::Util::CFPropertyList::CFData
- Facter::Util::CFPropertyList::CFDate
- Facter::Util::CFPropertyList::CFDictionary
- Facter::Util::CFPropertyList::CFInteger
- Facter::Util::CFPropertyList::CFReal
- Facter::Util::CFPropertyList::CFString
- Facter::Util::CFPropertyList::CFType
- Facter::Util::CFPropertyList::XML
- Facter::Util::Collection
- Facter::Util::CompositeLoader
- Facter::Util::Config
- Facter::Util::Confine
- Facter::Util::DirectoryLoader
- Facter::Util::DirectoryLoader::NoSuchDirectoryError
- Facter::Util::EC2
- Facter::Util::Fact
- Facter::Util::FileRead
- Facter::Util::IP
- Facter::Util::IP::Windows
- Facter::Util::IP::Windows::Bindings4
- Facter::Util::IP::Windows::Bindings6
- Facter::Util::Loader
- Facter::Util::Macaddress
- Facter::Util::Macaddress::Darwin
- Facter::Util::Macaddress::Windows
- Facter::Util::Macosx
- Facter::Util::MonkeyPatches
- Facter::Util::MonkeyPatches::Lines
- Facter::Util::NothingLoader
- Facter::Util::Parser
- Facter::Util::Parser::Base
- Facter::Util::Parser::JsonParser
- Facter::Util::Parser::KeyValuePairOutputFormat
- Facter::Util::Parser::NothingParser
- Facter::Util::Parser::PowershellParser
- Facter::Util::Parser::ScriptParser
- Facter::Util::Parser::TextParser
- Facter::Util::Parser::YamlParser
- Facter::Util::Processor
- Facter::Util::Registry
- Facter::Util::Resolution
- Facter::Util::SolarisZones
- Facter::Util::Uptime
- Facter::Util::Values
- Facter::Util::Virtual
- Facter::Util::Vlans
- Facter::Util::WMI
- Facter::Util::Xendomains
- Plist
- Plist::Emit
- Plist::Listener
- Plist::PArray
- Plist::PData
- Plist::PDate
- Plist::PDict
- Plist::PFalse
- Plist::PInteger
- Plist::PKey
- Plist::PList
- Plist::PReal
- Plist::PString
- Plist::PTag
- Plist::PTrue
- Plist::StreamParser
- CFFormatError
- CFPlistError
- CFTypeError
- IO
- Object
- String

No matching classes.

# 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
          $stderr.puts 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
        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 210
    def weight
      if @weight
        @weight
      else
        @confines.length
      end
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.