diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2022-07-26 13:43:48 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2022-07-26 14:38:17 +0900 |
commit | 9e6d07f3462d29f340114650da9f13a36b866d5f (patch) | |
tree | 1b347705d94dc8a6f2df99372d10e3f0946ef0c0 /lib | |
parent | b404a5f106d13e25708c163c91e117b2e106b70c (diff) | |
download | ruby-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.rb | 3 | ||||
-rw-r--r-- | lib/bundler/definition.rb | 33 | ||||
-rw-r--r-- | lib/bundler/dependency.rb | 5 | ||||
-rw-r--r-- | lib/bundler/force_platform.rb | 18 | ||||
-rw-r--r-- | lib/bundler/incomplete_specification.rb | 12 | ||||
-rw-r--r-- | lib/bundler/lazy_specification.rb | 33 | ||||
-rw-r--r-- | lib/bundler/remote_specification.rb | 9 | ||||
-rw-r--r-- | lib/bundler/resolver.rb | 5 | ||||
-rw-r--r-- | lib/bundler/rubygems_ext.rb | 22 | ||||
-rw-r--r-- | lib/bundler/spec_set.rb | 52 |
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 |