class Bundler::SpecSet

Attributes

incomplete_specs[R]

Public Class Methods

new(specs, incomplete_specs = []) click to toggle source
# File bundler/spec_set.rb, line 12
def initialize(specs, incomplete_specs = [])
  @specs = specs
  @incomplete_specs = incomplete_specs
end

Public Instance Methods

-(other) click to toggle source
# File bundler/spec_set.rb, line 147
def -(other)
  SpecSet.new(to_a - other.to_a)
end
<<(spec) click to toggle source
# File bundler/spec_set.rb, line 174
def <<(spec)
  @specs << spec
end
[](key) click to toggle source
# File bundler/spec_set.rb, line 85
def [](key)
  key = key.name if key.respond_to?(:name)
  lookup[key]&.reverse || []
end
[]=(key, value) click to toggle source
# File bundler/spec_set.rb, line 90
def []=(key, value)
  @specs << value

  reset!
end
add_extra_platforms!(platforms) click to toggle source
# File bundler/spec_set.rb, line 55
def add_extra_platforms!(platforms)
  return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty?

  new_platforms = all_platforms.select do |platform|
    next if platforms.include?(platform)
    next unless GemHelpers.generic(platform) == Gem::Platform::RUBY

    complete_platform(platform)
  end
  return platforms if new_platforms.empty?

  platforms.concat(new_platforms)

  less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform && platform === Bundler.local_platform }
  platforms.delete(Bundler.local_platform) if less_specific_platform

  platforms
end
delete(specs) click to toggle source
# File bundler/spec_set.rb, line 96
def delete(specs)
  specs.each {|spec| @specs.delete(spec) }

  reset!
end
delete_by_name(name) click to toggle source
# File bundler/spec_set.rb, line 161
def delete_by_name(name)
  @specs.reject! {|spec| spec.name == name }

  reset!
end
each(&b) click to toggle source
# File bundler/spec_set.rb, line 190
def each(&b)
  sorted.each(&b)
end
empty?() click to toggle source
# File bundler/spec_set.rb, line 186
def empty?
  @specs.empty?
end
find_by_name_and_platform(name, platform) click to toggle source
# File bundler/spec_set.rb, line 151
def find_by_name_and_platform(name, platform)
  @specs.detect {|spec| spec.name == name && spec.match_platform(platform) }
end
for(dependencies, check = false, platforms = [nil]) click to toggle source
# File bundler/spec_set.rb, line 17
def for(dependencies, check = false, platforms = [nil])
  handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h
  deps = dependencies.product(platforms)
  specs = []

  loop do
    break unless dep = deps.shift

    name = dep[0].name
    platform = dep[1]
    incomplete = false

    key = [name, platform]
    next if handled.key?(key)

    handled[key] = true

    specs_for_dep = specs_for_dependency(*dep)
    if specs_for_dep.any?
      specs.concat(specs_for_dep)

      specs_for_dep.first.dependencies.each do |d|
        next if d.type == :development
        incomplete = true if d.name != "bundler" && lookup[d.name].nil?
        deps << [d, dep[1]]
      end
    else
      incomplete = true
    end

    if incomplete && check
      @incomplete_specs += lookup[name] || [LazySpecification.new(name, nil, nil)]
    end
  end

  specs.uniq
end
incomplete_for_platform?(deps, platform) click to toggle source
# File bundler/spec_set.rb, line 133
def incomplete_for_platform?(deps, platform)
  return false if @specs.empty?

  @incomplete_specs = []

  self.for(deps, true, [platform])

  @incomplete_specs.any?
end
length() click to toggle source
# File bundler/spec_set.rb, line 178
def length
  @specs.length
end
materialize(deps) click to toggle source
# File bundler/spec_set.rb, line 114
def materialize(deps)
  materialized = self.for(deps, true)

  SpecSet.new(materialized, incomplete_specs)
end
materialized_for_all_platforms() click to toggle source

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<Gem::Specification>]

# File bundler/spec_set.rb, line 123
def materialized_for_all_platforms
  @specs.map do |s|
    next s unless s.is_a?(LazySpecification)
    s.source.remote!
    spec = s.materialize_for_installation
    raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec
    spec
  end
end
missing_specs() click to toggle source
# File bundler/spec_set.rb, line 143
def missing_specs
  @specs.select {|s| s.is_a?(LazySpecification) }
end
names() click to toggle source
# File bundler/spec_set.rb, line 194
def names
  lookup.keys
