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
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 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
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
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
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
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
# File lib/facter/util/resolution.rb, line 157 def has_weight(weight) @weight = weight end
# 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
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
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
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
# File lib/facter/util/resolution.rb, line 219 def to_s return self.value() end
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
Generated with the Darkfish Rdoc Generator 2.