[rubygems/rubygems] Create LazySpecifications directly with most_specific_locked_platform

So there's no need to pass it around in so many places.

https://github.com/rubygems/rubygems/commit/784ab7481b
This commit is contained in:
David Rodríguez 2024-11-13 17:57:18 +01:00 committed by Hiroshi SHIBATA
parent 963f98a94f
commit e15921c694
8 changed files with 49 additions and 40 deletions

View File

@ -89,6 +89,7 @@ module Bundler
@lockfile_contents = Bundler.read_file(lockfile)
@locked_gems = LockfileParser.new(@lockfile_contents)
@locked_platforms = @locked_gems.platforms
@most_specific_locked_platform = @locked_gems.most_specific_locked_platform
@platforms = @locked_platforms.dup
@locked_bundler_version = @locked_gems.bundler_version
@locked_ruby_version = @locked_gems.ruby_version
@ -110,6 +111,7 @@ module Bundler
@unlock = {}
@locked_gems = nil
@locked_platforms = []
@most_specific_locked_platform = nil
@platforms = []
@locked_deps = {}
@locked_specs = SpecSet.new([])
@ -239,7 +241,7 @@ module Bundler
end
def missing_specs
resolve.materialize(requested_dependencies, most_specific_locked_platform).missing_specs
resolve.materialize(requested_dependencies).missing_specs
end
def missing_specs?
@ -510,12 +512,6 @@ module Bundler
raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
end
def most_specific_locked_platform
@locked_platforms.min_by do |bundle_platform|
platform_specificity_match(bundle_platform, local_platform)
end
end
def nothing_changed?
return false unless lockfile_exists?
@ -598,7 +594,7 @@ module Bundler
end
def resolver
@resolver ||= Resolver.new(resolution_packages, gem_version_promoter)
@resolver ||= Resolver.new(resolution_packages, gem_version_promoter, @most_specific_locked_platform)
end
def expanded_dependencies
@ -633,7 +629,7 @@ module Bundler
incorrect_spec = nil
specs = begin
resolve.materialize(dependencies, most_specific_locked_platform)
resolve.materialize(dependencies)
rescue IncorrectLockfileDependencies => e
spec = e.spec
raise "Infinite loop while fixing lockfile dependencies" if incorrect_spec == spec
@ -679,7 +675,7 @@ module Bundler
Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
sources.remote!
reresolve_without(incomplete_specs)
specs = resolve.materialize(dependencies, most_specific_locked_platform)
specs = resolve.materialize(dependencies)
still_incomplete_specs = specs.incomplete_specs
@ -756,7 +752,7 @@ module Bundler
def find_most_specific_locked_ruby_platform
return unless generic_local_platform_is_ruby? && current_platform_locked?
most_specific_locked_platform
@most_specific_locked_platform
end
def change_reason

View File

@ -62,8 +62,8 @@ module Bundler
end
module_function :select_best_platform_match
def select_best_local_platform_match(specs, force_ruby: false, most_specific_locked_platform: nil)
select_best_platform_match(specs, local_platform, force_ruby: force_ruby).filter_map {|spec| spec.materialize_for_installation(most_specific_locked_platform) }
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)
end
module_function :select_best_local_platform_match

View File

@ -11,6 +11,18 @@ module Bundler
attr_reader :name, :version, :platform
attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version
#
# For backwards compatibility with existing lockfiles, if the most specific
# locked platform is not a specific platform like x86_64-linux or
# universal-java-11, then we keep the previous behaviour of resolving the
# best platform variant at materiliazation time. For previous bundler
# versions (before 2.2.0) this was always the case (except when the lockfile
# only included non-ruby platforms), but we're also keeping this behaviour
# on newer bundlers unless users generate the lockfile from scratch or
# explicitly add a more specific platform.
#
attr_accessor :most_specific_locked_platform
alias_method :runtime_dependencies, :dependencies
def self.from_spec(s)
@ -33,6 +45,7 @@ module Bundler
@source = source
@force_ruby_platform = default_force_ruby_platform
@most_specific_locked_platform = nil
end
def source_changed?
@ -108,10 +121,10 @@ module Bundler
__materialize__(matching_specs)
end
def materialize_for_installation(most_specific_locked_platform = nil)
def materialize_for_installation
source.local!
if use_exact_resolved_specifications?(most_specific_locked_platform)
if use_exact_resolved_specifications?
materialize_strictly
else
matching_specs = source.specs.search([name, version])
@ -180,21 +193,11 @@ module Bundler
private
def use_exact_resolved_specifications?(most_specific_locked_platform)
!source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform?(most_specific_locked_platform)
def use_exact_resolved_specifications?
!source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform?
end
#
# For backwards compatibility with existing lockfiles, if the most specific
# locked platform is not a specific platform like x86_64-linux or
# universal-java-11, then we keep the previous behaviour of resolving the
# best platform variant at materiliazation time. For previous bundler
# versions (before 2.2.0) this was always the case (except when the lockfile
# only included non-ruby platforms), but we're also keeping this behaviour
# on newer bundlers unless users generate the lockfile from scratch or
# explicitly add a more specific platform.
#
def ruby_platform_materializes_to_ruby_platform?(most_specific_locked_platform)
def ruby_platform_materializes_to_ruby_platform?
generic_platform = generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
(most_specific_locked_platform != generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform]

View File

@ -2,6 +2,8 @@
module Bundler
class LockfileParser
include GemHelpers
class Position
attr_reader :line, :column
def initialize(line, column)
@ -29,6 +31,7 @@ module Bundler
:dependencies,
:specs,
:platforms,
:most_specific_locked_platform,
:bundler_version,
:ruby_version,
:checksums,
@ -136,7 +139,12 @@ module Bundler
end
@pos.advance!(line)
end
@specs = @specs.values.sort_by!(&:full_name)
@most_specific_locked_platform = @platforms.min_by do |bundle_platform|
platform_specificity_match(bundle_platform, local_platform)
end
@specs = @specs.values.sort_by!(&:full_name).each do |spec|
spec.most_specific_locked_platform = @most_specific_locked_platform
end
rescue ArgumentError => e
Bundler.ui.debug(e)
raise LockfileError, "Your lockfile is unreadable. Run `rm #{@lockfile_path}` " \

View File

@ -15,10 +15,11 @@ module Bundler
include GemHelpers
def initialize(base, gem_version_promoter)
def initialize(base, gem_version_promoter, most_specific_locked_platform = nil)
@source_requirements = base.source_requirements
@base = base
@gem_version_promoter = gem_version_promoter
@most_specific_locked_platform = most_specific_locked_platform
end
def start
@ -79,7 +80,7 @@ module Bundler
def solve_versions(root:, logger:)
solver = PubGrub::VersionSolver.new(source: self, root: root, logger: logger)
result = solver.solve
resolved_specs = result.flat_map {|package, version| version.to_specs(package) }
resolved_specs = result.flat_map {|package, version| version.to_specs(package, @most_specific_locked_platform) }
resolved_specs |= @base.specs_compatible_with(SpecSet.new(resolved_specs))
rescue PubGrub::SolveFailure => e
incompatibility = e.incompatibility

View File

@ -34,10 +34,10 @@ module Bundler
@spec_group.dependencies
end
def to_specs(package)
def to_specs(package, most_specific_locked_platform)
return [] if package.meta?
@spec_group.to_specs(package.force_ruby_platform?)
@spec_group.to_specs(package.force_ruby_platform?, most_specific_locked_platform)
end
def prerelease?

View File

@ -25,10 +25,11 @@ module Bundler
@source ||= exemplary_spec.source
end
def to_specs(force_ruby_platform)
def to_specs(force_ruby_platform, most_specific_locked_platform)
@specs.map do |s|
lazy_spec = LazySpecification.from_spec(s)
lazy_spec.force_ruby_platform = force_ruby_platform
lazy_spec.most_specific_locked_platform = most_specific_locked_platform
lazy_spec
end
end

View File

@ -14,7 +14,7 @@ module Bundler
@incomplete_specs = incomplete_specs
end
def for(dependencies, check = false, platforms = [nil], most_specific_locked_platform = nil)
def for(dependencies, check = false, platforms = [nil])
handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h
deps = dependencies.product(platforms)
specs = []
@ -31,7 +31,7 @@ module Bundler
handled[key] = true
specs_for_dep = specs_for_dependency(*dep, most_specific_locked_platform)
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] })
@ -125,8 +125,8 @@ module Bundler
lookup.dup
end
def materialize(deps, most_specific_locked_platform = nil)
materialized = self.for(deps, true, [nil], most_specific_locked_platform)
def materialize(deps)
materialized = self.for(deps, true)
SpecSet.new(materialized, incomplete_specs)
end
@ -290,14 +290,14 @@ module Bundler
@specs.sort_by(&:name).each {|s| yield s }
end
def specs_for_dependency(dep, platform, most_specific_locked_platform)
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, most_specific_locked_platform: most_specific_locked_platform)
GemHelpers.select_best_local_platform_match(specs_for_name, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform)
end
end