Skip to content

Commit 1c3ef27

Browse files
committed
Merge RubyGems 4.0.3 and Bundler 4.0.3
1 parent ed1aac5 commit 1c3ef27

File tree

19 files changed

+164
-34
lines changed

19 files changed

+164
-34
lines changed

lib/bundler/lazy_specification.rb

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -138,24 +138,16 @@ def materialize_for_installation
138138
source.local!
139139

140140
if use_exact_resolved_specifications?
141-
materialize(self) do |matching_specs|
142-
choose_compatible(matching_specs)
143-
end
144-
else
145-
materialize([name, version]) do |matching_specs|
146-
target_platform = source.is_a?(Source::Path) ? platform : Bundler.local_platform
147-
148-
installable_candidates = MatchPlatform.select_best_platform_match(matching_specs, target_platform)
149-
150-
specification = choose_compatible(installable_candidates, fallback_to_non_installable: false)
151-
return specification unless specification.nil?
141+
spec = materialize(self) {|specs| choose_compatible(specs, fallback_to_non_installable: false) }
142+
return spec if spec
152143

153-
if target_platform != platform
154-
installable_candidates = MatchPlatform.select_best_platform_match(matching_specs, platform)
155-
end
156-
157-
choose_compatible(installable_candidates)
144+
# Exact spec is incompatible; in frozen mode, try to find a compatible platform variant
145+
# In non-frozen mode, return nil to trigger re-resolution and lockfile update
146+
if Bundler.frozen_bundle?
147+
materialize([name, version]) {|specs| resolve_best_platform(specs) }
158148
end
149+
else
150+
materialize([name, version]) {|specs| resolve_best_platform(specs) }
159151
end
160152
end
161153

@@ -190,6 +182,39 @@ def use_exact_resolved_specifications?
190182
!source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform?
191183
end
192184

185+
# Try platforms in order of preference until finding a compatible spec.
186+
# Used for legacy lockfiles and as a fallback when the exact locked spec
187+
# is incompatible. Falls back to frozen bundle behavior if none match.
188+
def resolve_best_platform(specs)
189+
find_compatible_platform_spec(specs) || frozen_bundle_fallback(specs)
190+
end
191+
192+
def find_compatible_platform_spec(specs)
193+
candidate_platforms.each do |plat|
194+
candidates = MatchPlatform.select_best_platform_match(specs, plat)
195+
spec = choose_compatible(candidates, fallback_to_non_installable: false)
196+
return spec if spec
197+
end
198+
nil
199+
end
200+
201+
# Platforms to try in order of preference. Ruby platform is last since it
202+
# requires compilation, but works when precompiled gems are incompatible.
203+
def candidate_platforms
204+
target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
205+
[target, platform, Gem::Platform::RUBY].uniq
206+
end
207+
208+
# In frozen mode, accept any candidate. Will error at install time.
209+
# When target differs from locked platform, prefer locked platform's candidates
210+
# to preserve lockfile integrity.
211+
def frozen_bundle_fallback(specs)
212+
target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
213+
fallback_platform = target == platform ? target : platform
214+
candidates = MatchPlatform.select_best_platform_match(specs, fallback_platform)
215+
choose_compatible(candidates)
216+
end
217+
193218
def ruby_platform_materializes_to_ruby_platform?
194219
generic_platform = Bundler.generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
195220

lib/bundler/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# frozen_string_literal: false
22

33
module Bundler
4-
VERSION = "4.0.2".freeze
4+
VERSION = "4.0.3".freeze
55

66
def self.bundler_major_version
77
@bundler_major_version ||= gem_version.segments.first

lib/rubygems.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
require "rbconfig"
1010

1111
module Gem
12-
VERSION = "4.0.2"
12+
VERSION = "4.0.3"
1313
end
1414

1515
require_relative "rubygems/defaults"

lib/rubygems/psych_tree.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def visit_Hash(o)
2222
def register(target, obj)
2323
end
2424