end
size() click to toggle source
# File bundler/spec_set.rb, line 182
def size
  @specs.size
end
sort!() click to toggle source
# File bundler/spec_set.rb, line 102
def sort!
  self
end
specs_compatible_with(other) click to toggle source
# File bundler/spec_set.rb, line 155
def specs_compatible_with(other)
  select do |spec|
    other.valid?(spec)
  end
end
to_a() click to toggle source
# File bundler/spec_set.rb, line 106
def to_a
  sorted.dup
end
to_hash() click to toggle source
# File bundler/spec_set.rb, line 110
def to_hash
  lookup.dup
end
valid?(s) click to toggle source
# File bundler/spec_set.rb, line 198
def valid?(s)
  s.matches_current_metadata? && valid_dependencies?(s)
end
validate_deps(s) click to toggle source
# File bundler/spec_set.rb, line 74
def validate_deps(s)
  s.runtime_dependencies.each do |dep|
    next if dep.name == "bundler"

    return :missing unless names.include?(dep.name)
    return :invalid if none? {|spec| dep.matches_spec?(spec) }
  end

  :valid
end
what_required(spec) click to toggle source
# File bundler/spec_set.rb, line 167
def what_required(spec)
  unless req = find {|s| s.runtime_dependencies.any? {|d| d.name == spec.name } }
    return [spec]
  end
  what_required(req) << spec
end

Private Instance Methods

all_platforms() click to toggle source
# File bundler/spec_set.rb, line 236
def all_platforms
  @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq
end
complete_platform(platform) click to toggle source
# File bundler/spec_set.rb, line 209
def complete_platform(platform)
  new_specs = []

  valid_platform = lookup.all? do |_, specs|
    spec = specs.first
    matching_specs = spec.source.specs.search([spec.name, spec.version])
    platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).find do |s|
      valid?(s)
    end

    if platform_spec
      new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec)
      true
    else
      false
    end
  end

  if valid_platform && new_specs.any?
    @specs.concat(new_specs)

    reset!
  end

  valid_platform
end
extract_circular_gems(error) click to toggle source
# File bundler/spec_set.rb, line 256
def extract_circular_gems(error)
  error.message.scan(/@name="(.*?)"/).flatten
end
lookup() click to toggle source
# File bundler/spec_set.rb, line 260
def lookup
  @lookup ||= begin
    lookup = {}
    @specs.each do |s|
      lookup[s.name] ||= []
      lookup[s.name] << s
    end
    lookup
  end
end
reset!() click to toggle source
# File bundler/spec_set.rb, line 204
def reset!
  @sorted = nil
  @lookup = nil
end
sorted() click to toggle source
# File bundler/spec_set.rb, line 244
def sorted
  rake = @specs.find {|s| s.name == "rake" }
  begin
    @sorted ||= ([rake] + tsort).compact.uniq
  rescue TSort::Cyclic => error
    cgems = extract_circular_gems(error)
    raise CyclicDependencyError, "Your bundle requires gems that depend" \
      " on each other, creating an infinite loop. Please remove either" \
      " gem '#{cgems[0]}' or gem '#{cgems[1]}' and try again."
  end
end
specs_for_dependency(dep, platform) click to toggle source
# File bundler/spec_set.rb, line 276
def specs_for_dependency(dep, platform)
  specs_for_name = lookup[dep.name]
  return [] unless specs_for_name

  if platform
    GemHelpers.select_best_platform_match(specs_for_name, platform, force_ruby: dep.force_ruby_platform)
  else
    GemHelpers.select_best_local_platform_match(specs_for_name, force_ruby: dep.force_ruby_platform)
  end
end
tsort_each_child(s) { |s2| ... } click to toggle source
# File bundler/spec_set.rb, line 287
def tsort_each_child(s)
  s.dependencies.sort_by(&:name).each do |d|
    next if d.type == :development

    specs_for_name = lookup[d.name]
    next unless specs_for_name

    specs_for_name.each {|s2| yield s2 }
  end
end
tsort_each_node() { |s| ... } click to toggle source
# File bundler/spec_set.rb, line 271
def tsort_each_node
  # MUST sort by name for backwards compatibility
  @specs.sort_by(&:name).each {|s| yield s }
end
valid_dependencies?(s) click to toggle source
# File bundler/spec_set.rb, line 240
def valid_dependencies?(s)
  validate_deps(s) == :valid
end