1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Merge RubyGems 3.2.6 and Bundler 2.2.6 (#4103)

This commit is contained in:
Hiroshi SHIBATA 2021-01-21 14:35:56 +09:00 committed by GitHub
parent 41d0c70812
commit 151e469a62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 236 additions and 51 deletions

View file

@ -818,11 +818,6 @@ module Bundler
# commonly happens if the version changed in the gemspec # commonly happens if the version changed in the gemspec
next unless new_spec next unless new_spec
new_runtime_deps = new_spec.dependencies.select {|d| d.type != :development }
old_runtime_deps = s.dependencies.select {|d| d.type != :development }
# If the dependencies of the path source have changed and locked spec can't satisfy new dependencies, unlock it
next unless new_runtime_deps.sort == old_runtime_deps.sort || new_runtime_deps.all? {|d| satisfies_locked_spec?(d) }
s.dependencies.replace(new_spec.dependencies) s.dependencies.replace(new_spec.dependencies)
end end
@ -897,7 +892,7 @@ module Bundler
def expand_dependency_with_platforms(dep, platforms) def expand_dependency_with_platforms(dep, platforms)
platforms.map do |p| platforms.map do |p|
DepProxy.new(dep, p) DepProxy.get_proxy(dep, p)
end end
end end
@ -977,7 +972,7 @@ module Bundler
next requirements if @locked_gems.dependencies[name] != dependency next requirements if @locked_gems.dependencies[name] != dependency
next requirements if dependency.source.is_a?(Source::Path) next requirements if dependency.source.is_a?(Source::Path)
dep = Gem::Dependency.new(name, ">= #{locked_spec.version}") dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
requirements[name] = DepProxy.new(dep, locked_spec.platform) requirements[name] = DepProxy.get_proxy(dep, locked_spec.platform)
requirements requirements
end.values end.values
end end

View file

@ -4,19 +4,18 @@ module Bundler
class DepProxy class DepProxy
attr_reader :__platform, :dep attr_reader :__platform, :dep
@proxies = {}
def self.get_proxy(dep, platform)
@proxies[[dep, platform]] ||= new(dep, platform).freeze
end
def initialize(dep, platform) def initialize(dep, platform)
@dep = dep @dep = dep
@__platform = platform @__platform = platform
end end
def hash private_class_method :new
@hash ||= [dep, __platform].hash
end
def ==(other)
return false if other.class != self.class
dep == other.dep && __platform == other.__platform
end
alias_method :eql?, :== alias_method :eql?, :==
@ -39,6 +38,14 @@ module Bundler
s s
end end
def dup
raise NoMethodError.new("DepProxy cannot be duplicated")
end
def clone
raise NoMethodError.new("DepProxy cannot be cloned")
end
private private
def method_missing(*args, &blk) def method_missing(*args, &blk)

View file

@ -81,8 +81,8 @@ module Bundler
sort_dep_specs(spec_groups, locked_spec) sort_dep_specs(spec_groups, locked_spec)
end.tap do |specs| end.tap do |specs|
if DEBUG if DEBUG
warn before_result puts before_result
warn " after sort_versions: #{debug_format_result(dep, specs).inspect}" puts " after sort_versions: #{debug_format_result(dep, specs).inspect}"
end end
end end
end end

View file

@ -32,7 +32,7 @@ module Bundler
@base_dg = Molinillo::DependencyGraph.new @base_dg = Molinillo::DependencyGraph.new
@base.each 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.new(dep, ls.platform), true) @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
end end
additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
@platforms = platforms @platforms = platforms
@ -75,7 +75,7 @@ module Bundler
return unless debug? return unless debug?
debug_info = yield debug_info = yield
debug_info = debug_info.inspect unless debug_info.is_a?(String) 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 end
def debug? def debug?

View file

@ -99,7 +99,7 @@ module Bundler
spec.dependencies.each do |dep| spec.dependencies.each do |dep|
next if dep.type == :development next if dep.type == :development
next if @ignores_bundler_dependencies && dep.name == "bundler".freeze next if @ignores_bundler_dependencies && dep.name == "bundler".freeze
dependencies[platform] << DepProxy.new(dep, platform) dependencies[platform] << DepProxy.get_proxy(dep, platform)
end end
end end
dependencies[platform] dependencies[platform]
@ -110,10 +110,10 @@ module Bundler
return [] unless spec && spec.is_a?(Gem::Specification) return [] unless spec && spec.is_a?(Gem::Specification)
dependencies = [] dependencies = []
if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none? if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
dependencies << DepProxy.new(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform) dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
end end
if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none? if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none?
dependencies << DepProxy.new(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform) dependencies << DepProxy.get_proxy(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform)
end end
dependencies dependencies
end end

