mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Sync latest development version of bundler & rubygems
This commit is contained in:
parent
2ab6b7a751
commit
53468cc111
Notes:
git
2021-03-08 13:47:56 +09:00
161 changed files with 2544 additions and 1016 deletions
|
@ -5,6 +5,8 @@ module Bundler
|
|||
require_relative "vendored_molinillo"
|
||||
require_relative "resolver/spec_group"
|
||||
|
||||
include GemHelpers
|
||||
|
||||
# Figures out the best possible configuration of gems that satisfies
|
||||
# the list of passed dependencies and any child dependencies without
|
||||
# causing any gem activation errors.
|
||||
|
@ -15,31 +17,38 @@ module Bundler
|
|||
# ==== Returns
|
||||
# <GemBundle>,nil:: If the list of dependencies can be resolved, a
|
||||
# collection of gemspecs is returned. Otherwise, nil is returned.
|
||||
def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil)
|
||||
platforms = Set.new(platforms) if platforms
|
||||
def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil)
|
||||
base = SpecSet.new(base) unless base.is_a?(SpecSet)
|
||||
resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
|
||||
resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
|
||||
result = resolver.start(requirements)
|
||||
SpecSet.new(result)
|
||||
end
|
||||
|
||||
def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
|
||||
@index = index
|
||||
def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
|
||||
@source_requirements = source_requirements
|
||||
|
||||
@index_requirements = source_requirements.each_with_object({}) do |source_requirement, index_requirements|
|
||||
name, source = source_requirement
|
||||
index_requirements[name] = name == :global ? source : source.specs
|
||||
end
|
||||
|
||||
@base = base
|
||||
@resolver = Molinillo::Resolver.new(self, self)
|
||||
@search_for = {}
|
||||
@base_dg = Molinillo::DependencyGraph.new
|
||||
@base.each do |ls|
|
||||
dep = Dependency.new(ls.name, ls.version)
|
||||
@base_dg.add_vertex(ls.name, DepProxy.new(dep, ls.platform), true)
|
||||
@base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
|
||||
end
|
||||
additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
|
||||
@platforms = platforms
|
||||
@platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } }
|
||||
@resolving_only_for_ruby = platforms == [Gem::Platform::RUBY]
|
||||
@gem_version_promoter = gem_version_promoter
|
||||
@allow_bundler_dependency_conflicts = Bundler.feature_flag.allow_bundler_dependency_conflicts?
|
||||
@use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major?
|
||||
@lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource?
|
||||
@no_aggregate_global_source = @source_requirements[:global].nil?
|
||||
|
||||
@variant_specific_names = []
|
||||
@generic_names = ["Ruby\0", "RubyGems\0"]
|
||||
end
|
||||
|
||||
def start(requirements)
|
||||
|
@ -75,7 +84,7 @@ module Bundler
|
|||
return unless debug?
|
||||
debug_info = yield
|
||||
debug_info = debug_info.inspect unless debug_info.is_a?(String)
|
||||
puts debug_info.split("\n").map {|s| "BUNDLER: " + " " * depth + s }
|
||||
puts debug_info.split("\n").map {|s| depth == 0 ? "BUNDLER: #{s}" : "BUNDLER(#{depth}): #{s}" }
|
||||
end
|
||||
|
||||
def debug?
|
||||
|
@ -103,16 +112,25 @@ module Bundler
|
|||
include Molinillo::SpecificationProvider
|
||||
|
||||
def dependencies_for(specification)
|
||||
specification.dependencies_for_activated_platforms
|
||||
all_dependencies = specification.dependencies_for_activated_platforms
|
||||
|
||||
if @variant_specific_names.include?(specification.name)
|
||||
@variant_specific_names |= all_dependencies.map(&:name) - @generic_names
|
||||
else
|
||||
generic_names, variant_specific_names = specification.partitioned_dependency_names_for_activated_platforms
|
||||
@variant_specific_names |= variant_specific_names - @generic_names
|
||||
@generic_names |= generic_names
|
||||
end
|
||||
|
||||
all_dependencies
|
||||
end
|
||||
|
||||
def search_for(dependency_proxy)
|
||||
platform = dependency_proxy.__platform
|
||||
dependency = dependency_proxy.dep
|
||||
@search_for[dependency_proxy] ||= begin
|
||||
name = dependency.name
|
||||
index = index_for(dependency)
|
||||
results = index.search(dependency, @base[name])
|
||||
name = dependency.name
|
||||
search_result = @search_for[dependency_proxy] ||= begin
|
||||
results = results_for(dependency, @base[name])
|
||||
|
||||
if vertex = @base_dg.vertex_named(name)
|
||||
locked_requirement = vertex.payload.requirement
|
||||
|
@ -137,55 +155,67 @@ module Bundler
|
|||
end
|
||||
nested.reduce([]) do |groups, (version, specs)|
|
||||
next groups if locked_requirement && !locked_requirement.satisfied_by?(version)
|
||||
spec_group = SpecGroup.new(specs)
|
||||
spec_group.ignores_bundler_dependencies = @allow_bundler_dependency_conflicts
|
||||
groups << spec_group
|
||||
|
||||
specs_by_platform = Hash.new do |current_specs, current_platform|
|
||||
current_specs[current_platform] = select_best_platform_match(specs, current_platform)
|
||||
end
|
||||
|
||||
spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY)
|
||||
groups << spec_group_ruby if spec_group_ruby
|
||||
|
||||
next groups if @resolving_only_for_ruby
|
||||
|
||||
spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform)
|
||||
groups << spec_group if spec_group
|
||||
|
||||
groups
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
# GVP handles major itself, but it's still a bit risky to trust it with it
|
||||
# until we get it settled with new behavior. For 2.x it can take over all cases.
|
||||
search = if !@use_gvp
|
||||
if !@use_gvp
|
||||
spec_groups
|
||||
else
|
||||
@gem_version_promoter.sort_versions(dependency, spec_groups)
|
||||
end
|
||||
selected_sgs = []
|
||||
search.each do |sg|
|
||||
next unless sg.for?(platform)
|
||||
sg_all_platforms = sg.copy_for(self.class.sort_platforms(@platforms).reverse)
|
||||
next unless sg_all_platforms
|
||||
|
||||
selected_sgs << sg_all_platforms
|
||||
|
||||
next if sg_all_platforms.activated_platforms == [Gem::Platform::RUBY]
|
||||
# Add a spec group for "non platform specific spec" as the fallback
|
||||
# spec group.
|
||||
sg_ruby = sg.copy_for([Gem::Platform::RUBY])
|
||||
selected_sgs.insert(-2, sg_ruby) if sg_ruby
|
||||
end
|
||||
selected_sgs
|
||||
end
|
||||
|
||||
unless search_result.empty?
|
||||
specific_dependency = @variant_specific_names.include?(name)
|
||||
return search_result unless specific_dependency
|
||||
|
||||
search_result.each do |sg|
|
||||
if @generic_names.include?(name)
|
||||
@variant_specific_names -= [name]
|
||||
sg.activate_all_platforms!
|
||||
else
|
||||
sg.activate_platform!(platform)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
search_result
|
||||
end
|
||||
|
||||
def index_for(dependency)
|
||||
source = @source_requirements[dependency.name]
|
||||
source = @index_requirements[dependency.name]
|
||||
if source
|
||||
source.specs
|
||||
elsif @lockfile_uses_separate_rubygems_sources
|
||||
source
|
||||
elsif @no_aggregate_global_source
|
||||
Index.build do |idx|
|
||||
if dependency.all_sources
|
||||
dependency.all_sources.each {|s| idx.add_source(s.specs) if s }
|
||||
else
|
||||
idx.add_source @source_requirements[:default].specs
|
||||
end
|
||||
dependency.all_sources.each {|s| idx.add_source(s.specs) }
|
||||
end
|
||||
else
|
||||
@index
|
||||
@index_requirements[:global]
|
||||
end
|
||||
end
|
||||
|
||||
def results_for(dependency, base)
|
||||
index_for(dependency).search(dependency, base)
|
||||
end
|
||||
|
||||
def name_for(dependency)
|
||||
dependency.name
|
||||
end
|
||||
|
@ -206,21 +236,27 @@ module Bundler
|
|||
requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
|
||||
end
|
||||
|
||||
def dependencies_equal?(dependencies, other_dependencies)
|
||||
dependencies.map(&:dep) == other_dependencies.map(&:dep)
|
||||
end
|
||||
|
||||
def relevant_sources_for_vertex(vertex)
|
||||
if vertex.root?
|
||||
[@source_requirements[vertex.name]]
|
||||
elsif @lockfile_uses_separate_rubygems_sources
|
||||
elsif @no_aggregate_global_source
|
||||
vertex.recursive_predecessors.map do |v|
|
||||
@source_requirements[v.name]
|
||||
end << @source_requirements[:default]
|
||||
end.compact << @source_requirements[:default]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def sort_dependencies(dependencies, activated, conflicts)
|
||||
dependencies.sort_by do |dependency|
|
||||
dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name))
|
||||
name = name_for(dependency)
|
||||
vertex = activated.vertex_named(name)
|
||||
dependency.all_sources = relevant_sources_for_vertex(vertex)
|
||||
[
|
||||
@base_dg.vertex_named(name) ? 0 : 1,
|
||||
vertex.payload ? 0 : 1,
|
||||
|
@ -233,13 +269,6 @@ module Bundler
|
|||
end
|
||||
end
|
||||
|
||||
# Sort platforms from most general to most specific
|
||||
def self.sort_platforms(platforms)
|
||||
platforms.sort_by do |platform|
|
||||
platform_sort_key(platform)
|
||||
end
|
||||
end
|
||||
|
||||
def self.platform_sort_key(platform)
|
||||
# Prefer specific platform to not specific platform
|
||||
return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform
|
||||
|
@ -294,7 +323,7 @@ module Bundler
|
|||
"If you are updating multiple gems in your Gemfile at once,\n" \
|
||||
"try passing them all to `bundle update`"
|
||||
elsif source = @source_requirements[name]
|
||||
specs = source.specs[name]
|
||||
specs = source.specs.search(name)
|
||||
versions_with_platforms = specs.map {|s| [s.version, s.platform] }
|
||||
message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n")
|
||||
message << if versions_with_platforms.any?
|
||||
|
@ -303,7 +332,7 @@ module Bundler
|
|||
"The source does not contain any versions of '#{name}'"
|
||||
end
|
||||
else
|
||||
message = "Could not find gem '#{requirement}' in any of the gem sources " \
|
||||
message = "Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in any of the gem sources " \
|
||||
"listed in your Gemfile#{cache_message}."
|
||||
end
|
||||
raise GemNotFound, message
|
||||
|
@ -324,10 +353,16 @@ module Bundler
|
|||
def version_conflict_message(e)
|
||||
# only show essential conflicts, if possible
|
||||
conflicts = e.conflicts.dup
|
||||
conflicts.delete_if do |_name, conflict|
|
||||
deps = conflict.requirement_trees.map(&:last).flatten(1)
|
||||
!Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
|
||||
|
||||
if conflicts["bundler"]
|
||||
conflicts.replace("bundler" => conflicts["bundler"])
|
||||
else
|
||||
conflicts.delete_if do |_name, conflict|
|
||||
deps = conflict.requirement_trees.map(&:last).flatten(1)
|
||||
!Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
|
||||
end
|
||||
end
|
||||
|
||||
e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty?
|
||||
|
||||
solver_name = "Bundler"
|
||||
|
@ -355,15 +390,25 @@ module Bundler
|
|||
:additional_message_for_conflict => lambda do |o, name, conflict|
|
||||
if name == "bundler"
|
||||
o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
|
||||
other_bundler_required = !conflict.requirement.requirement.satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
||||
end
|
||||
|
||||
if name == "bundler" && other_bundler_required
|
||||
o << "\n"
|
||||
o << "This Gemfile requires a different version of Bundler.\n"
|
||||
o << "Perhaps you need to update Bundler by running `gem install bundler`?\n"
|
||||
end
|
||||
if conflict.locked_requirement
|
||||
conflict_dependency = conflict.requirement
|
||||
conflict_requirement = conflict_dependency.requirement
|
||||
other_bundler_required = !conflict_requirement.satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
||||
|
||||
if other_bundler_required
|
||||
o << "\n\n"
|
||||
|
||||
candidate_specs = @index_requirements[:default_bundler].search(conflict_dependency)
|
||||
if candidate_specs.any?
|
||||
target_version = candidate_specs.last.version
|
||||
new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ")
|
||||
o << "Your bundle requires a different version of Bundler than the one you're running.\n"
|
||||
o << "Install the necessary version with `gem install bundler:#{target_version}` and rerun bundler using `#{new_command}`\n"
|
||||
else
|
||||
o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n"
|
||||
end
|
||||
end
|
||||
elsif conflict.locked_requirement
|
||||
o << "\n"
|
||||
o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
|
||||
o << %(the gems in your Gemfile, which may resolve the conflict.\n)
|
||||
|
@ -372,14 +417,8 @@ module Bundler
|
|||
|
||||
relevant_sources = if conflict.requirement.source
|
||||
[conflict.requirement.source]
|
||||
elsif conflict.requirement.all_sources
|
||||
conflict.requirement.all_sources
|
||||
elsif @lockfile_uses_separate_rubygems_sources
|
||||
# every conflict should have an explicit group of sources when we
|
||||
# enforce strict pinning
|
||||
raise "no source set for #{conflict}"
|
||||
else
|
||||
[]
|
||||
conflict.requirement.all_sources
|
||||
end.compact.map(&:to_s).uniq.sort
|
||||
|
||||
metadata_requirement = name.end_with?("\0")
|
||||
|
@ -416,23 +455,21 @@ module Bundler
|
|||
def validate_resolved_specs!(resolved_specs)
|
||||
resolved_specs.each do |v|
|
||||
name = v.name
|
||||
next unless sources = relevant_sources_for_vertex(v)
|
||||
sources.compact!
|
||||
sources = relevant_sources_for_vertex(v)
|
||||
next unless sources.any?
|
||||
if default_index = sources.index(@source_requirements[:default])
|
||||
sources.delete_at(default_index)
|
||||
end
|
||||
sources.reject! {|s| s.specs[name].empty? }
|
||||
sources.reject! {|s| s.specs.search(name).empty? }
|
||||
sources.uniq!
|
||||
next if sources.size <= 1
|
||||
|
||||
multisource_disabled = Bundler.feature_flag.disable_multisource?
|
||||
|
||||
msg = ["The gem '#{name}' was found in multiple relevant sources."]
|
||||
msg.concat sources.map {|s| " * #{s}" }.sort
|
||||
msg << "You #{multisource_disabled ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
|
||||
msg << "You #{@no_aggregate_global_source ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
|
||||
msg = msg.join("\n")
|
||||
|
||||
raise SecurityError, msg if multisource_disabled
|
||||
raise SecurityError, msg if @no_aggregate_global_source
|
||||
Bundler.ui.warn "Warning: #{msg}"
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue