aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorHiroshi SHIBATA <hsbt@ruby-lang.org>2022-07-26 13:43:48 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2022-07-26 14:38:17 +0900
commit9e6d07f3462d29f340114650da9f13a36b866d5f (patch)
tree1b347705d94dc8a6f2df99372d10e3f0946ef0c0 /lib
parentb404a5f106d13e25708c163c91e117b2e106b70c (diff)
downloadruby-9e6d07f3462d29f340114650da9f13a36b866d5f.tar.gz
Merge rubygems/bundler HEAD
Merge from https://github.com/rubygems/rubygems/commit/2af2520b4a7ab1c6eb1fdc3d2ef4d8c062d96ad7
Diffstat (limited to 'lib')
-rw-r--r--lib/bundler.rb3
-rw-r--r--lib/bundler/definition.rb33
-rw-r--r--lib/bundler/dependency.rb5
-rw-r--r--lib/bundler/force_platform.rb18
-rw-r--r--lib/bundler/incomplete_specification.rb12
-rw-r--r--lib/bundler/lazy_specification.rb33
-rw-r--r--lib/bundler/remote_specification.rb9
-rw-r--r--lib/bundler/resolver.rb5
-rw-r--r--lib/bundler/rubygems_ext.rb22
-rw-r--r--lib/bundler/spec_set.rb52
10 files changed, 111 insertions, 81 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 9fb9ce3e82..7df22ab3a5 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -53,6 +53,7 @@ module Bundler
autoload :GemHelpers, File.expand_path("bundler/gem_helpers", __dir__)
autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__)
autoload :Graph, File.expand_path("bundler/graph", __dir__)
+ autoload :IncompleteSpecification, File.expand_path("bundler/incomplete_specification", __dir__)
autoload :Index, File.expand_path("bundler/index", __dir__)
autoload :Injector, File.expand_path("bundler/injector", __dir__)
autoload :Installer, File.expand_path("bundler/installer", __dir__)
@@ -455,7 +456,7 @@ EOF
end
def local_platform
- return Gem::Platform::RUBY if settings[:force_ruby_platform]
+ return Gem::Platform::RUBY if settings[:force_ruby_platform] || Gem.platforms == [Gem::Platform::RUBY]
Gem::Platform.local
end
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 8f43befe35..4cb829470a 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -138,13 +138,13 @@ module Bundler
@unlock[:gems] ||= @dependencies.map(&:name)
else
eager_unlock = expand_dependencies(@unlock[:gems] || [], true)
- @unlock[:gems] = @locked_specs.for(eager_unlock, false, false).map(&:name)
+ @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name)
end
@dependency_changes = converge_dependencies
@local_changes = converge_locals
- @locked_specs_incomplete_for_platform = !@locked_specs.for(requested_dependencies & expand_dependencies(locked_dependencies), true, true)
+ @reresolve = nil
@requires = compute_requires
end
@@ -279,11 +279,8 @@ module Bundler
end
end
else
- last_resolve = converge_locked_specs
- # Run a resolve against the locally available gems
Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
- expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, true)
- Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
+ @reresolve = reresolve
end
end
@@ -468,7 +465,7 @@ module Bundler
private :sources
def nothing_changed?
- !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform
+ !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes
end
def unlocking?
@@ -477,8 +474,14 @@ module Bundler
private
+ def reresolve
+ last_resolve = converge_locked_specs
+ expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, true)
+ Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
+ end
+
def filter_specs(specs, deps)
- SpecSet.new(specs).for(expand_dependencies(deps, true), false, false)
+ SpecSet.new(specs).for(expand_dependencies(deps, true), false, platforms)
end
def materialize(dependencies)
@@ -502,6 +505,17 @@ module Bundler
raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}"
end
+ if @reresolve.nil?
+ incomplete_specs = specs.incomplete_specs
+
+ if incomplete_specs.any?
+ Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
+ @unlock[:gems].concat(incomplete_specs.map(&:name))
+ @resolve = reresolve
+ specs = resolve.materialize(dependencies)
+ end
+ end
+
unless specs["bundler"].any?
bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
specs["bundler"] = bundler
@@ -549,7 +563,6 @@ module Bundler
[@new_platform, "you added a new platform to your gemfile"],
[@path_changes, "the gemspecs for path gems changed"],
[@local_changes, "the gemspecs for git local gems changed"],
- [@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"],
].select(&:first).map(&:last).join(", ")
end
@@ -725,7 +738,7 @@ module Bundler
# if we won't need the source (according to the lockfile),
# don't error if the path/git source isn't available
next if specs.
- for(requested_dependencies, false, true).
+ for(requested_dependencies, false).
none? {|locked_spec| locked_spec.source == s.source }
raise
diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb
index 2449cb6411..7f94079e09 100644
--- a/lib/bundler/dependency.rb
+++ b/lib/bundler/dependency.rb
@@ -1,14 +1,11 @@
# frozen_string_literal: true
require "rubygems/dependency"
-require_relative "force_platform"
require_relative "shared_helpers"
require_relative "rubygems_ext"
module Bundler
class Dependency < Gem::Dependency
- include ForcePlatform
-
attr_reader :autorequire
attr_reader :groups, :platforms, :gemfile, :git, :github, :branch, :ref, :force_ruby_platform
@@ -112,7 +109,7 @@ module Bundler
@env = options["env"]
@should_include = options.fetch("should_include", true)
@gemfile = options["gemfile"]
- @force_ruby_platform = options.fetch("force_ruby_platform", default_force_ruby_platform)
+ @force_ruby_platform = options["force_ruby_platform"]
@autorequire = Array(options["require"] || []) if options.key?("require")
end
diff --git a/lib/bundler/force_platform.rb b/lib/bundler/force_platform.rb
deleted file mode 100644
index 0648ea9737..0000000000
--- a/lib/bundler/force_platform.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module ForcePlatform
- private
-
- # The `:force_ruby_platform` value used by dependencies for resolution, and
- # by locked specifications for materialization is `false` by default, except
- # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform
- # variant unless the name is explicitly allowlisted.
-
- def default_force_ruby_platform
- return false unless Bundler.current_ruby.truffleruby?
-
- !Gem::Platform::REUSE_AS_BINARY_ON_TRUFFLERUBY.include?(name)
- end
- end
-end
diff --git a/lib/bundler/incomplete_specification.rb b/lib/bundler/incomplete_specification.rb
new file mode 100644
index 0000000000..6d0b9b901c
--- /dev/null
+++ b/lib/bundler/incomplete_specification.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Bundler
+ class IncompleteSpecification
+ attr_reader :name, :platform
+
+ def initialize(name, platform)
+ @name = name
+ @platform = platform
+ end
+ end
+end
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index 89b21efc04..21e75d2126 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -1,16 +1,13 @@
# frozen_string_literal: true
-require_relative "force_platform"
require_relative "match_platform"
module Bundler
class LazySpecification
- include ForcePlatform
include MatchPlatform
attr_reader :name, :version, :dependencies, :platform
- attr_writer :force_ruby_platform
- attr_accessor :source, :remote
+ attr_accessor :source, :remote, :force_ruby_platform
def initialize(name, version, platform, source = nil)
@name = name
@@ -19,23 +16,16 @@ module Bundler
@platform = platform || Gem::Platform::RUBY
@source = source
@specification = nil
- @force_ruby_platform = nil
end
def full_name
- if platform == Gem::Platform::RUBY || platform.nil?
+ if platform == Gem::Platform::RUBY
"#{@name}-#{@version}"
else
"#{@name}-#{@version}-#{platform}"
end
end
- def force_ruby_platform
- return @force_ruby_platform unless @force_ruby_platform.nil?
-
- default_force_ruby_platform
- end
-
def ==(other)
identifier == other.identifier
end
@@ -71,7 +61,7 @@ module Bundler
def to_lock
out = String.new
- if platform == Gem::Platform::RUBY || platform.nil?
+ if platform == Gem::Platform::RUBY
out << " #{name} (#{version})\n"
else
out << " #{name} (#{version}-#{platform})\n"
@@ -85,7 +75,17 @@ module Bundler
out
end
- def __materialize__
+ def materialize_for_installation
+ __materialize__(ruby_platform_materializes_to_ruby_platform? ? platform : Bundler.local_platform)
+ end
+
+ def materialize_for_resolution
+ return self unless Gem::Platform.match_spec?(self)
+
+ __materialize__(platform)
+ end
+
+ def __materialize__(platform)
@specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name
source.gemspec.tap {|s| s.source = source }
else
@@ -94,10 +94,9 @@ module Bundler
else
ruby_platform_materializes_to_ruby_platform? ? self : Dependency.new(name, version)
end
- platform_object = ruby_platform_materializes_to_ruby_platform? ? Gem::Platform.new(platform) : Gem::Platform.local
candidates = source.specs.search(search_object)
same_platform_candidates = candidates.select do |spec|
- MatchPlatform.platforms_match?(spec.platform, platform_object)
+ MatchPlatform.platforms_match?(spec.platform, platform)
end
installable_candidates = same_platform_candidates.select do |spec|
spec.is_a?(StubSpecification) ||
@@ -115,7 +114,7 @@ module Bundler
end
def to_s
- @__to_s ||= if platform == Gem::Platform::RUBY || platform.nil?
+ @__to_s ||= if platform == Gem::Platform::RUBY
"#{name} (#{version})"
else
"#{name} (#{version}-#{platform})"
diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb
index 4e966b820a..b5d7e3a6c9 100644
--- a/lib/bundler/remote_specification.rb
+++ b/lib/bundler/remote_specification.rb
@@ -16,7 +16,8 @@ module Bundler
def initialize(name, version, platform, spec_fetcher)
@name = name
@version = Gem::Version.create version
- @platform = platform
+ @original_platform = platform || Gem::Platform::RUBY
+ @platform = Gem::Platform.new(platform)
@spec_fetcher = spec_fetcher
@dependencies = nil
end
@@ -35,10 +36,10 @@ module Bundler
end
def full_name
- if platform == Gem::Platform::RUBY || platform.nil?
+ if @original_platform == Gem::Platform::RUBY
"#{@name}-#{@version}"
else
- "#{@name}-#{@version}-#{platform}"
+ "#{@name}-#{@version}-#{@original_platform}"
end
end
@@ -105,7 +106,7 @@ module Bundler
end
def _remote_specification
- @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform])
+ @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform])
@_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \
" missing from the server! Try installing with `--full-index` as a workaround.")
end
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index 972a4c254d..33f232e184 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -22,17 +22,16 @@ module Bundler
metadata_requirements, regular_requirements = requirements.partition {|dep| dep.name.end_with?("\0") }
resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements)
result = resolver.start(requirements)
- SpecSet.new(SpecSet.new(result).for(regular_requirements))
+ SpecSet.new(SpecSet.new(result).for(regular_requirements, false, platforms))
end
def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements)
@source_requirements = source_requirements
@metadata_requirements = metadata_requirements
- @base = base
@resolver = Molinillo::Resolver.new(self, self)
@search_for = {}
@base_dg = Molinillo::DependencyGraph.new
- @base.each do |ls|
+ @base = base.materialized_for_resolution do |ls|
dep = Dependency.new(ls.name, ls.version)
@base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
end
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index d679d20c21..a47692d1f2 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -222,9 +222,27 @@ module Gem
MINGW = Gem::Platform.new("x86-mingw32")
X64_MINGW = [Gem::Platform.new("x64-mingw32"),
Gem::Platform.new("x64-mingw-ucrt")].freeze
+ end
+
+ Platform.singleton_class.module_eval do
+ unless Platform.singleton_methods.include?(:match_spec?)
+ def match_spec?(spec)
+ match_gem?(spec.platform, spec.name)
+ end
+
+ def match_gem?(platform, gem_name)
+ match_platforms?(platform, Gem.platforms)
+ end
+
+ private
- if RUBY_ENGINE == "truffleruby" && !defined?(REUSE_AS_BINARY_ON_TRUFFLERUBY)
- REUSE_AS_BINARY_ON_TRUFFLERUBY = %w[libv8 sorbet-static].freeze
+ def match_platforms?(platform, platforms)
+ platforms.any? do |local_platform|
+ platform.nil? ||
+ local_platform == platform ||
+ (local_platform != Gem::Platform::RUBY && local_platform =~ platform)
+ end
+ end
end
end
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index 06257ac93f..a7a95e49bc 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -11,30 +11,27 @@ module Bundler
@specs = specs
end
- def for(dependencies, check = false, match_current_platform = false)
- # dep.name => [list, of, deps]
- handled = Hash.new {|h, k| h[k] = [] }
- deps = dependencies.dup
+ def for(dependencies, check = false, platforms = [nil])
+ handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h
+ deps = dependencies.product(platforms).map {|dep, platform| [dep.name, platform && dep.force_ruby_platform ? Gem::Platform::RUBY : platform] }
specs = []
loop do
break unless dep = deps.shift
- next if handled[dep.name].any? {|d| match_current_platform || d.__platform == dep.__platform } || dep.name == "bundler"
+ next if handled.key?(dep)
- # use a hash here to ensure constant lookup time in the `any?` call above
- handled[dep.name] << dep
+ handled[dep] = true
- specs_for_dep = specs_for_dependency(dep, match_current_platform)
+ 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
- d = DepProxy.get_proxy(Dependency.new(d.name, d.requirement), dep.__platform) unless match_current_platform
- deps << d
+ deps << [d.name, dep[1]]
end
elsif check
- return false
+ specs << IncompleteSpecification.new(*dep)
end
end
@@ -42,9 +39,7 @@ module Bundler
specs << spec
end
- specs.uniq! unless match_current_platform
-
- check ? true : specs
+ specs
end
def [](key)
@@ -71,12 +66,12 @@ module Bundler
end
def materialize(deps)
- materialized = self.for(deps, false, true)
+ materialized = self.for(deps, true).uniq
materialized.map! do |s|
next s unless s.is_a?(LazySpecification)
s.source.local!
- s.__materialize__ || s
+ s.materialize_for_installation || s
end
SpecSet.new(materialized)
end
@@ -89,16 +84,29 @@ module Bundler
next s unless s.is_a?(LazySpecification)
s.source.local!
s.source.remote!
- spec = s.__materialize__
+ spec = s.materialize_for_installation
raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec
spec
end
end
+ def materialized_for_resolution
+ materialized = @specs.map do |s|
+ spec = s.materialize_for_resolution
+ yield spec if spec
+ spec
+ end.compact
+ SpecSet.new(materialized)
+ end
+
def missing_specs
@specs.select {|s| s.is_a?(LazySpecification) }
end
+ def incomplete_specs
+ @specs.select {|s| s.is_a?(IncompleteSpecification) }
+ end
+
def merge(set)
arr = sorted.dup
set.each do |set_spec|
@@ -173,12 +181,12 @@ module Bundler
@specs.sort_by(&:name).each {|s| yield s }
end
- def specs_for_dependency(dep, match_current_platform)
- specs_for_name = lookup[dep.name]
- if match_current_platform
- GemHelpers.select_best_platform_match(specs_for_name, Bundler.local_platform)
+ def specs_for_dependency(name, platform)
+ specs_for_name = lookup[name]
+ if platform.nil?
+ GemHelpers.select_best_platform_match(specs_for_name.select {|s| Gem::Platform.match_spec?(s) }, Bundler.local_platform)
else
- specs_for_name_and_platform = GemHelpers.select_best_platform_match(specs_for_name, dep.force_ruby_platform ? Gem::Platform::RUBY : dep.__platform)
+ specs_for_name_and_platform = GemHelpers.select_best_platform_match(specs_for_name, platform)
specs_for_name_and_platform.any? ? specs_for_name_and_platform : specs_for_name
end
end