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 72: def self.absolute_path?(path, platform=nil) 73: # Escape once for the string literal, and once for the regex. 74: slash = '[\\/]' 75: name = '[^\\/]+' 76: regexes = { 77: :windows => %^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!, 78: :posix => %^/!, 79: } 80: platform ||= Facter::Util::Config.is_windows? ? :windows : :posix 81: 82: !! (path =~ regexes[platform]) 83: 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 117: def self.exec(code, interpreter = nil) 118: Facter.warnonce "The interpreter parameter to 'exec' is deprecated and will be removed in a future version." if interpreter 119: 120: if expanded_code = expand_command(code) 121: # if we can find the binary, we'll run the command with the expanded path to the binary 122: code = expanded_code 123: else 124: # if we cannot find the binary return nil on posix. On windows we'll still try to run the 125: # command in case it is a shell-builtin. In case it is not, windows will raise Errno::ENOENT 126: return nil unless Facter::Util::Config.is_windows? 127: return nil if absolute_path?(code) 128: end 129: 130: out = nil 131: 132: begin 133: out = %{#{code}}.chomp 134: 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 135: rescue Errno::ENOENT => detail 136: # command not found on Windows 137: return nil 138: rescue => detail 139: $stderr.puts detail 140: return nil 141: end 142: 143: if out == "" 144: return nil 145: else 146: return out 147: end 148: 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 92: def self.expand_command(command) 93: if match = /^"(.+?)"(?:\s+(.*))?/.match(command) 94: exe, arguments = match.captures 95: exe = which(exe) and [ "\"#{exe}\"", arguments ].compact.join(" ") 96: elsif match = /^'(.+?)'(?:\s+(.*))?/.match(command) and not Facter::Util::Config.is_windows? 97: exe, arguments = match.captures 98: exe = which(exe) and [ "'#{exe}'", arguments ].compact.join(" ") 99: else 100: exe, arguments = command.split(/ /,2) 101: if exe = which(exe) 102: # the binary was not quoted which means it contains no spaces. But the 103: # full path to the binary may do so. 104: exe = "\"#{exe}\"" if exe =~ /\s/ and Facter::Util::Config.is_windows? 105: exe = "'#{exe}'" if exe =~ /\s/ and not Facter::Util::Config.is_windows? 106: [ exe, arguments ].compact.join(" ") 107: end 108: end 109: end
Create a new resolution mechanism.
# File lib/facter/util/resolution.rb, line 162 162: def initialize(name) 163: @name = name 164: @confines = [] 165: @value = nil 166: @timeout = 0 167: @weight = nil 168: 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 19: def self.search_paths 20: if Facter::Util::Config.is_windows? 21: ENV['PATH'].split(File::PATH_SEPARATOR) 22: else 23: # Make sure facter is usable even for non-root users. Most commands 24: # in /sbin (like ifconfig) can be run as non priviledged users as 25: # long as they do not modify anything - which we do not do with facter 26: ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/sbin', '/usr/sbin' ] 27: end 28: 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 36: def self.which(bin) 37: if absolute_path?(bin) 38: return bin if File.executable?(bin) 39: if Facter::Util::Config.is_windows? and File.extname(bin).empty? 40: exts = ENV['PATHEXT'] 41: exts = exts ? exts.split(File::PATH_SEPARATOR) : ].COM .EXE .BAT .CMD] 42: exts.each do |ext| 43: destext = bin + ext 44: if File.executable?(destext) 45: Facter.warnonce("Using Facter::Util::Resolution.which with an absolute path like #{bin} but no fileextension is deprecated. Please add the correct extension (#{ext})") 46: return destext 47: end 48: end 49: end 50: else 51: search_paths.each do |dir| 52: dest = File.join(dir, bin) 53: if Facter::Util::Config.is_windows? 54: dest.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) 55: if File.extname(dest).empty? 56: exts = ENV['PATHEXT'] 57: exts = exts ? exts.split(File::PATH_SEPARATOR) : ].COM .EXE .BAT .CMD] 58: exts.each do |ext| 59: destext = dest + ext 60: return destext if File.executable?(destext) 61: end 62: end 63: end 64: return dest if File.executable?(dest) 65: end 66: end 67: nil 68: end
Add a new confine to the resolution mechanism.
# File lib/facter/util/resolution.rb, line 151 151: def confine(confines) 152: confines.each do |fact, values| 153: @confines.push Facter::Util::Confine.new(fact, *values) 154: end 155: end
# File lib/facter/util/resolution.rb, line 157 157: def has_weight(weight) 158: @weight = weight 159: end
# File lib/facter/util/resolution.rb, line 200 200: def interpreter 201: Facter.warnonce "The 'Facter::Util::Resolution.interpreter' method is deprecated and will be removed in a future version." 202: @interpreter 203: end
# File lib/facter/util/resolution.rb, line 205 205: def interpreter=(interp) 206: Facter.warnonce "The 'Facter::Util::Resolution.interpreter=' method is deprecated and will be removed in a future version." 207: @interpreter = interp 208: 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 182: def limit 183: @timeout 184: end
Set our code for returning a value.
# File lib/facter/util/resolution.rb, line 187 187: def setcode(string = nil, interp = nil, &block) 188: Facter.warnonce "The interpreter parameter to 'setcode' is deprecated and will be removed in a future version." if interp 189: if string 190: @code = string 191: @interpreter = interp || INTERPRETER 192: else 193: unless block_given? 194: raise ArgumentError, "You must pass either code or a block" 195: end 196: @code = block 197: end 198: end
Is this resolution mechanism suitable on the system in question?
# File lib/facter/util/resolution.rb, line 211 211: def suitable? 212: unless defined? @suitable 213: @suitable = ! @confines.detect { |confine| ! confine.true? } 214: end 215: 216: return @suitable 217: end
# File lib/facter/util/resolution.rb, line 219 219: def to_s 220: return self.value() 221: end
How we get a value for our resolution mechanism.
# File lib/facter/util/resolution.rb, line 224 224: def value 225: result = nil 226: return result if @code == nil 227: 228: starttime = Time.now.to_f 229: 230: begin 231: Timeout.timeout(limit) do 232: if @code.is_a?(Proc) 233: result = @code.call() 234: else 235: result = Facter::Util::Resolution.exec(@code) 236: end 237: end 238: rescue Timeout::Error => detail 239: warn "Timed out seeking value for %s" % self.name 240: 241: # This call avoids zombies -- basically, create a thread that will 242: # dezombify all of the child processes that we're ignoring because 243: # of the timeout. 244: Thread.new { Process.waitall } 245: return nil 246: rescue => details 247: warn "Could not retrieve %s: %s" % [self.name, details] 248: return nil 249: end 250: 251: finishtime = Time.now.to_f 252: ms = (finishtime - starttime) * 1000 253: Facter.show_time "#{self.name}: #{"%.2f" % ms}ms" 254: 255: return nil if result == "" 256: return result 257: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.