require 'facter' require 'pathname' require 'facter/util/directory_loader' # Load facts on demand. class Facter::Util::Loader def initialize @loaded = [] @valid_path = {} end # Load all resolutions for a single fact. def load(fact) # Now load from the search path shortname = fact.to_s.downcase load_env(shortname) filename = shortname + ".rb" search_path.each do |dir| # Load individual files file = File.join(dir, filename) load_file(file) if FileTest.exist?(file) # And load any directories matching the name factdir = File.join(dir, shortname) load_dir(factdir) if FileTest.directory?(factdir) end end # Load all facts from all directories. def load_all return if defined?(@loaded_all) load_env search_path.each do |dir| next unless FileTest.directory?(dir) Dir.entries(dir).sort.each do |file| path = File.join(dir, file) if File.directory?(path) load_dir(path) elsif file =~ /\.rb$/ load_file(File.join(dir, file)) end end end @loaded_all = true end # The list of directories we're going to search through for facts. def search_path result = [] result += $LOAD_PATH.collect { |d| File.join(d, "facter") } if ENV.include?("FACTERLIB") result += ENV["FACTERLIB"].split(File::PATH_SEPARATOR) end # This allows others to register additional paths we should search. result += Facter.search_path result.select do |dir| good = valid_search_path? dir Facter.debugonce("Relative directory #{dir} removed from search path.") unless good good end end def valid_search_path?(path) return @valid_path[path] unless @valid_path[path].nil? return @valid_path[path] = Pathname.new(path).absolute? end private :valid_search_path? private def load_dir(dir) return if dir =~ /\/\.+$/ or dir =~ /\/util$/ or dir =~ /\/lib$/ Dir.entries(dir).find_all { |f| f =~ /\.rb$/ }.sort.each do |file| load_file(File.join(dir, file)) end end def load_file(file) return if @loaded.include? file # We have to specify Kernel.load, because we have a load method. begin # Store the file path so we don't try to reload it @loaded << file Kernel.load(file) rescue ScriptError => detail # Don't store the path if the file can't be loaded # in case it's loadable later on. @loaded.delete(file) Facter.warn "Error loading fact #{file} #{detail}" end end # Load facts from the environment. If no name is provided, # all will be loaded. def load_env(fact = nil) # Load from the environment, if possible ENV.each do |name, value| # Skip anything that doesn't match our regex. next unless name =~ /^facter_?(\w+)$/i env_name = $1 # If a fact name was specified, skip anything that doesn't # match it. next if fact and env_name != fact Facter.add($1) do has_weight 1_000_000 setcode { value } end # Short-cut, if we are only looking for one value. break if fact end end end