# frozen_string_literal: true
require "tsort"
module Bundler
class SpecSet
include Enumerable
include TSort
def initialize(specs)
@specs = specs
end
def for(dependencies, check = false, match_current_platform = false, raise_on_missing = true)
handled = []
deps = dependencies.dup
specs = []
loop do
break unless dep = deps.shift
next if handled.any?{|d| d.name == dep.name && (match_current_platform || d.__platform == dep.__platform) } || dep.name == "bundler"
handled << dep
specs_for_dep = spec_for_dependency(dep, match_current_platform)
if specs_for_dep.any?
specs += specs_for_dep
specs_for_dep.first.dependencies.each do |d|
next if d.type == :development
d = DepProxy.get_proxy(d, dep.__platform) unless match_current_platform
deps << d
end
elsif check
return false
elsif raise_on_missing
others = lookup[dep.name] if match_current_platform
message = "Unable to find a spec satisfying #{dep} in the set. Perhaps the lockfile is corrupted?"
message += " Found #{others.join(", ")} that did not match the current platform." if others && !others.empty?
raise GemNotFound, message
end
end
if spec = lookup["bundler"].first
specs << spec
end
check ? true : specs
end
def [](key)
key = key.name if key.respond_to?(:name)
lookup[key].reverse
end
def []=(key, value)
@specs << value
@lookup = nil
@sorted = nil
end
def sort!
self
end
def to_a
sorted.dup
end
def to_hash
lookup.dup
end
def materialize(deps, missing_specs = nil)
materialized = self.for(deps, false, true, !missing_specs)
materialized.group_by(&:source).each do |source, specs|
next unless specs.any?{|s| s.is_a?(LazySpecification) }
source.local!
names = -> { specs.map(&:name).uniq }
source.double_check_for(names)
end
materialized.map! do |s|
next s unless s.is_a?(LazySpecification)
spec = s.__materialize__
unless spec
unless missing_specs
raise GemNotFound, "Could not find #{s.full_name} in any of the sources"
end
missing_specs << s
end
spec
end
SpecSet.new(missing_specs ? materialized.compact : materialized)
end
# Materialize for all the specs in the spec set, regardless of what platform they're for
# This is in contrast to how for does platform filtering (and specifically different from how `materialize` calls `for` only for the current platform)
# @return [Array