[rubygems/rubygems] Fix yanked gems being unintentionally update when other gems are unlocked

This is a regression from a change intended to raise errors when user
puts a gem under an incorrect source in the Gemfile by mistake. To fix
the issue, we revert the change that caused it and implement it in a
different way that restores the resolver independency from real
specifications. Now it deals only with names and versions and does not
try to materialize anything into real specifications before resolving.

https://github.com/rubygems/rubygems/commit/d2bf1b86eb
This commit is contained in:
David Rodríguez 2022-08-03 19:03:50 +02:00 коммит произвёл git
Родитель 8dd63b89d9
Коммит 466a760e18
6 изменённых файлов: 81 добавлений и 20 удалений

Просмотреть файл

@ -739,11 +739,22 @@ module Bundler
specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) } specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
end end
@specs_that_changed_sources = []
specs.each do |s| specs.each do |s|
dep = @dependencies.find {|d| s.satisfies?(d) } dep = @dependencies.find {|d| s.satisfies?(d) }
# Replace the locked dependency's source with the equivalent source from the Gemfile # Replace the locked dependency's source with the equivalent source from the Gemfile
s.source = (dep && dep.source) || sources.get_with_fallback(s.source) s.source = if dep && dep.source
gemfile_source = dep.source
lockfile_source = s.source
@specs_that_changed_sources << s if gemfile_source != lockfile_source
gemfile_source
else
sources.get_with_fallback(s.source)
end
next if @unlock[:sources].include?(s.source.name) next if @unlock[:sources].include?(s.source.name)
@ -821,9 +832,18 @@ module Bundler
end end
source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source
source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements["bundler"] = sources.metadata_source # needs to come last to override
verify_changed_sources!
source_requirements source_requirements
end end
def verify_changed_sources!
@specs_that_changed_sources.each do |s|
if s.source.specs.search(s.name).empty?
raise GemNotFound, "Could not find gem '#{s.name}' in #{s.source}"
end
end
end
def requested_groups def requested_groups
values = groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] values = groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
values &= Bundler.settings[:only] unless Bundler.settings[:only].empty? values &= Bundler.settings[:only] unless Bundler.settings[:only].empty?

Просмотреть файл

@ -93,14 +93,6 @@ module Bundler
__materialize__(candidates) __materialize__(candidates)
end end
def materialize_for_resolution
return self unless Gem::Platform.match_spec?(self)
candidates = source.specs.search(self)
__materialize__(candidates)
end
def __materialize__(candidates) def __materialize__(candidates)
@specification = begin @specification = begin
search = candidates.reverse.find do |spec| search = candidates.reverse.find do |spec|

Просмотреть файл

@ -28,10 +28,11 @@ module Bundler
def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements) def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements)
@source_requirements = source_requirements @source_requirements = source_requirements
@metadata_requirements = metadata_requirements @metadata_requirements = metadata_requirements
@base = base
@resolver = Molinillo::Resolver.new(self, self) @resolver = Molinillo::Resolver.new(self, self)
@search_for = {} @search_for = {}
@base_dg = Molinillo::DependencyGraph.new @base_dg = Molinillo::DependencyGraph.new
@base = base.materialized_for_resolution do |ls| base.each do |ls|
dep = Dependency.new(ls.name, ls.version) dep = Dependency.new(ls.name, ls.version)
@base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true) @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
end end

Просмотреть файл

@ -82,15 +82,6 @@ module Bundler
end end
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 incomplete_ruby_specs?(deps) def incomplete_ruby_specs?(deps)
self.class.new(self.for(deps, true, [Gem::Platform::RUBY])).incomplete_specs.any? self.class.new(self.for(deps, true, [Gem::Platform::RUBY])).incomplete_specs.any?
end end

Просмотреть файл

@ -43,6 +43,63 @@ RSpec.context "when installing a bundle that includes yanked gems" do
end end
end end
RSpec.context "when resolving a bundle that includes yanked gems, but unlocking an unrelated gem" do
before(:each) do
build_repo4 do
build_gem "foo", "10.0.0"
build_gem "bar", "1.0.0"
build_gem "bar", "2.0.0"
end
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo4)}
specs:
foo (9.0.0)
bar (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo
bar
BUNDLED WITH
#{Bundler::VERSION}
L
gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "foo"
gem "bar"
G
end
it "does not update the yanked gem" do
bundle "lock --update bar"
expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
bar (2.0.0)
foo (9.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
bar
foo
BUNDLED WITH
#{Bundler::VERSION}
L
end
end
RSpec.context "when using gem before installing" do RSpec.context "when using gem before installing" do
it "does not suggest the author has yanked the gem" do it "does not suggest the author has yanked the gem" do
gemfile <<-G gemfile <<-G

Просмотреть файл

@ -233,7 +233,7 @@ Bundler could not find compatible versions for gem "a":
it "resolves foo only to latest patch - changing dependency declared case" do it "resolves foo only to latest patch - changing dependency declared case" do
# bar is locked AND a declared dependency in the Gemfile, so it will not move, and therefore # bar is locked AND a declared dependency in the Gemfile, so it will not move, and therefore
# foo can only move up to 1.4.4. # foo can only move up to 1.4.4.
@base << Bundler::LazySpecification.new("bar", "2.0.3", nil) @base << build_spec("bar", "2.0.3").first
should_conservative_resolve_and_include :patch, ["foo"], %w[foo-1.4.4 bar-2.0.3] should_conservative_resolve_and_include :patch, ["foo"], %w[foo-1.4.4 bar-2.0.3]
end end