Autoload paths, either based on names or all at once.
# File lib/puppet/util/autoload.rb, line 220 def changed?(name) self.class.changed?(expand(name)) end
# File lib/puppet/util/autoload.rb, line 228 def expand(name) ::File.join(@path, name.to_s) end
# File lib/puppet/util/autoload.rb, line 224 def files_to_load self.class.files_to_load(@path) end
# File lib/puppet/util/autoload.rb, line 198 def load(name, env = nil) self.class.load_file(expand(name), env) end
Load all instances from a path of ::search_directories matching the relative path this Autoloader was initialized with. For example, if we have created a Puppet::Util::Autoload for Puppet::Type::User with a path of ‘puppet/provider/user’, the ::search_directories path will be searched for all ruby files matching puppet/provider/user/*.rb and they will then be loaded from the first directory in the search path providing them. So earlier entries in the search path may shadow later entries.
This uses require, rather than load, so that already-loaded files don’t get reloaded unnecessarily.
# File lib/puppet/util/autoload.rb, line 212 def loadall(env = nil) self.class.loadall(@path, env) end
# File lib/puppet/util/autoload.rb, line 216 def loaded?(name) self.class.loaded?(expand(name)) end
# File lib/puppet/util/autoload.rb, line 42 def changed?(name) name = cleanpath(name).chomp('.rb') return true unless loaded.include?(name) file, old_mtime = loaded[name] environment = Puppet.lookup(:current_environment) return true unless file == get_file(name, environment) begin old_mtime.to_i != File.mtime(file).to_i rescue Errno::ENOENT true end end
Normalize a path. This converts ALT_SEPARATOR to SEPARATOR on Windows and eliminates unnecessary parts of a path.
# File lib/puppet/util/autoload.rb, line 169 def cleanpath(path) # There are two cases here because cleanpath does not handle absolute # paths correctly on windows (c:\ and c:/ are treated as distinct) but # we don't want to convert relative paths to absolute if Puppet::Util.absolute_path?(path) File.expand_path(path) else Pathname.new(path).cleanpath.to_s end end
# File lib/puppet/util/autoload.rb, line 97 def files_in_dir(dir, path) dir = Pathname.new(File.expand_path(dir)) Dir.glob(File.join(dir, path, "*.rb")).collect do |file| Pathname.new(file).relative_path_from(dir).to_s end end
# File lib/puppet/util/autoload.rb, line 93 def files_to_load(path, env = nil) search_directories(env).map {|dir| files_in_dir(dir, path) }.flatten.uniq end
# File lib/puppet/util/autoload.rb, line 159 def gem_directories gem_source.directories end
# File lib/puppet/util/autoload.rb, line 18 def gem_source @gem_source ||= Puppet::Util::RubyGems::Source.new end
Get the correct file to load for a given path returns nil if no file is found
# File lib/puppet/util/autoload.rb, line 87 def get_file(name, env) name = name + '.rb' unless name =~ /\.rb$/ path = search_directories(env).find { |dir| Puppet::FileSystem.exist?(File.join(dir, name)) } path and File.join(path, name) end
# File lib/puppet/util/autoload.rb, line 149 def libdirs() # See the comments in #module_directories above. Basically, we need to be careful not to try to access the # libdir before we know for sure that all of the settings have been initialized (e.g., during bootstrapping). if (Puppet.settings.app_defaults_initialized?) Puppet[:libdir].split(File::PATH_SEPARATOR) else [] end end
Load a single plugin by name. We use ‘load’ here so we can reload a given plugin.
# File lib/puppet/util/autoload.rb, line 57 def load_file(name, env) file = get_file(name.to_s, env) return false unless file begin mark_loaded(name, file) Kernel.load file, @wrap return true rescue SystemExit,NoMemoryError raise rescue Exception => detail message = "Could not autoload #{name}: #{detail}" Puppet.log_exception(detail, message) raise Puppet::Error, message, detail.backtrace end end
# File lib/puppet/util/autoload.rb, line 73 def loadall(path, env = nil) # Load every instance of everything we can find. files_to_load(path, env).each do |file| name = file.chomp(".rb") load_file(name, env) unless loaded?(name) end end
Has a given path been loaded? This is used for testing whether a changed file should be loaded or just ignored. This is only used in network/client/master, when downloading plugins, to see if a given plugin is currently loaded and thus should be reloaded.
# File lib/puppet/util/autoload.rb, line 27 def loaded?(path) path = cleanpath(path).chomp('.rb') loaded.include?(path) end
Save the fact that a given path has been loaded. This is so we can load downloaded plugins if they’ve already been loaded into memory.
# File lib/puppet/util/autoload.rb, line 35 def mark_loaded(name, file) name = cleanpath(name).chomp('.rb') ruby_file = name + ".rb" $LOADED_FEATURES << ruby_file unless $LOADED_FEATURES.include?(ruby_file) loaded[name] = [file, File.mtime(file)] end
# File lib/puppet/util/autoload.rb, line 104 def module_directories(env) # We're using a per-thread cache of module directories so that we don't # scan the filesystem each time we try to load something. This is reset # at the beginning of compilation and at the end of an agent run. $env_module_directories ||= {} # This is a little bit of a hack. Basically, the autoloader is being # called indirectly during application bootstrapping when we do things # such as check "features". However, during bootstrapping, we haven't # yet parsed all of the command line parameters nor the config files, # and thus we don't yet know with certainty what the module path is. # This should be irrelevant during bootstrapping, because anything that # we are attempting to load during bootstrapping should be something # that we ship with puppet, and thus the module path is irrelevant. # # In the long term, I think the way that we want to handle this is to # have the autoloader ignore the module path in all cases where it is # not specifically requested (e.g., by a constructor param or # something)... because there are very few cases where we should # actually be loading code from the module path. However, until that # happens, we at least need a way to prevent the autoloader from # attempting to access the module path before it is initialized. For # now we are accomplishing that by calling the # "app_defaults_initialized?" method on the main puppet Settings object. # --cprice 2012-03-16 if Puppet.settings.app_defaults_initialized? env ||= Puppet.lookup(:environments).get(Puppet[:environment]) if env # if the app defaults have been initialized then it should be safe to access the module path setting. $env_module_directories[env] ||= env.modulepath.collect do |dir| Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f, "lib") } end.flatten.find_all do |d| FileTest.directory?(d) end else [] end else # if we get here, the app defaults have not been initialized, so we basically use an empty module path. [] end end
# File lib/puppet/util/autoload.rb, line 186 def initialize(obj, path, options = {}) @path = path.to_s raise ArgumentError, "Autoload paths cannot be fully qualified" if Puppet::Util.absolute_path?(@path) @object = obj self.class[obj] = self set_options(options) @wrap = true unless defined?(@wrap) end
# File lib/puppet/util/autoload.rb, line 81 def reload_changed loaded.keys.each { |file| load_file(file, nil) if changed?(file) } end
# File lib/puppet/util/autoload.rb, line 163 def search_directories(env) [gem_directories, module_directories(env), libdirs(), $LOAD_PATH].flatten end