class Puppet::ModuleTool::Applications::Installer

Public Instance Methods

run() click to toggle source
# File lib/puppet/module_tool/applications/installer.rb, line 53
def run
  name = @name.tr('/', '-')
  version = options[:version] || '>= 0.0.0'

  results = { :action => :install, :module_name => name, :module_version => version }

  begin
    if mod = installed_modules[name]
      unless forced?
        if Semantic::VersionRange.parse(version).include? mod.version
          results[:result] = :noop
          results[:version] = mod.version
          return results
        else
          changes = Checksummer.run(installed_modules[name].mod.path) rescue []
          raise AlreadyInstalledError,
            :module_name       => name,
            :installed_version => installed_modules[name].version,
            :requested_version => options[:version] || :latest,
            :local_changes     => changes
        end
      end
    end

    @install_dir.prepare(name, options[:version] || 'latest')
    results[:install_dir] = @install_dir.target

    unless @local_tarball && @ignore_dependencies
      Puppet.notice "Downloading from #{module_repository.host} ..."
    end

    if @ignore_dependencies
      graph = build_single_module_graph(name, version)
    else
      graph = build_dependency_graph(name, version)
    end

    unless forced?
      add_module_name_constraints_to_graph(graph)
    end

    installed_modules.each do |mod, release|
      mod = mod.tr('/', '-')
      next if mod == name

      version = release.version

      unless forced?
        # Since upgrading already installed modules can be troublesome,
        # we'll place constraints on the graph for each installed module,
        # locking it to upgrades within the same major version.
        ">=#{version} #{version.major}.x".tap do |range|
          graph.add_constraint('installed', mod, range) do |node|
            Semantic::VersionRange.parse(range).include? node.version
          end
        end

        release.mod.dependencies.each do |dep|
          dep_name = dep['name'].tr('/', '-')

          dep['version_requirement'].tap do |range|
            graph.add_constraint("#{mod} constraint", dep_name, range) do |node|
              Semantic::VersionRange.parse(range).include? node.version
            end
          end
        end
      end
    end

    # Ensure that there is at least one candidate release available
    # for the target package.
    if graph.dependencies[name].empty?
      raise NoCandidateReleasesError, results.merge(:module_name => name, :source => module_repository.host, :requested_version => options[:version] || :latest)
    end

    begin
      Puppet.info "Resolving dependencies ..."
      releases = Semantic::Dependency.resolve(graph)
    rescue Semantic::Dependency::UnsatisfiableGraph
      raise NoVersionsSatisfyError, results.merge(:requested_name => name)
    end

    unless forced?
      # Check for module name conflicts.
      releases.each do |rel|
        if mod = installed_modules_source.by_name[rel.name.split('-').last]
          next if mod.has_metadata? && mod.forge_name.tr('/', '-') == rel.name

          if rel.name != name
            dependency = {
              :name => rel.name,
              :version => rel.version
            }
          end

          raise InstallConflictError,
            :requested_module  => name,
            :requested_version => options[:version] || 'latest',
            :dependency        => dependency,
            :directory         => mod.path,
            :metadata          => mod.metadata
        end
      end
    end

    Puppet.info "Preparing to install ..."
    releases.each { |release| release.prepare }

    Puppet.notice 'Installing -- do not interrupt ...'
    releases.each do |release|
      installed = installed_modules[release.name]
      if forced? || installed.nil?
        release.install(Pathname.new(results[:install_dir]))
      else
        release.install(Pathname.new(installed.mod.modulepath))
      end
    end

    results[:result] = :success
    results[:installed_modules] = releases
    results[:graph] = [ build_install_graph(releases.first, releases) ]

  rescue ModuleToolError, ForgeError => err
    results[:error] = {
      :oneline   => err.message,
      :multiline => err.multiline,
    }
  ensure
    results[:result] ||= :failure
  end

  results
end

Public Class Methods

new(name, install_dir, options = {}) click to toggle source
# File lib/puppet/module_tool/applications/installer.rb, line 20
def initialize(name, install_dir, options = {})
  super(options)

  @action              = :install
  @environment         = options[:environment_instance]
  @ignore_dependencies = forced? || options[:ignore_dependencies]
  @name                = name
  @install_dir         = install_dir

  Puppet::Forge::Cache.clean

  @local_tarball = Puppet::FileSystem.exist?(name)

  if @local_tarball
    release = local_tarball_source.release
    @name = release.name
    options[:version] = release.version.to_s
    Semantic::Dependency.add_source(local_tarball_source)

    # If we're operating on a local tarball and ignoring dependencies, we
    # don't need to search any additional sources.  This will cut down on
    # unnecessary network traffic.
    unless @ignore_dependencies
      Semantic::Dependency.add_source(installed_modules_source)
      Semantic::Dependency.add_source(module_repository)
    end

  else
    Semantic::Dependency.add_source(installed_modules_source) unless forced?
    Semantic::Dependency.add_source(module_repository)
  end
end