[rubygems/rubygems] Keep track of materializations in the original resolve
This gives more flexibility to allow further improvements. https://github.com/rubygems/rubygems/commit/f11a890f5e
This commit is contained in:
parent
e15921c694
commit
c76b1ea2a6
@ -62,6 +62,7 @@ module Bundler
|
||||
autoload :LazySpecification, File.expand_path("bundler/lazy_specification", __dir__)
|
||||
autoload :LockfileParser, File.expand_path("bundler/lockfile_parser", __dir__)
|
||||
autoload :MatchRemoteMetadata, File.expand_path("bundler/match_remote_metadata", __dir__)
|
||||
autoload :Materialization, File.expand_path("bundler/materialization", __dir__)
|
||||
autoload :NULL, File.expand_path("bundler/constants", __dir__)
|
||||
autoload :ProcessLock, File.expand_path("bundler/process_lock", __dir__)
|
||||
autoload :RemoteSpecification, File.expand_path("bundler/remote_specification", __dir__)
|
||||
|
@ -241,7 +241,7 @@ module Bundler
|
||||
end
|
||||
|
||||
def missing_specs
|
||||
resolve.materialize(requested_dependencies).missing_specs
|
||||
resolve.missing_specs_for(requested_dependencies)
|
||||
end
|
||||
|
||||
def missing_specs?
|
||||
@ -639,7 +639,7 @@ module Bundler
|
||||
retry
|
||||
end
|
||||
|
||||
missing_specs = specs.missing_specs
|
||||
missing_specs = resolve.missing_specs
|
||||
|
||||
if missing_specs.any?
|
||||
missing_specs.each do |s|
|
||||
@ -668,7 +668,7 @@ module Bundler
|
||||
raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}"
|
||||
end
|
||||
|
||||
incomplete_specs = specs.incomplete_specs
|
||||
incomplete_specs = resolve.incomplete_specs
|
||||
loop do
|
||||
break if incomplete_specs.empty?
|
||||
|
||||
@ -677,7 +677,7 @@ module Bundler
|
||||
reresolve_without(incomplete_specs)
|
||||
specs = resolve.materialize(dependencies)
|
||||
|
||||
still_incomplete_specs = specs.incomplete_specs
|
||||
still_incomplete_specs = resolve.incomplete_specs
|
||||
|
||||
if still_incomplete_specs == incomplete_specs
|
||||
package = resolution_packages.get_package(incomplete_specs.first.name)
|
||||
@ -687,7 +687,7 @@ module Bundler
|
||||
incomplete_specs = still_incomplete_specs
|
||||
end
|
||||
|
||||
insecurely_materialized_specs = specs.insecurely_materialized_specs
|
||||
insecurely_materialized_specs = resolve.insecurely_materialized_specs
|
||||
|
||||
if insecurely_materialized_specs.any?
|
||||
Bundler.ui.warn "The following platform specific gems are getting installed, yet the lockfile includes only their generic ruby version:\n" \
|
||||
|
@ -63,7 +63,7 @@ module Bundler
|
||||
module_function :select_best_platform_match
|
||||
|
||||
def select_best_local_platform_match(specs, force_ruby: false)
|
||||
select_best_platform_match(specs, local_platform, force_ruby: force_ruby).filter_map(&:materialize_for_installation)
|
||||
select_best_platform_match(specs, local_platform, force_ruby: force_ruby).filter_map(&:materialized_for_installation)
|
||||
end
|
||||
module_function :select_best_local_platform_match
|
||||
|
||||
|
@ -8,7 +8,7 @@ module Bundler
|
||||
include MatchPlatform
|
||||
include ForcePlatform
|
||||
|
||||
attr_reader :name, :version, :platform
|
||||
attr_reader :name, :version, :platform, :materialization
|
||||
attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version
|
||||
|
||||
#
|
||||
@ -46,6 +46,15 @@ module Bundler
|
||||
|
||||
@force_ruby_platform = default_force_ruby_platform
|
||||
@most_specific_locked_platform = nil
|
||||
@materialization = nil
|
||||
end
|
||||
|
||||
def missing?
|
||||
@materialization == self
|
||||
end
|
||||
|
||||
def incomplete?
|
||||
@materialization.nil?
|
||||
end
|
||||
|
||||
def source_changed?
|
||||
@ -121,6 +130,12 @@ module Bundler
|
||||
__materialize__(matching_specs)
|
||||
end
|
||||
|
||||
def materialized_for_installation
|
||||
@materialization = materialize_for_installation
|
||||
|
||||
self unless incomplete?
|
||||
end
|
||||
|
||||
def materialize_for_installation
|
||||
source.local!
|
||||
|
||||
|
53
lib/bundler/materialization.rb
Normal file
53
lib/bundler/materialization.rb
Normal file
@ -0,0 +1,53 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Bundler
|
||||
#
|
||||
# This class materializes a set of resolved specifications (`LazySpecification`)
|
||||
# for a given gem into the most appropriate real specifications
|
||||
# (`StubSepecification`, `EndpointSpecification`, etc), given a dependency and a
|
||||
# target platform.
|
||||
#
|
||||
class Materialization
|
||||
def initialize(dep, platform, candidates:)
|
||||
@dep = dep
|
||||
@platform = platform
|
||||
@candidates = candidates
|
||||
end
|
||||
|
||||
def complete?
|
||||
specs.any?
|
||||
end
|
||||
|
||||
def specs
|
||||
@specs ||= if @candidates.nil?
|
||||
[]
|
||||
elsif platform
|
||||
GemHelpers.select_best_platform_match(@candidates, platform, force_ruby: dep.force_ruby_platform)
|
||||
else
|
||||
GemHelpers.select_best_local_platform_match(@candidates, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform)
|
||||
end
|
||||
end
|
||||
|
||||
def dependencies
|
||||
specs.first.runtime_dependencies.map {|d| [d, platform] }
|
||||
end
|
||||
|
||||
def materialized_spec
|
||||
specs.first&.materialization
|
||||
end
|
||||
|
||||
def missing_specs
|
||||
specs.select(&:missing?)
|
||||
end
|
||||
|
||||
def incomplete_specs
|
||||
return [] if complete?
|
||||
|
||||
@candidates || LazySpecification.new(dep.name, nil, nil)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :dep, :platform
|
||||
end
|
||||
end
|
@ -7,44 +7,14 @@ module Bundler
|
||||
include Enumerable
|
||||
include TSort
|
||||
|
||||
attr_reader :incomplete_specs
|
||||
|
||||
def initialize(specs, incomplete_specs = [])
|
||||
def initialize(specs)
|
||||
@specs = specs
|
||||
@incomplete_specs = incomplete_specs
|
||||
end
|
||||
|
||||
def for(dependencies, check = false, platforms = [nil])
|
||||
handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h
|
||||
deps = dependencies.product(platforms)
|
||||
specs = []
|
||||
materialize_dependencies(dependencies, platforms)
|
||||
|
||||
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)
|
||||
deps.concat(specs_for_dep.first.runtime_dependencies.map {|d| [d, platform] })
|
||||
else
|
||||
incomplete = true
|
||||
end
|
||||
|
||||
if incomplete && check
|
||||
@incomplete_specs += lookup[name] || [LazySpecification.new(name, nil, nil)]
|
||||
end
|
||||
end
|
||||
|
||||
specs.uniq
|
||||
@materializations.flat_map(&:specs).uniq
|
||||
end
|
||||
|
||||
def normalize_platforms!(deps, platforms)
|
||||
@ -126,13 +96,12 @@ module Bundler
|
||||
end
|
||||
|
||||
def materialize(deps)
|
||||
materialized = self.for(deps, true)
|
||||
materialize_dependencies(deps)
|
||||
|
||||
SpecSet.new(materialized, incomplete_specs)
|
||||
SpecSet.new(materialized_specs)
|
||||
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<Gem::Specification>]
|
||||
def materialized_for_all_platforms
|
||||
@specs.map do |s|
|
||||
@ -153,12 +122,22 @@ module Bundler
|
||||
validation_set.incomplete_specs.any?
|
||||
end
|
||||
|
||||
def missing_specs_for(dependencies)
|
||||
materialize_dependencies(dependencies)
|
||||
|
||||
missing_specs
|
||||
end
|
||||
|
||||
def missing_specs
|
||||
@specs.select {|s| s.is_a?(LazySpecification) }
|
||||
@materializations.flat_map(&:missing_specs)
|
||||
end
|
||||
|
||||
def incomplete_specs
|
||||
@materializations.flat_map(&:incomplete_specs)
|
||||
end
|
||||
|
||||
def insecurely_materialized_specs
|
||||
@specs.select(&:insecurely_materialized?)
|
||||
materialized_specs.select(&:insecurely_materialized?)
|
||||
end
|
||||
|
||||
def -(other)
|
||||
@ -218,6 +197,37 @@ module Bundler
|
||||
|
||||
private
|
||||
|
||||
def materialize_dependencies(dependencies, platforms = [nil])
|
||||
handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h
|
||||
deps = dependencies.product(platforms)
|
||||
@materializations = []
|
||||
|
||||
loop do
|
||||
break unless dep = deps.shift
|
||||
|
||||
dependency = dep[0]
|
||||
platform = dep[1]
|
||||
name = dependency.name
|
||||
|
||||
key = [name, platform]
|
||||
next if handled.key?(key)
|
||||
|
||||
handled[key] = true
|
||||
|
||||
materialization = Materialization.new(dependency, platform, candidates: lookup[name])
|
||||
|
||||
deps.concat(materialization.dependencies) if materialization.complete?
|
||||
|
||||
@materializations << materialization
|
||||
end
|
||||
|
||||
@materializations
|
||||
end
|
||||
|
||||
def materialized_specs
|
||||
@materializations.filter_map(&:materialized_spec)
|
||||
end
|
||||
|
||||
def reset!
|
||||
@sorted = nil
|
||||
@lookup = nil
|
||||
@ -290,17 +300,6 @@ module Bundler
|
||||
@specs.sort_by(&:name).each {|s| yield s }
|
||||
end
|
||||
|
||||
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 || dep.default_force_ruby_platform)
|
||||
end
|
||||
end
|
||||
|
||||
def tsort_each_child(s)
|
||||
s.dependencies.sort_by(&:name).each do |d|
|
||||
next if d.type == :development
|
||||
|
Loading…
x
Reference in New Issue
Block a user