[rubygems/rubygems] Show all missing gems when using a bundle before installing it

Not only the first one that's missing.

This also allows us to simplify things.

https://github.com/rubygems/rubygems/commit/69718a9509
This commit is contained in:
David Rodríguez 2021-07-23 23:49:13 +02:00 коммит произвёл Hiroshi SHIBATA
Родитель d298ef40f2
Коммит 9a25a98c6b
3 изменённых файлов: 57 добавлений и 37 удалений

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

@ -138,7 +138,7 @@ module Bundler
@unlock[:gems] ||= @dependencies.map(&:name)
else
eager_unlock = expand_dependencies(@unlock[:gems] || [], true)
@unlock[:gems] = @locked_specs.for(eager_unlock, false, false, false).map(&:name)
@unlock[:gems] = @locked_specs.for(eager_unlock, false, false).map(&:name)
end
@dependency_changes = converge_dependencies
@ -191,14 +191,6 @@ module Bundler
# @return [Bundler::SpecSet]
def specs
@specs ||= materialize(requested_dependencies)
rescue GemNotFound => e # Handle yanked gem
gem_name, gem_version = extract_gem_info(e)
locked_gem = @locked_specs[gem_name].last
raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote
raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
"no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
"You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
"removed in order to install."
end
def new_specs
@ -210,9 +202,7 @@ module Bundler
end
def missing_specs
missing = []
resolve.materialize(requested_dependencies, missing)
missing
resolve.materialize(requested_dependencies).missing_specs
end
def missing_specs?
@ -498,6 +488,20 @@ module Bundler
def materialize(dependencies)
specs = resolve.materialize(dependencies)
missing_specs = specs.missing_specs
if missing_specs.any?
missing_specs.each do |s|
locked_gem = @locked_specs[s.name].last
next if locked_gem.nil? || locked_gem.version != s.version || !@remote
raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
"no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
"You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
"removed in order to install."
end
raise GemNotFound, "Could not find #{missing_specs.map(&:full_name).join(", ")} in any of the sources"
end
unless specs["bundler"].any?
bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
@ -735,7 +739,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 @locked_specs.
for(requested_dependencies, false, true, false).
for(requested_dependencies, false, true).
none? {|locked_spec| locked_spec.source == s.source }
raise
@ -755,7 +759,7 @@ module Bundler
resolve = SpecSet.new(converged)
@locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(requested_dependencies & deps), true, true)
resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false, false).reject{|s| @unlock[:gems].include?(s.name) })
resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false).reject{|s| @unlock[:gems].include?(s.name) })
diff = nil
# Now, we unlock any sources that do not have anymore gems pinned to it
@ -859,12 +863,6 @@ module Bundler
current == proposed
end
def extract_gem_info(error)
# This method will extract the error message like "Could not find foo-1.2.3 in any of the sources"
# to an array. The first element will be the gem name (e.g. foo), the second will be the version number.
error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten
end
def compute_requires
dependencies.reduce({}) do |requires, dep|
next requires unless dep.should_include?

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

@ -11,7 +11,7 @@ module Bundler
@specs = specs
end
def for(dependencies, check = false, match_current_platform = false, raise_on_missing = true)
def for(dependencies, check = false, match_current_platform = false)
handled = []
deps = dependencies.dup
specs = []
@ -33,11 +33,6 @@ module Bundler
end
elsif check
return false
elsif raise_on_missing
others = lookup[dep.name] if match_current_platform
message = "Unable to find a spec satisfying #{dep} in the set. Perhaps the lockfile is corrupted?"
message += " Found #{others.join(", ")} that did not match the current platform." if others && !others.empty?
raise GemNotFound, message
end
end
@ -71,8 +66,8 @@ module Bundler
lookup.dup
end
def materialize(deps, missing_specs = nil)
materialized = self.for(deps, false, true, !missing_specs)
def materialize(deps)
materialized = self.for(deps, false, true)
materialized.group_by(&:source).each do |source, specs|
next unless specs.any?{|s| s.is_a?(LazySpecification) }
@ -84,16 +79,9 @@ module Bundler
materialized.map! do |s|
next s unless s.is_a?(LazySpecification)
spec = s.__materialize__
unless spec
unless missing_specs
raise GemNotFound, "Could not find #{s.full_name} in any of the sources"
end
missing_specs << s
end
spec
s.__materialize__ || s
end
SpecSet.new(missing_specs ? materialized.compact : materialized)
SpecSet.new(materialized)
end
# Materialize for all the specs in the spec set, regardless of what platform they're for
@ -117,6 +105,10 @@ module Bundler
end
end
def missing_specs
select {|s| s.is_a?(LazySpecification) }
end
def merge(set)
arr = sorted.dup
set.each do |set_spec|

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

@ -70,4 +70,34 @@ RSpec.context "when using gem before installing" do
expect(err).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.")
expect(err).to_not include("You'll need to update your bundle to a different version of rack (0.9.1) that hasn't been removed in order to install.")
end
it "does not suggest the author has yanked the gem when using more than one gem, but shows all gems that couldn't be found in the source" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", "0.9.1"
gem "rack_middleware", "1.0"
G
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo1)}
specs:
rack (0.9.1)
rack_middleware (1.0)
PLATFORMS
ruby
DEPENDENCIES
rack (= 0.9.1)
rack_middleware (1.0)
L
bundle :list, :raise_on_error => false
expect(err).to include("Could not find rack-0.9.1, rack_middleware-1.0 in any of the sources")
expect(err).to_not include("Your bundle is locked to rack (0.9.1), but that version could not be found in any of the sources listed in your Gemfile.")
expect(err).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.")
expect(err).to_not include("You'll need to update your bundle to a different version of rack (0.9.1) that hasn't been removed in order to install.")
end
end