# class Puppet::Util::Autoload

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

### Attributes

autoloaders[R]
loaded[RW]
object[RW]
objwarn[RW]
path[RW]
wrap[RW]

### Public Class Methods

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

### Public Instance 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

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_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(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

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

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