class Puppet::Util::Autoload

Autoload paths, either based on names or all at once.

Attributes

object[RW]
objwarn[RW]
path[RW]
wrap[RW]

Public Class Methods

changed?(name) click to toggle source
# 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]
  return true unless file == get_file(name)
  begin
    old_mtime != File.mtime(file)
  rescue Errno::ENOENT
    true
  end
end
cleanpath(path) click to toggle source

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 171
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
files_in_dir(dir, path) click to toggle source
# 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
files_to_load(path) click to toggle source
# File lib/puppet/util/autoload.rb, line 93
def files_to_load(path)
  search_directories.map {|dir| files_in_dir(dir, path) }.flatten.uniq
end
gem_directories() click to toggle source
# File lib/puppet/util/autoload.rb, line 161
def gem_directories
  gem_source.directories
end
gem_source() click to toggle source
# File lib/puppet/util/autoload.rb, line 18
def gem_source
  @gem_source ||= Puppet::Util::RubyGems::Source.new
end
get_file(name, env=nil) click to toggle source

Get the correct file to load for a given path returns nil if no file is found

# File lib/puppet/util/autoload.rb, line 86
def get_file(name, env=nil)
  name = name + '.rb' unless name =~ /\.rb$/
  dirname, base = File.split(name)
  path = search_directories(env).find { |dir| File.exist?(File.join(dir, name)) }
  path and File.join(path, name)
end
libdirs() click to toggle source
# File lib/puppet/util/autoload.rb, line 151
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_file(name, env=nil) click to toggle source

Load a single plugin by name. We use ‘load’ here so we can reload a given plugin.

# File lib/puppet/util/autoload.rb, line 56
def load_file(name, env=nil)
  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
  end
end
loadall(path) click to toggle source
# File lib/puppet/util/autoload.rb, line 72
def loadall(path)
  # Load every instance of everything we can find.
  files_to_load(path).each do |file|
    name = file.chomp(".rb")
    load_file(name) unless loaded?(name)
  end
end
loaded?(path) click to toggle source

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
mark_loaded(name, file) click to toggle source

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
module_directories(env=nil) click to toggle source
# File lib/puppet/util/autoload.rb, line 104
def module_directories(env=nil)
  # We have to require this late in the process because otherwise we might
  # have load order issues. Since require is much slower than defined?, we
  # can skip that - and save some 2,155 invocations of require in my real
  # world testing. --daniel 2012-07-10
  require 'puppet/node/environment' unless defined?(Puppet::Node::Environment)

  real_env = Puppet::Node::Environment.new(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.
  Thread.current[: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?
    # if the app defaults have been initialized then it should be safe to access the module path setting.
    Thread.current[:env_module_directories][real_env] ||= real_env.modulepath.collect do |dir|
      Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f) }
    end.flatten.collect { |d| File.join(d, "lib") }.find_all do |d|
      FileTest.directory?(d)
    end
  else
    # if we get here, the app defaults have not been initialized, so we basically use an empty module path.
    []
  end
end
new(obj, path, options = {}) click to toggle source
# File lib/puppet/util/autoload.rb, line 188
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
reload_changed() click to toggle source
# File lib/puppet/util/autoload.rb, line 80
def reload_changed
  loaded.keys.each { |file| load_file(file) if changed?(file) }
end
search_directories(env=nil) click to toggle source
# File lib/puppet/util/autoload.rb, line 165
def search_directories(env=nil)
  [gem_directories, module_directories(env), libdirs(), $LOAD_PATH].flatten
end

Public Instance Methods

changed?(name) click to toggle source
# File lib/puppet/util/autoload.rb, line 214
def changed?(name)
  self.class.changed?(expand(name))
end
expand(name) click to toggle source
# File lib/puppet/util/autoload.rb, line 222
def expand(name)
  ::File.join(@path, name.to_s)
end
files_to_load() click to toggle source
# File lib/puppet/util/autoload.rb, line 218
def files_to_load
  self.class.files_to_load(@path)
end
load(name, env=nil) click to toggle source
# File lib/puppet/util/autoload.rb, line 200
def load(name, env=nil)
  self.class.load_file(expand(name), env)
end
loadall() click to toggle source

Load all instances that we can. This uses require, rather than load, so that already-loaded files don’t get reloaded unnecessarily.

# File lib/puppet/util/autoload.rb, line 206
def loadall
  self.class.loadall(@path)
end
loaded?(name) click to toggle source
# File lib/puppet/util/autoload.rb, line 210
def loaded?(name)
  self.class.loaded?(expand(name))
end