mirror of
https://github.com/ruby/ruby.git
synced 2026-01-27 04:24:23 +00:00
Merge RubyGems 4.0.3 and Bundler 4.0.3
This commit is contained in:
parent
ed1aac5486
commit
1c3ef27191
Notes:
git
2025-12-23 07:10:32 +00:00
@ -138,24 +138,16 @@ module Bundler
|
||||
source.local!
|
||||
|
||||
if use_exact_resolved_specifications?
|
||||
materialize(self) do |matching_specs|
|
||||
choose_compatible(matching_specs)
|
||||
spec = materialize(self) {|specs| choose_compatible(specs, fallback_to_non_installable: false) }
|
||||
return spec if spec
|
||||
|
||||
# Exact spec is incompatible; in frozen mode, try to find a compatible platform variant
|
||||
# In non-frozen mode, return nil to trigger re-resolution and lockfile update
|
||||
if Bundler.frozen_bundle?
|
||||
materialize([name, version]) {|specs| resolve_best_platform(specs) }
|
||||
end
|
||||
else
|
||||
materialize([name, version]) do |matching_specs|
|
||||
target_platform = source.is_a?(Source::Path) ? platform : Bundler.local_platform
|
||||
|
||||
installable_candidates = MatchPlatform.select_best_platform_match(matching_specs, target_platform)
|
||||
|
||||
specification = choose_compatible(installable_candidates, fallback_to_non_installable: false)
|
||||
return specification unless specification.nil?
|
||||
|
||||
if target_platform != platform
|
||||
installable_candidates = MatchPlatform.select_best_platform_match(matching_specs, platform)
|
||||
end
|
||||
|
||||
choose_compatible(installable_candidates)
|
||||
end
|
||||
materialize([name, version]) {|specs| resolve_best_platform(specs) }
|
||||
end
|
||||
end
|
||||
|
||||
@ -190,6 +182,39 @@ module Bundler
|
||||
!source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform?
|
||||
end
|
||||
|
||||
# Try platforms in order of preference until finding a compatible spec.
|
||||
# Used for legacy lockfiles and as a fallback when the exact locked spec
|
||||
# is incompatible. Falls back to frozen bundle behavior if none match.
|
||||
def resolve_best_platform(specs)
|
||||
find_compatible_platform_spec(specs) || frozen_bundle_fallback(specs)
|
||||
end
|
||||
|
||||
def find_compatible_platform_spec(specs)
|
||||
candidate_platforms.each do |plat|
|
||||
candidates = MatchPlatform.select_best_platform_match(specs, plat)
|
||||
spec = choose_compatible(candidates, fallback_to_non_installable: false)
|
||||
return spec if spec
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# Platforms to try in order of preference. Ruby platform is last since it
|
||||
# requires compilation, but works when precompiled gems are incompatible.
|
||||
def candidate_platforms
|
||||
target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
|
||||
[target, platform, Gem::Platform::RUBY].uniq
|
||||
end
|
||||
|
||||
# In frozen mode, accept any candidate. Will error at install time.
|
||||
# When target differs from locked platform, prefer locked platform's candidates
|
||||
# to preserve lockfile integrity.
|
||||
def frozen_bundle_fallback(specs)
|
||||
target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
|
||||
fallback_platform = target == platform ? target : platform
|
||||
candidates = MatchPlatform.select_best_platform_match(specs, fallback_platform)
|
||||
choose_compatible(candidates)
|
||||
end
|
||||
|
||||
def ruby_platform_materializes_to_ruby_platform?
|
||||
generic_platform = Bundler.generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
module Bundler
|
||||
VERSION = "4.0.2".freeze
|
||||
VERSION = "4.0.3".freeze
|
||||
|
||||
def self.bundler_major_version
|
||||
@bundler_major_version ||= gem_version.segments.first
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
require "rbconfig"
|
||||
|
||||
module Gem
|
||||
VERSION = "4.0.2"
|
||||
VERSION = "4.0.3"
|
||||
end
|
||||
|
||||
require_relative "rubygems/defaults"
|
||||
|
||||
@ -22,7 +22,7 @@ module Gem
|
||||
def register(target, obj)
|
||||
end
|
||||
|
||||
# This is ported over from the yaml_tree in 1.9.3
|
||||
# This is ported over from the YAMLTree implementation in Ruby 1.9.3
|
||||
def format_time(time)
|
||||
if time.utc?
|
||||
time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
|
||||
|
||||
@ -38,7 +38,7 @@ class Gem::RequestSet::Lockfile
|
||||
end
|
||||
|
||||
##
|
||||
# Creates a new Lockfile for the given +request_set+ and +gem_deps_file+
|
||||
# Creates a new Lockfile for the given Gem::RequestSet and +gem_deps_file+
|
||||
# location.
|
||||
|
||||
def self.build(request_set, gem_deps_file, dependencies = nil)
|
||||
|
||||
@ -143,7 +143,7 @@ class Gem::Security::Policy
|
||||
end
|
||||
|
||||
##
|
||||
# Ensures the root of +chain+ has a trusted certificate in +trust_dir+ and
|
||||
# Ensures the root of +chain+ has a trusted certificate in Gem::Security.trust_dir and
|
||||
# the digests of the two certificates match according to +digester+
|
||||
|
||||
def check_trust(chain, digester, trust_dir)
|
||||
|
||||
@ -102,7 +102,7 @@ class Gem::Source
|
||||
end
|
||||
|
||||
##
|
||||
# Fetches a specification for the given +name_tuple+.
|
||||
# Fetches a specification for the given Gem::NameTuple.
|
||||
|
||||
def fetch_spec(name_tuple)
|
||||
fetcher = Gem::RemoteFetcher.fetcher
|
||||
|
||||
@ -2,7 +2,17 @@
|
||||
|
||||
RSpec.describe Bundler::Plugin::Events do
|
||||
context "plugin events" do
|
||||
before { Bundler::Plugin::Events.send :reset }
|
||||
before do
|
||||
@old_constants = Bundler::Plugin::Events.constants.map {|name| [name, Bundler::Plugin::Events.const_get(name)] }
|
||||
Bundler::Plugin::Events.send :reset
|
||||
end
|
||||
|
||||
after do
|
||||
Bundler::Plugin::Events.send(:reset)
|
||||
Hash[@old_constants].each do |name, value|
|
||||
Bundler::Plugin::Events.send(:define, name, value)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#define" do
|
||||
it "raises when redefining a constant" do
|
||||
|
||||
@ -279,6 +279,7 @@ RSpec.describe Bundler::Plugin do
|
||||
s.write "plugins.rb", code
|
||||
end
|
||||
|
||||
@old_constants = Bundler::Plugin::Events.constants.map {|name| [name, Bundler::Plugin::Events.const_get(name)] }
|
||||
Bundler::Plugin::Events.send(:reset)
|
||||
Bundler::Plugin::Events.send(:define, :EVENT1, "event-1")
|
||||
Bundler::Plugin::Events.send(:define, :EVENT2, "event-2")
|
||||
@ -291,6 +292,13 @@ RSpec.describe Bundler::Plugin do
|
||||
allow(index).to receive(:load_paths).with("foo-plugin").and_return([])
|
||||
end
|
||||
|
||||
after do
|
||||
Bundler::Plugin::Events.send(:reset)
|
||||
Hash[@old_constants].each do |name, value|
|
||||
Bundler::Plugin::Events.send(:define, name, value)
|
||||
end
|
||||
end
|
||||
|
||||
let(:code) { <<-RUBY }
|
||||
Bundler::Plugin::API.hook("event-1") { puts "hook for event 1" }
|
||||
RUBY
|
||||
|
||||
25
spec/bundler/bundler/uri_normalizer_spec.rb
Normal file
25
spec/bundler/bundler/uri_normalizer_spec.rb
Normal file
@ -0,0 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe Bundler::URINormalizer do
|
||||
describe ".normalize_suffix" do
|
||||
context "when trailing_slash is true" do
|
||||
it "adds a trailing slash when missing" do
|
||||
expect(described_class.normalize_suffix("https://example.com", trailing_slash: true)).to eq("https://example.com/")
|
||||
end
|
||||
|
||||
it "keeps the trailing slash when present" do
|
||||
expect(described_class.normalize_suffix("https://example.com/", trailing_slash: true)).to eq("https://example.com/")
|
||||
end
|
||||
end
|
||||
|
||||
context "when trailing_slash is false" do
|
||||
it "removes a trailing slash when present" do
|
||||
expect(described_class.normalize_suffix("https://example.com/", trailing_slash: false)).to eq("https://example.com")
|
||||
end
|
||||
|
||||
it "keeps the value unchanged when no trailing slash exists" do
|
||||
expect(described_class.normalize_suffix("https://example.com", trailing_slash: false)).to eq("https://example.com")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -157,6 +157,11 @@ RSpec.describe "bundle install with specific platforms" do
|
||||
end
|
||||
|
||||
context "when running on a legacy lockfile locked only to ruby" do
|
||||
# Exercises the legacy lockfile path (use_exact_resolved_specifications? = false)
|
||||
# because most_specific_locked_platform is ruby, matching the generic platform.
|
||||
# Key insight: when target (arm64-darwin-22) != platform (ruby), the code tries
|
||||
# both platforms before falling back, preserving lockfile integrity.
|
||||
|
||||
around do |example|
|
||||
build_repo4 do
|
||||
build_gem "nokogiri", "1.3.10"
|
||||
@ -192,13 +197,69 @@ RSpec.describe "bundle install with specific platforms" do
|
||||
end
|
||||
|
||||
it "still installs the generic ruby variant if necessary" do
|
||||
bundle "install --verbose"
|
||||
expect(out).to include("Installing nokogiri 1.3.10")
|
||||
bundle "install"
|
||||
expect(the_bundle).to include_gem("nokogiri 1.3.10")
|
||||
expect(the_bundle).not_to include_gem("nokogiri 1.3.10 arm64-darwin")
|
||||
end
|
||||
|
||||
it "still installs the generic ruby variant if necessary, even in frozen mode" do
|
||||
bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }
|
||||
expect(out).to include("Installing nokogiri 1.3.10")
|
||||
bundle "install", env: { "BUNDLE_FROZEN" => "true" }
|
||||
expect(the_bundle).to include_gem("nokogiri 1.3.10")
|
||||
expect(the_bundle).not_to include_gem("nokogiri 1.3.10 arm64-darwin")
|
||||
end
|
||||
end
|
||||
|
||||
context "when platform-specific gem has incompatible required_ruby_version" do
|
||||
# Key insight: candidate_platforms tries [target, platform, ruby] in order.
|
||||
# Ruby platform is last since it requires compilation, but works when
|
||||
# precompiled gems are incompatible with the current Ruby version.
|
||||
#
|
||||
# Note: This fix requires the lockfile to include both ruby and platform-
|
||||
# specific variants (typical after `bundle lock --add-platform`). If the
|
||||
# lockfile only has platform-specific gems, frozen mode cannot help because
|
||||
# Bundler.setup would still expect the locked (incompatible) gem.
|
||||
|
||||
# Exercises the exact spec path (use_exact_resolved_specifications? = true)
|
||||
# because lockfile has platform-specific entry as most_specific_locked_platform
|
||||
it "falls back to ruby platform in frozen mode when lockfile includes both variants" do
|
||||
build_repo4 do
|
||||
build_gem "nokogiri", "1.18.10"
|
||||
build_gem "nokogiri", "1.18.10" do |s|
|
||||
s.platform = "x86_64-linux"
|
||||
s.required_ruby_version = "< #{Gem.ruby_version}"
|
||||
end
|
||||
end
|
||||
|
||||
gemfile <<~G
|
||||
source "https://gem.repo4"
|
||||
|
||||
gem "nokogiri"
|
||||
G
|
||||
|
||||
# Lockfile has both ruby and platform-specific gem (typical after `bundle lock --add-platform`)
|
||||
lockfile <<-L
|
||||
GEM
|
||||
remote: https://gem.repo4/
|
||||
specs:
|
||||
nokogiri (1.18.10)
|
||||
nokogiri (1.18.10-x86_64-linux)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
nokogiri
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
L
|
||||
|
||||
simulate_platform "x86_64-linux" do
|
||||
bundle "install", env: { "BUNDLE_FROZEN" => "true" }
|
||||
expect(the_bundle).to include_gem("nokogiri 1.18.10")
|
||||
expect(the_bundle).not_to include_gem("nokogiri 1.18.10 x86_64-linux")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -46,4 +46,4 @@ DEPENDENCIES
|
||||
tapioca
|
||||
|
||||
BUNDLED WITH
|
||||
4.0.2
|
||||
4.0.3
|
||||
|
||||
@ -36,4 +36,4 @@ DEPENDENCIES
|
||||
warbler!
|
||||
|
||||
BUNDLED WITH
|
||||
4.0.2
|
||||
4.0.3
|
||||
|
||||
@ -184,6 +184,7 @@ module Spec
|
||||
"spec/bundler/resolver/candidate_spec.rb",
|
||||
"spec/bundler/digest_spec.rb",
|
||||
"spec/bundler/fetcher/gem_remote_fetcher_spec.rb",
|
||||
"spec/bundler/uri_normalizer_spec.rb",
|
||||
],
|
||||
}.freeze
|
||||
end
|
||||
|
||||
@ -1610,7 +1610,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
||||
|
||||
gem_make_out = File.read(File.join(gemspec.extension_dir, "gem_make.out"))
|
||||
if vc_windows? && nmake_found?
|
||||
refute_includes(gem_make_out, " -j4")
|
||||
refute_includes(gem_make_out, "-j4")
|
||||
else
|
||||
assert_includes(gem_make_out, "make -j4")
|
||||
end
|
||||
|
||||
@ -129,4 +129,4 @@ CHECKSUMS
|
||||
turbo_tests (2.2.5) sha256=3fa31497d12976d11ccc298add29107b92bda94a90d8a0a5783f06f05102509f
|
||||
|
||||
BUNDLED WITH
|
||||
4.0.2
|
||||
4.0.3
|
||||
|
||||
@ -156,4 +156,4 @@ CHECKSUMS
|
||||
unicode-emoji (4.1.0) sha256=4997d2d5df1ed4252f4830a9b6e86f932e2013fbff2182a9ce9ccabda4f325a5
|
||||
|
||||
BUNDLED WITH
|
||||
4.0.2
|
||||
4.0.3
|
||||
|
||||
@ -176,4 +176,4 @@ CHECKSUMS
|
||||
unicode-emoji (4.1.0) sha256=4997d2d5df1ed4252f4830a9b6e86f932e2013fbff2182a9ce9ccabda4f325a5
|
||||
|
||||
BUNDLED WITH
|
||||
4.0.2
|
||||
4.0.3
|
||||
|
||||
@ -103,4 +103,4 @@ CHECKSUMS
|
||||
tilt (2.6.1) sha256=35a99bba2adf7c1e362f5b48f9b581cce4edfba98117e34696dde6d308d84770
|
||||
|
||||
BUNDLED WITH
|
||||
4.0.2
|
||||
4.0.3
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user