class Gem::RequestSet::Lockfile

def self.build request_set, gem_deps_file, dependencies = nil

def self.build request_set, gem_deps_file, dependencies = nil
  request_set.resolve
  dependencies ||= requests_to_deps request_set.sorted_requests
  new request_set, gem_deps_file, dependencies
end

def self.requests_to_deps requests # :nodoc:

:nodoc:
def self.requests_to_deps requests # :nodoc:
  deps = {}
  requests.each do |request|
    spec        = request.spec
    name        = request.name
    requirement = request.request.dependency.requirement
    deps[name] = if [Gem::Resolver::VendorSpecification,
                     Gem::Resolver::GitSpecification].include? spec.class then
                   Gem::Requirement.source_set
                 else
                   requirement
                 end
  end
  deps
end

def add_DEPENDENCIES out # :nodoc:

:nodoc:
def add_DEPENDENCIES out # :nodoc:
  out << "DEPENDENCIES"
  out.concat @dependencies.sort_by { |name,| name }.map { |name, requirement|
    "  #{name}#{requirement.for_lockfile}"
  }
  out << nil
end

def add_GEM out, spec_groups # :nodoc:

:nodoc:
def add_GEM out, spec_groups # :nodoc:
  return if spec_groups.empty?
  source_groups = spec_groups.values.flatten.group_by do |request|
    request.spec.source.uri
  end
  source_groups.sort_by { |group,| group.to_s }.map do |group, requests|
    out << "GEM"
    out << "  remote: #{group}"
    out << "  specs:"
    requests.sort_by { |request| request.name }.each do |request|
      next if request.spec.name == 'bundler'
      platform = "-#{request.spec.platform}" unless
        Gem::Platform::RUBY == request.spec.platform
      out << "    #{request.name} (#{request.version}#{platform})"
      request.full_spec.dependencies.sort.each do |dependency|
        next if dependency.type == :development
        requirement = dependency.requirement
        out << "      #{dependency.name}#{requirement.for_lockfile}"
      end
    end
    out << nil
  end
end

def add_GIT out, git_requests

def add_GIT out, git_requests
  return if git_requests.empty?
  by_repository_revision = git_requests.group_by do |request|
    source = request.spec.source
    [source.repository, source.rev_parse]
  end
  by_repository_revision.each do |(repository, revision), requests|
    out << "GIT"
    out << "  remote: #{repository}"
    out << "  revision: #{revision}"
    out << "  specs:"
    requests.sort_by { |request| request.name }.each do |request|
      out << "    #{request.name} (#{request.version})"
      dependencies = request.spec.dependencies.sort_by { |dep| dep.name }
      dependencies.each do |dep|
        out << "      #{dep.name}#{dep.requirement.for_lockfile}"
      end
    end
    out << nil
  end
end

def add_PATH out, path_requests # :nodoc:

:nodoc:
def add_PATH out, path_requests # :nodoc:
  return if path_requests.empty?
  out << "PATH"
  path_requests.each do |request|
    directory = File.expand_path(request.spec.source.uri)
    out << "  remote: #{relative_path_from directory, @gem_deps_dir}"
    out << "  specs:"
    out << "    #{request.name} (#{request.version})"
  end
  out << nil
end

def add_PLATFORMS out # :nodoc:

:nodoc:
def add_PLATFORMS out # :nodoc:
  out << "PLATFORMS"
  platforms = requests.map { |request| request.spec.platform }.uniq
  platforms = platforms.sort_by { |platform| platform.to_s }
  platforms.each do |platform|
    out << "  #{platform}"
  end
  out << nil
end

def initialize request_set, gem_deps_file, dependencies

def initialize request_set, gem_deps_file, dependencies
  @set           = request_set
  @dependencies  = dependencies
  @gem_deps_file = File.expand_path(gem_deps_file)
  @gem_deps_dir  = File.dirname(@gem_deps_file)
  @gem_deps_file.untaint unless gem_deps_file.tainted?
  @platforms      = []
end

def relative_path_from dest, base # :nodoc:

:nodoc:
def relative_path_from dest, base # :nodoc:
  dest = File.expand_path(dest)
  base = File.expand_path(base)
  if dest.index(base) == 0 then
    offset = dest[base.size+1..-1]
    return '.' unless offset
    offset
  else
    dest
  end
end

def requests

def requests
  @set.sorted_requests
end

def spec_groups

def spec_groups
  requests.group_by { |request| request.spec.class }
end

def to_s

def to_s
  out = []
  groups = spec_groups
  add_PATH out, groups.delete(Gem::Resolver::VendorSpecification) { [] }
  add_GIT out, groups.delete(Gem::Resolver::GitSpecification) { [] }
  add_GEM out, groups
  add_PLATFORMS out
  add_DEPENDENCIES out
  out.join "\n"
end

def write

def write
  content = to_s
  open "#{@gem_deps_file}.lock", 'w' do |io|
    io.write content
  end
end