25-
# This is ported over from the yaml_tree in 1.9.3
25+
# This is ported over from the YAMLTree implementation in Ruby 1.9.3
2626
def format_time(time)
2727
if time.utc?
2828
time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")

lib/rubygems/request_set/lockfile.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def initialize(message, column, line, path)
3838
end
3939

4040
##
41-
# Creates a new Lockfile for the given +request_set+ and +gem_deps_file+
41+
# Creates a new Lockfile for the given Gem::RequestSet and +gem_deps_file+
4242
# location.
4343

4444
def self.build(request_set, gem_deps_file, dependencies = nil)

lib/rubygems/security/policy.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def check_root(chain, time)
143143
end
144144

145145
##
146-
# Ensures the root of +chain+ has a trusted certificate in +trust_dir+ and
146+
# Ensures the root of +chain+ has a trusted certificate in Gem::Security.trust_dir and
147147
# the digests of the two certificates match according to +digester+
148148

149149
def check_trust(chain, digester, trust_dir)

lib/rubygems/source.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def update_cache?
102102
end
103103

104104
##
105-
# Fetches a specification for the given +name_tuple+.
105+
# Fetches a specification for the given Gem::NameTuple.
106106

107107
def fetch_spec(name_tuple)
108108
fetcher = Gem::RemoteFetcher.fetcher

spec/bundler/bundler/plugin/events_spec.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@
22

33
RSpec.describe Bundler::Plugin::Events do
44
context "plugin events" do
5-
before { Bundler::Plugin::Events.send :reset }
5+
before do
6+
@old_constants = Bundler::Plugin::Events.constants.map {|name| [name, Bundler::Plugin::Events.const_get(name)] }
7+
Bundler::Plugin::Events.send :reset
8+
end
9+
10+
after do
11+
Bundler::Plugin::Events.send(:reset)
12+
Hash[@old_constants].each do |name, value|
13+
Bundler::Plugin::Events.send(:define, name, value)
14+
end
15+
end
616

717
describe "#define" do
818
it "raises when redefining a constant" do

spec/bundler/bundler/plugin_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@
279279
s.write "plugins.rb", code
280280
end
281281

282+
@old_constants = Bundler::Plugin::Events.constants.map {|name| [name, Bundler::Plugin::Events.const_get(name)] }
282283
Bundler::Plugin::Events.send(:reset)
283284
Bundler::Plugin::Events.send(:define, :EVENT1, "event-1")
284285
Bundler::Plugin::Events.send(:define, :EVENT2, "event-2")
@@ -291,6 +292,13 @@
291292
allow(index).to receive(:load_paths).with("foo-plugin").and_return([])
292293
end
293294

295+
after do
296+
Bundler::Plugin::Events.send(:reset)
297+
Hash[@old_constants].each do |name, value|
298+
Bundler::Plugin::Events.send(:define, name, value)
299+
end
300+
end
301+
294302
let(:code) { <<-RUBY }
295303
Bundler::Plugin::API.hook("event-1") { puts "hook for event 1" }
296304
RUBY
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe Bundler::URINormalizer do
4+
describe ".normalize_suffix" do
5+
context "when trailing_slash is true" do
6+
it "adds a trailing slash when missing" do
7+
expect(described_class.normalize_suffix("https://example.com", trailing_slash: true)).to eq("https://example.com/")
8+
end
9+
10+
it "keeps the trailing slash when present" do
11+
expect(described_class.normalize_suffix("https://example.com/", trailing_slash: true)).to eq("https://example.com/")
12+
end
13+
end
14+
15+
context "when trailing_slash is false" do
16+
it "removes a trailing slash when present" do
17+
expect(described_class.normalize_suffix("https://example.com/", trailing_slash: false)).to eq("https://example.com")
18+
end
19+
20+
it "keeps the value unchanged when no trailing slash exists" do
21+
expect(described_class.normalize_suffix("https://example.com", trailing_slash: false)).to eq("https://example.com")
22+
end
23+
end
24+
end
25+
end

0 commit comments

Comments
 (0)