View file

@ -158,6 +158,22 @@ module Gem
end end
end end
if Gem::Requirement.new("~> 2.0").hash == Gem::Requirement.new("~> 2.0.0").hash
class Requirement
module CorrectHashForLambdaOperator
def hash
if requirements.any? {|r| r.first == "~>" }
requirements.map {|r| r.first == "~>" ? [r[0], r[1].to_s] : r }.sort.hash
else
super
end
end
end
prepend CorrectHashForLambdaOperator
end
end
class Platform class Platform
JAVA = Gem::Platform.new("java") unless defined?(JAVA) JAVA = Gem::Platform.new("java") unless defined?(JAVA)
MSWIN = Gem::Platform.new("mswin32") unless defined?(MSWIN) MSWIN = Gem::Platform.new("mswin32") unless defined?(MSWIN)

View file

@ -28,7 +28,7 @@ module Bundler
specs_for_dep.first.dependencies.each do |d| specs_for_dep.first.dependencies.each do |d|
next if d.type == :development next if d.type == :development
d = DepProxy.new(d, dep.__platform) unless match_current_platform d = DepProxy.get_proxy(d, dep.__platform) unless match_current_platform
deps << d deps << d
end end
elsif check elsif check

View file

@ -329,11 +329,11 @@ module Bundler::Molinillo
# Look for past conflicts that could be unwound to affect the # Look for past conflicts that could be unwound to affect the
# requirement tree for the current conflict # requirement tree for the current conflict
all_reqs = last_detail_for_current_unwind.all_requirements
all_reqs_size = all_reqs.size
relevant_unused_unwinds = unused_unwind_options.select do |alternative| relevant_unused_unwinds = unused_unwind_options.select do |alternative|
intersecting_requirements = diff_reqs = all_reqs - alternative.requirements_unwound_to_instead
last_detail_for_current_unwind.all_requirements & next if diff_reqs.size == all_reqs_size
alternative.requirements_unwound_to_instead
next if intersecting_requirements.empty?
# Find the highest index unwind whilst looping through # Find the highest index unwind whilst looping through
current_detail = alternative if alternative > current_detail current_detail = alternative if alternative > current_detail
alternative alternative
@ -344,8 +344,12 @@ module Bundler::Molinillo
state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 } state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 }
# Update the requirements_unwound_to_instead on any relevant unused unwinds # Update the requirements_unwound_to_instead on any relevant unused unwinds
relevant_unused_unwinds.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } relevant_unused_unwinds.each do |d|
unwind_details.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
end
unwind_details.each do |d|
(d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
end
current_detail current_detail
end end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: false # frozen_string_literal: false
module Bundler module Bundler
VERSION = "2.2.5".freeze VERSION = "2.2.6".freeze
def self.bundler_major_version def self.bundler_major_version
@bundler_major_version ||= VERSION.split(".").first.to_i @bundler_major_version ||= VERSION.split(".").first.to_i

View file

@ -8,7 +8,7 @@
require 'rbconfig' require 'rbconfig'
module Gem module Gem
VERSION = "3.2.5".freeze VERSION = "3.2.6".freeze
end end
# Must be first since it unloads the prelude from 1.9.2 # Must be first since it unloads the prelude from 1.9.2
@ -469,7 +469,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
next if File.exist? subdir next if File.exist? subdir
begin begin
FileUtils.mkdir_p subdir, **options FileUtils.mkdir_p subdir, **options
rescue Errno::EACCES rescue SystemCallError
end end
end end
ensure ensure

View file

@ -28,13 +28,14 @@ class Gem::Ext::Builder
unless make_program unless make_program
make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make' make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
end end
make_program = Shellwords.split(make_program)
destdir = 'DESTDIR=%s' % ENV['DESTDIR'] destdir = 'DESTDIR=%s' % ENV['DESTDIR']
['clean', '', 'install'].each do |target| ['clean', '', 'install'].each do |target|
# Pass DESTDIR via command line to override what's in MAKEFLAGS # Pass DESTDIR via command line to override what's in MAKEFLAGS
cmd = [ cmd = [
make_program, *make_program,
destdir, destdir,
target, target,
].reject(&:empty?) ].reject(&:empty?)

View file

@ -121,10 +121,6 @@ class Gem::Platform
end end
end end
def inspect
"%s @cpu=%p, @os=%p, @version=%p>" % [super[0..-2], *to_a]
end
def to_a def to_a
[@cpu, @os, @version] [@cpu, @os, @version]
end end

View file

@ -190,7 +190,7 @@ class Gem::Requirement
end end
def hash # :nodoc: def hash # :nodoc:
requirements.sort.hash requirements.map {|r| r.first == "~>" ? [r[0], r[1].to_s] : r }.sort.hash
end end
def marshal_dump # :nodoc: def marshal_dump # :nodoc:

View file

@ -2,10 +2,10 @@
RSpec.describe Bundler::DepProxy do RSpec.describe Bundler::DepProxy do
let(:dep) { Bundler::Dependency.new("rake", ">= 0") } let(:dep) { Bundler::Dependency.new("rake", ">= 0") }
subject { described_class.new(dep, Gem::Platform::RUBY) } subject { described_class.get_proxy(dep, Gem::Platform::RUBY) }
let(:same) { subject } let(:same) { subject }
let(:other) { subject.dup } let(:other) { described_class.get_proxy(dep, Gem::Platform::RUBY) }
let(:different) { described_class.new(dep, Gem::Platform::JAVA) } let(:different) { described_class.get_proxy(dep, Gem::Platform::JAVA) }
describe "#eql?" do describe "#eql?" do
it { expect(subject.eql?(same)).to be true } it { expect(subject.eql?(same)).to be true }
@ -15,8 +15,18 @@ RSpec.describe Bundler::DepProxy do
it { expect(subject.eql?("foobar")).to be false } it { expect(subject.eql?("foobar")).to be false }
end end
describe "#hash" do describe "must use factory methods" do
it { expect(subject.hash).to eq(same.hash) } it { expect { described_class.new(dep, Gem::Platform::RUBY) }.to raise_error NoMethodError }
it { expect(subject.hash).to eq(other.hash) } it { expect { subject.dup }.to raise_error NoMethodError }
it { expect { subject.clone }.to raise_error NoMethodError }
end
describe "frozen" do
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.5.0")
error = Object.const_get("FrozenError")
else
error = RuntimeError
end
it { expect { subject.instance_variable_set(:@__platform, {}) }.to raise_error error }
end end
end end

View file

@ -170,7 +170,7 @@ RSpec.describe Bundler::GemVersionPromoter do
context "debug output" do context "debug output" do
it "should not kerblooie on its own debug output" do it "should not kerblooie on its own debug output" do
gvp = unlocking(:level => :patch) gvp = unlocking(:level => :patch)
dep = Bundler::DepProxy.new(dep("foo", "1.2.0").first, "ruby") dep = Bundler::DepProxy.get_proxy(dep("foo", "1.2.0").first, "ruby")
result = gvp.send(:debug_format_result, dep, build_spec_groups("foo", %w[1.2.0 1.3.0])) result = gvp.send(:debug_format_result, dep, build_spec_groups("foo", %w[1.2.0 1.3.0]))
expect(result.class).to eq Array expect(result.class).to eq Array
end end

View file

@ -581,6 +581,71 @@ RSpec.describe "bundle install with explicit source paths" do
expect(the_bundle).to include_gems "rack 0.9.1" expect(the_bundle).to include_gems "rack 0.9.1"
end end
it "keeps using the same version even when another dependency is added" do
build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.add_dependency "rack", "0.9.1"
end
bundle "install"
expect(the_bundle).to include_gems "rack 0.9.1"
lockfile_should_be <<-G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
rack (= 0.9.1)
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
BUNDLED WITH
#{Bundler::VERSION}
G
build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.add_dependency "rack"
s.add_dependency "rake", "13.0.1"
end
bundle "install"
lockfile_should_be <<-G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
rack
rake (= 13.0.1)
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
rack (0.9.1)
rake (13.0.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
BUNDLED WITH
#{Bundler::VERSION}
G
expect(the_bundle).to include_gems "rack 0.9.1"
end
end end
describe "switching sources" do describe "switching sources" do

View file

@ -88,7 +88,7 @@ RSpec.describe "bundle install with install-time dependencies" do
end end
it "installs plugins depended on by other plugins" do it "installs plugins depended on by other plugins" do
install_gemfile <<-G install_gemfile <<-G, :env => { "DEBUG" => "1" }
source "#{file_uri_for(gem_repo2)}" source "#{file_uri_for(gem_repo2)}"
gem "net_a" gem "net_a"
G G
@ -97,7 +97,7 @@ RSpec.describe "bundle install with install-time dependencies" do
end end
it "installs multiple levels of dependencies" do it "installs multiple levels of dependencies" do
install_gemfile <<-G install_gemfile <<-G, :env => { "DEBUG" => "1" }
source "#{file_uri_for(gem_repo2)}" source "#{file_uri_for(gem_repo2)}"
gem "net_c" gem "net_c"
gem "net_e" gem "net_e"
@ -114,7 +114,7 @@ RSpec.describe "bundle install with install-time dependencies" do
gem "net_e" gem "net_e"
G G
bundle :install, :env => { "BUNDLER_DEBUG_RESOLVER" => "1" } bundle :install, :env => { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
expect(out).to include("BUNDLER: Starting resolution") expect(out).to include("BUNDLER: Starting resolution")
end end
@ -128,7 +128,7 @@ RSpec.describe "bundle install with install-time dependencies" do
gem "net_e" gem "net_e"
G G
bundle :install, :env => { "DEBUG_RESOLVER" => "1" } bundle :install, :env => { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
expect(out).to include("BUNDLER: Starting resolution") expect(out).to include("BUNDLER: Starting resolution")
end end

View file

@ -0,0 +1,20 @@
# frozen_string_literal: true
require "spec_helper"
RSpec.describe "bundle install with complex dependencies", :realworld => true do
it "resolves quickly" do
start_time = Time.now
install_gemfile <<-G
source 'https://rubygems.org'
gem "actionmailer"
gem "mongoid", ">= 0.10.2"
G
duration = Time.now - start_time
expect(duration.to_f).to be < 120 # seconds
end
end

View file

@ -176,7 +176,7 @@ Bundler could not find compatible versions for gem "a":
deps = [] deps = []
@deps.each do |d| @deps.each do |d|
deps << Bundler::DepProxy.new(d, "ruby") deps << Bundler::DepProxy.get_proxy(d, "ruby")
end end
should_resolve_and_include %w[foo-1.0.0 bar-1.0.0], [[]] should_resolve_and_include %w[foo-1.0.0 bar-1.0.0], [[]]

View file

@ -22,7 +22,7 @@ module Spec
@deps.each do |d| @deps.each do |d|
@platforms.each do |p| @platforms.each do |p|
source_requirements[d.name] = d.source = default_source source_requirements[d.name] = d.source = default_source
deps << Bundler::DepProxy.new(d, p) deps << Bundler::DepProxy.get_proxy(d, p)
end end
end end
source_requirements ||= {} source_requirements ||= {}

View file

@ -692,6 +692,11 @@ class TestGem < Gem::TestCase
ensure ensure
FileUtils.chmod 0600, parent FileUtils.chmod 0600, parent
end end
def test_self_ensure_gem_directories_non_existent_paths
Gem.ensure_gem_subdirectories '/proc/0123456789/bogus' # should not raise
Gem.ensure_gem_subdirectories 'classpath:/bogus/x' # JRuby embed scenario
end
end end
def test_self_extension_dir_shared def test_self_extension_dir_shared

View file

@ -14,6 +14,7 @@ class TestGemExtBuilder < Gem::TestCase
FileUtils.mkdir_p @dest_path FileUtils.mkdir_p @dest_path
@orig_DESTDIR = ENV['DESTDIR'] @orig_DESTDIR = ENV['DESTDIR']
@orig_make = ENV['make']
@spec = util_spec 'a' @spec = util_spec 'a'
@ -22,6 +23,7 @@ class TestGemExtBuilder < Gem::TestCase
def teardown def teardown
ENV['DESTDIR'] = @orig_DESTDIR ENV['DESTDIR'] = @orig_DESTDIR
ENV['make'] = @orig_make
super super
end end
@ -81,6 +83,28 @@ install:
assert_match %r{DESTDIR\\=#{ENV['DESTDIR']} install$}, results assert_match %r{DESTDIR\\=#{ENV['DESTDIR']} install$}, results
end end
def test_custom_make_with_options
ENV['make'] = 'make V=1'
results = []
File.open File.join(@ext, 'Makefile'), 'w' do |io|
io.puts <<-MAKEFILE
all:
\t@#{Gem.ruby} -e "puts 'all: OK'"
clean:
\t@#{Gem.ruby} -e "puts 'clean: OK'"
install:
\t@#{Gem.ruby} -e "puts 'install: OK'"
MAKEFILE
end
Gem::Ext::Builder.make @dest_path, results, @ext
results = results.join("\n").b
assert_match %r{clean: OK}, results
assert_match %r{all: OK}, results
assert_match %r{install: OK}, results
end
def test_build_extensions def test_build_extensions
@spec.extensions << 'ext/extconf.rb' @spec.extensions << 'ext/extconf.rb'

View file

@ -356,6 +356,14 @@ class TestGemPlatform < Gem::TestCase
assert_local_match 'sparc-solaris2.8-mq5.3' assert_local_match 'sparc-solaris2.8-mq5.3'
end end
def test_inspect
result = Gem::Platform.new("universal-java11").inspect
assert_equal 1, result.scan(/@cpu=/).size
assert_equal 1, result.scan(/@os=/).size
assert_equal 1, result.scan(/@version=/).size
end
def assert_local_match(name) def assert_local_match(name)
assert_match Gem::Platform.local, name assert_match Gem::Platform.local, name
end end

View file

@ -402,6 +402,27 @@ class TestGemRequirement < Gem::TestCase
assert_equal r1.hash, r2.hash assert_equal r1.hash, r2.hash
end end
def test_hash_returns_equal_hashes_for_equivalent_requirements
refute_requirement_hash_equal "= 1.2", "= 1.3"
refute_requirement_hash_equal "= 1.3", "= 1.2"
refute_requirement_hash_equal "~> 1.3", "~> 1.3.0"
refute_requirement_hash_equal "~> 1.3.0", "~> 1.3"
assert_requirement_hash_equal ["> 2", "~> 1.3", "~> 1.3.1"], ["~> 1.3.1", "~> 1.3", "> 2"]
assert_requirement_hash_equal ["> 2", "~> 1.3"], ["> 2.0", "~> 1.3"]
assert_requirement_hash_equal ["> 2.0", "~> 1.3"], ["> 2", "~> 1.3"]
assert_requirement_hash_equal "= 1.0", "= 1.0.0"
assert_requirement_hash_equal "= 1.1", "= 1.1.0"
assert_requirement_hash_equal "= 1", "= 1.0.0"
assert_requirement_hash_equal "1.0", "1.0.0"
assert_requirement_hash_equal "1.1", "1.1.0"
assert_requirement_hash_equal "1", "1.0.0"
end
# Assert that two requirements are equal. Handles Gem::Requirements, # Assert that two requirements are equal. Handles Gem::Requirements,
# strings, arrays, numbers, and versions. # strings, arrays, numbers, and versions.
@ -416,6 +437,13 @@ class TestGemRequirement < Gem::TestCase
"#{requirement} is satisfied by #{version}" "#{requirement} is satisfied by #{version}"
end end
# Assert that two requirement hashes are equal. Handles Gem::Requirements,
# strings, arrays, numbers, and versions.
def assert_requirement_hash_equal(expected, actual)
assert_equal req(expected).hash, req(actual).hash
end
# Refute the assumption that two requirements are equal. # Refute the assumption that two requirements are equal.
def refute_requirement_equal(unexpected, actual) def refute_requirement_equal(unexpected, actual)
@ -428,4 +456,10 @@ class TestGemRequirement < Gem::TestCase
refute req(requirement).satisfied_by?(v(version)), refute req(requirement).satisfied_by?(v(version)),
"#{requirement} is not satisfied by #{version}" "#{requirement} is not satisfied by #{version}"
end end
# Refute the assumption that two requirements hashes are equal.
def refute_requirement_hash_equal(unexpected, actual)
refute_equal req(unexpected).hash, req(actual).hash
end
end end