lib/bundler/installer.rb



require 'rubygems/dependency_installer'

module Bundler
  class Installer < Environment
    def self.install(root, definition, options)
      new(root, definition).run(options)
    end

    def run(options)
      if dependencies.empty?
        Bundler.ui.warn "The Gemfile specifies no dependencies"
        return
      end

      # Ensure that BUNDLE_PATH exists
      FileUtils.mkdir_p(Bundler.bundle_path)

      specs.sort_by { |s| s.name }.each do |spec|
        # unless spec.source.is_a?(Source::SystemGems)
          Bundler.ui.info "Installing #{spec.name} (#{spec.version}) from #{spec.source} "
        # end

        if (spec.groups & options[:without]).any?
          Bundler.ui.debug "  * Not in requested group; skipping."
          next
        end

        spec.source.install(spec)

        Bundler.ui.info ""
      end

      Bundler.ui.confirm "Your bundle is complete!"
    end

    def dependencies
      @definition.actual_dependencies
    end

    def specs
      @specs ||= group_specs(resolve_locally || resolve_remotely)
    end

  private

    def sources
      @definition.sources
    end

    def resolve_locally
      # Return unless all the dependencies have = version requirements
      return if dependencies.any? { |d| ambiguous?(d) }

      source_requirements = {}
      dependencies.each do |dep|
        next unless dep.source && dep.source.respond_to?(:local_specs)
        source_requirements[dep.name] = dep.source.local_specs
      end

      # Run a resolve against the locally available gems
      specs = Resolver.resolve(dependencies, local_index, source_requirements)

      # Simple logic for now. Can improve later.
      specs.length == dependencies.length && specs
    rescue Bundler::GemNotFound
      nil
      raise if ENV["OMG"]
    end

    def resolve_remotely
      index # trigger building the index
      Bundler.ui.info "Resolving dependencies"
      source_requirements = {}
      dependencies.each do |dep|
        next unless dep.source
        source_requirements[dep.name] = dep.source.specs
      end

      specs = Resolver.resolve(dependencies, index, source_requirements)
      specs
    end

    def ambiguous?(dep)
      dep.version_requirements.requirements.any? { |op,_| op != '=' }
    end

    def index
      @index ||= begin
        index = Index.new

        if File.directory?("#{root}/vendor/cache")
          index = cache_source.specs.merge(index).freeze
        end

        rg_sources = sources.select { |s| s.is_a?(Source::Rubygems) }
        other_sources = sources.select { |s| !s.is_a?(Source::Rubygems)   }

        other_sources.each do |source|
          i = source.specs
          Bundler.ui.debug "Source: Processing index"
          index = i.merge(index).freeze
        end

        index = Index.from_installed_gems.merge(index)

        rg_sources.each do |source|
          i = source.specs
          Bundler.ui.debug "Source: Processing index"
          index = i.merge(index).freeze
        end

        index
      end
    end

    def local_index
      @local_index ||= begin
        index = Index.new

        sources.each do |source|
          next unless source.respond_to?(:local_specs)
          index = source.local_specs.merge(index)
        end

        if File.directory?("#{root}/vendor/cache")
          index = cache_source.specs.merge(index).freeze
        end

        Index.from_installed_gems.merge(index)
      end
    end

    def cache_source
      Source::GemCache.new("path" => "#{root}/vendor/cache")
    end

  end
end