class Puppet::Util::Autoload
Autoload paths, either based on names or all at once.
Attributes
Public Class Methods
@api private
# File lib/puppet/util/autoload.rb 60 def changed?(name, env) 61 name = cleanpath(name).chomp('.rb') 62 return true unless loaded.include?(name) 63 file, old_mtime = loaded[name] 64 return true unless file == get_file(name, env) 65 begin 66 old_mtime.to_i != File.mtime(file).to_i 67 rescue Errno::ENOENT 68 true 69 end 70 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 169 def cleanpath(path) 170 Pathname.new(path).cleanpath.to_s 171 end
@api private
# File lib/puppet/util/autoload.rb 120 def files_in_dir(dir, path) 121 dir = Pathname.new(Puppet::FileSystem.expand_path(dir)) 122 Dir.glob(File.join(dir, path, "*.rb")).collect do |file| 123 Pathname.new(file).relative_path_from(dir).to_s 124 end 125 end
# File lib/puppet/util/autoload.rb 115 def files_to_load(path, env) 116 search_directories(env).map {|dir| files_in_dir(dir, path) }.flatten.uniq 117 end
@api private
# File lib/puppet/util/autoload.rb 135 def gem_directories 136 gem_source.directories 137 end
# File lib/puppet/util/autoload.rb 34 def gem_source 35 @gem_source ||= Puppet::Util::RubyGems::Source.new 36 end
Get the correct file to load for a given path returns nil if no file is found @api private
# File lib/puppet/util/autoload.rb 109 def get_file(name, env) 110 name = name + '.rb' unless name =~ /\.rb$/ 111 path = search_directories(env).find { |dir| Puppet::FileSystem.exist?(File.join(dir, name)) } 112 path and File.join(path, name) 113 end
Load a single plugin by name. We use 'load' here so we can reload a given plugin.
# File lib/puppet/util/autoload.rb 74 def load_file(name, env) 75 file = get_file(name.to_s, env) 76 return false unless file 77 begin 78 mark_loaded(name, file) 79 Kernel.load file 80 return true 81 rescue SystemExit,NoMemoryError 82 raise 83 rescue Exception => detail 84 message = _("Could not autoload %{name}: %{detail}") % { name: name, detail: detail } 85 Puppet.log_exception(detail, message) 86 raise Puppet::Error, message, detail.backtrace 87 end 88 end
# File lib/puppet/util/autoload.rb 90 def loadall(path, env) 91 # Load every instance of everything we can find. 92 files_to_load(path, env).each do |file| 93 name = file.chomp(".rb") 94 load_file(name, env) unless loaded?(name) 95 end 96 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 43 def loaded?(path) 44 path = cleanpath(path).chomp('.rb') 45 loaded.include?(path) 46 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. @api private
# File lib/puppet/util/autoload.rb 52 def mark_loaded(name, file) 53 name = cleanpath(name).chomp('.rb') 54 file = File.expand_path(file) 55 $LOADED_FEATURES << file unless $LOADED_FEATURES.include?(file) 56 loaded[name] = [file, File.mtime(file)] 57 end
@api private
# File lib/puppet/util/autoload.rb 128 def module_directories(env) 129 raise ArgumentError, "Autoloader requires an environment" unless env 130 131 Puppet::Util::ModuleDirectoriesAdapter.adapt(env).directories 132 end
# File lib/puppet/util/autoload.rb 176 def initialize(obj, path) 177 @path = path.to_s 178 raise ArgumentError, _("Autoload paths cannot be fully qualified") if Puppet::Util.absolute_path?(@path) 179 @object = obj 180 end
# File lib/puppet/util/autoload.rb 98 def reload_changed(env) 99 loaded.keys.each do |file| 100 if changed?(file, env) 101 load_file(file, env) 102 end 103 end 104 end
@api private
# File lib/puppet/util/autoload.rb 140 def search_directories(env) 141 # This is a little bit of a hack. Basically, the autoloader is being 142 # called indirectly during application bootstrapping when we do things 143 # such as check "features". However, during bootstrapping, we haven't 144 # yet parsed all of the command line parameters nor the config files, 145 # and thus we don't yet know with certainty what the module path is. 146 # This should be irrelevant during bootstrapping, because anything that 147 # we are attempting to load during bootstrapping should be something 148 # that we ship with puppet, and thus the module path is irrelevant. 149 # 150 # In the long term, I think the way that we want to handle this is to 151 # have the autoloader ignore the module path in all cases where it is 152 # not specifically requested (e.g., by a constructor param or 153 # something)... because there are very few cases where we should 154 # actually be loading code from the module path. However, until that 155 # happens, we at least need a way to prevent the autoloader from 156 # attempting to access the module path before it is initialized. For 157 # now we are accomplishing that by calling the 158 # "app_defaults_initialized?" method on the main puppet Settings object. 159 # --cprice 2012-03-16 160 if Puppet.settings.app_defaults_initialized? 161 gem_directories + module_directories(env) + $LOAD_PATH 162 else 163 gem_directories + $LOAD_PATH 164 end 165 end
Public Instance Methods
@api private
# File lib/puppet/util/autoload.rb 205 def changed?(name, env) 206 self.class.changed?(expand(name), env) 207 end
# File lib/puppet/util/autoload.rb 213 def expand(name) 214 ::File.join(@path, name.to_s) 215 end
# File lib/puppet/util/autoload.rb 209 def files_to_load(env) 210 self.class.files_to_load(@path, env) 211 end
# File lib/puppet/util/autoload.rb 182 def load(name, env) 183 self.class.load_file(expand(name), env) 184 end
Load all instances from a path of Autoload.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 196 def loadall(env) 197 self.class.loadall(@path, env) 198 end
# File lib/puppet/util/autoload.rb 200 def loaded?(name) 201 self.class.loaded?(expand(name)) 202 end