class Bundler::Definition

def self.build(gemfile, lockfile, unlock)

def self.build(gemfile, lockfile, unlock)
  unlock ||= {}
  gemfile = Pathname.new(gemfile).expand_path
  unless gemfile.file?
    raise GemfileNotFound, "#{gemfile} not found"
  end
  # TODO: move this back into DSL
  builder = Dsl.new
  builder.instance_eval(File.read(gemfile.to_s), gemfile.to_s, 1)
  builder.to_definition(lockfile, unlock)
end

def converge

def converge
  converge_sources
  converge_dependencies
  converge_locked_specs
end

def converge_dependencies

def converge_dependencies
  (@dependencies + @locked_deps).each do |dep|
    if dep.source
      source = @sources.find { |s| dep.source == s }
      raise "Something went wrong, there is no matching source" unless source
      dep.source = source
    end
  end
end

def converge_locked_specs

def converge_locked_specs
  deps = []
  @dependencies.each do |dep|
    if in_locked_deps?(dep) || satisfies_locked_spec?(dep)
      deps << dep
    end
  end
  converged = []
  @last_resolve.each do |s|
    s.source = @sources.find { |src| s.source == src }
    next if s.source.nil? || @unlock[:sources].include?(s.name)
    # If the spec is from a path source and it doesn't exist anymore
    # then we just unlock it.
    next if s.source.instance_of?(Source::Path) && s.source.specs[s].empty?
    converged << s
  end
  resolve = SpecSet.new(converged)
  resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems])
  @last_resolve = resolve
end

def converge_sources

def converge_sources
  @sources = (@locked_sources & @sources) | @sources
  @sources.each do |source|
    source.unlock! if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
  end
end

def current_dependencies

def current_dependencies
  dependencies.reject { |d| !d.should_include? }
end

def expand_dependencies(dependencies, remote = false)

def expand_dependencies(dependencies, remote = false)
  deps = []
  dependencies.each do |dep|
    dep.gem_platforms(@platforms).each do |p|
      deps << DepProxy.new(dep, p) if remote || p == Gem::Platform.local.to_generic
    end
  end
  deps
end

def expanded_dependencies

def expanded_dependencies
  @expanded_dependencies ||= expand_dependencies(dependencies, @remote)
end

def groups

def groups
  dependencies.map { |d| d.groups }.flatten.uniq
end

def in_locked_deps?(dep)

def in_locked_deps?(dep)
  @locked_deps.any? do |d|
    dep == d && dep.source == d.source
  end
end

def index

def index
  @index ||= Index.build do |idx|
    @sources.each do |s|
      idx.use s.specs
    end
  end
end

def initialize(lockfile, dependencies, sources, unlock)

def initialize(lockfile, dependencies, sources, unlock)
  @dependencies, @sources, @unlock = dependencies, sources, unlock
  @remote = false
  @specs = nil
  @unlock[:gems] ||= []
  @unlock[:sources] ||= []
  if lockfile && File.exists?(lockfile)
    locked = LockfileParser.new(File.read(lockfile))
    @platforms      = locked.platforms
    @locked_deps    = locked.dependencies
    @last_resolve   = SpecSet.new(locked.specs)
    @locked_sources = locked.sources
  else
    @platforms      = []
    @locked_deps    = []
    @last_resolve   = SpecSet.new([])
    @locked_sources = []
  end
  current_platform = Gem.platforms.map { |p| p.to_generic }.compact.last
  @platforms |= [current_platform]
  converge
end

def missing_specs

def missing_specs
  missing = []
  resolve.materialize(requested_dependencies, missing)
  missing
end

def no_sources?

def no_sources?
  @sources.length == 1 && @sources.first.remotes.empty?
end

def requested_dependencies

def requested_dependencies
  groups = self.groups - Bundler.settings.without
  groups.map! { |g| g.to_sym }
  dependencies.reject { |d| !d.should_include? || (d.groups & groups).empty? }
end

def requested_specs

def requested_specs
  @requested_specs ||= begin
    groups = self.groups - Bundler.settings.without
    groups.map! { |g| g.to_sym }
    specs_for(groups)
  end
end

def resolve

def resolve
  @resolve ||= begin
    if @last_resolve.valid_for?(expanded_dependencies)
      @last_resolve
    else
      source_requirements = {}
      dependencies.each do |dep|
        next unless dep.source
        source_requirements[dep.name] = dep.source.specs
      end
      # Run a resolve against the locally available gems
      @last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, @last_resolve)
    end
  end
end

def resolve_remotely!

def resolve_remotely!
  raise "Specs already loaded" if @specs
  @remote = true
  @sources.each { |s| s.remote! }
  specs
end

def resolve_with_cache!

def resolve_with_cache!
  raise "Specs already loaded" if @specs
  @sources.each { |s| s.cached! }
  specs
end

def satisfies_locked_spec?(dep)

def satisfies_locked_spec?(dep)
  @last_resolve.any? { |s| s.satisfies?(dep) }
end

def sorted_sources

def sorted_sources
  @sources.sort_by do |s|
    # Place GEM at the top
    [ s.is_a?(Source::Rubygems) ? 1 : 0, s.to_s ]
  end
end

def specs

def specs
  @specs ||= begin
    specs = resolve.materialize(requested_dependencies)
    unless specs["bundler"].any?
      bundler = index.search(Gem::Dependency.new('bundler', VERSION)).last
      specs["bundler"] = bundler if bundler
    end
    specs
  end
end

def specs_for(groups)

def specs_for(groups)
  deps = dependencies.select { |d| (d.groups & groups).any? }
  deps.delete_if { |d| !d.should_include? }
  specs.for(expand_dependencies(deps))
end

def to_lock

def to_lock
  out = ""
  sorted_sources.each do |source|
    # Add the source header
    out << source.to_lock
    # Find all specs for this source
    resolve.
      select  { |s| s.source == source }.
      sort_by { |s| s.name }.
      each do |spec|
        next if spec.name == 'bundler'
        out << spec.to_lock
    end
    out << "\n"
  end
  out << "PLATFORMS\n"
  platforms.map { |p| p.to_s }.sort.each do |p|
    out << "  #{p}\n"
  end
  out << "\n"
  out << "DEPENDENCIES\n"
  dependencies.
    sort_by { |d| d.name }.
    each do |dep|
      out << dep.to_lock
  end
  out
end