Skip to content

Commit 0bdf970

Browse files
Automatically lock extra ruby platforms
Since we started locking the specific platform in the lockfile, that has created an annoying situation for users that don't develop on Linux. They will create a lockfile on their machines, locking their local platform, for example, darwin. But then that lockfile won't work automatically when deploying to Heroku for example, because the lockfile is frozen and the Linux platform is not included. There's the chance though that resolving against two platforms (Linux + the local platform) won't succeed while resolving for just the current platform will. So, instead, we check other platform specific variants available for the resolution we initially found, and lock those platforms and specs too if they satisfy the resolution. This is only done when generating new lockfiles from scratch, existing lockfiles should keep working as before, and it's only done for "ruby platforms", i.e., not Java or Windows which have their own complexities, and so are excluded. With this change, we expect that MacOS users can bundle locally and deploy to Heroku without needing to do anything special.
1 parent ec58eda commit 0bdf970

File tree

8 files changed

+216
-44
lines changed

8 files changed

+216
-44
lines changed

bundler/lib/bundler/definition.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti
8484
@new_platform = nil
8585
@removed_platform = nil
8686

87-
if lockfile && File.exist?(lockfile)
87+
if lockfile_exists?
8888
@lockfile_contents = Bundler.read_file(lockfile)
8989
@locked_gems = LockfileParser.new(@lockfile_contents)
9090
@locked_platforms = @locked_gems.platforms
@@ -302,6 +302,10 @@ def resolve
302302
end
303303
end
304304

305+
def should_complete_platforms?
306+
!lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
307+
end
308+
305309
def spec_git_paths
306310
sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact
307311
end
@@ -491,6 +495,10 @@ def unlocking?
491495

492496
private
493497

498+
def lockfile_exists?
499+
lockfile && File.exist?(lockfile)
500+
end
501+
494502
def resolver
495503
@resolver ||= Resolver.new(resolution_packages, gem_version_promoter)
496504
end
@@ -567,11 +575,12 @@ def materialize(dependencies)
567575
end
568576

569577
def start_resolution
570-
result = resolver.start
578+
result = SpecSet.new(resolver.start)
571579

572580
@resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
581+
@platforms = result.complete_platforms!(platforms) if should_complete_platforms?
573582

574-
SpecSet.new(SpecSet.new(result).for(dependencies, false, @platforms))
583+
SpecSet.new(result.for(dependencies, false, @platforms))
575584
end
576585

577586
def precompute_source_requirements_for_indirect_dependencies?

bundler/lib/bundler/spec_set.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,44 @@ def for(dependencies, check = false, platforms = [nil])
5252
specs.uniq
5353
end
5454

55+
def complete_platforms!(platforms)
56+
return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty?
57+
58+
new_platforms = @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq.select do |platform|
59+
next if platforms.include?(platform)
60+
next unless GemHelpers.generic(platform) == Gem::Platform::RUBY
61+
62+
new_specs = []
63+
64+
valid_platform = lookup.all? do |_, specs|
65+
spec = specs.first
66+
matching_specs = spec.source.specs.search([spec.name, spec.version])
67+
platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).first
68+
69+
if platform_spec
70+
new_specs << LazySpecification.from_spec(platform_spec)
71+
true
72+
else
73+
false
74+
end
75+
end
76+
next unless valid_platform
77+
78+
@specs.concat(new_specs.uniq)
79+
end
80+
return platforms if new_platforms.empty?
81+
82+
platforms.concat(new_platforms)
83+
84+
less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && platform === Bundler.local_platform }
85+
platforms.delete(Bundler.local_platform) if less_specific_platform
86+
87+
@sorted = nil
88+
@lookup = nil
89+
90+
platforms
91+
end
92+
5593
def [](key)
5694
key = key.name if key.respond_to?(:name)
5795
lookup[key].reverse

bundler/spec/commands/lock_spec.rb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@
733733
gem "libv8"
734734
G
735735

736-
simulate_platform(Gem::Platform.new("x86_64-darwin")) { bundle "lock" }
736+
simulate_platform(Gem::Platform.new("x86_64-darwin-19")) { bundle "lock" }
737737

738738
expect(lockfile).to eq <<~G
739739
GEM
@@ -743,7 +743,8 @@
743743
libv8 (8.4.255.0-x86_64-darwin-20)
744744
745745
PLATFORMS
746-
x86_64-darwin
746+
x86_64-darwin-19
747+
x86_64-darwin-20
747748
748749
DEPENDENCIES
749750
libv8
@@ -1237,7 +1238,7 @@
12371238
activemodel (>= 6.0.4)
12381239
12391240
PLATFORMS
1240-
#{lockfile_platforms}
1241+
#{local_platform}
12411242
12421243
DEPENDENCIES
12431244
activeadmin (= 2.13.1)
@@ -1273,7 +1274,7 @@
12731274
version solving has failed.
12741275
ERR
12751276

1276-
lockfile lockfile.gsub(/PLATFORMS\n #{lockfile_platforms}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}")
1277+
lockfile lockfile.gsub(/PLATFORMS\n #{local_platform}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}")
12771278

12781279
bundle "lock", :raise_on_error => false
12791280

@@ -1438,7 +1439,7 @@
14381439
nokogiri (1.14.2)
14391440
14401441
PLATFORMS
1441-
x86_64-linux
1442+
#{lockfile_platforms}
14421443
14431444
DEPENDENCIES
14441445
foo!

bundler/spec/commands/update_spec.rb

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,12 +559,36 @@
559559
before do
560560
build_repo2
561561

562-
install_gemfile <<-G
562+
gemfile <<-G
563563
source "#{file_uri_for(gem_repo2)}"
564564
gem "activesupport"
565565
gem "rack-obama"
566566
gem "platform_specific"
567567
G
568+
569+
lockfile <<~L
570+
GEM
571+
remote: #{file_uri_for(gem_repo2)}/
572+
specs:
573+
activesupport (2.3.5)
574+
platform_specific (1.0-#{local_platform})
575+
rack (1.0.0)
576+
rack-obama (1.0)
577+
rack
578+
579+
PLATFORMS
580+
#{local_platform}
581+
582+
DEPENDENCIES
583+
activesupport
584+
platform_specific
585+
rack-obama
586+
587+
BUNDLED WITH
588+
#{Bundler::VERSION}
589+
L
590+
591+
bundle "install"
568592
end
569593

570594
it "doesn't hit repo2" do

bundler/spec/install/gemfile/sources_spec.rb

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@
379379
rack
380380
381381
PLATFORMS
382-
#{local_platform}
382+
#{lockfile_platforms}
383383
384384
DEPENDENCIES
385385
depends_on_rack!
@@ -422,7 +422,7 @@
422422
rack
423423
424424
PLATFORMS
425-
#{local_platform}
425+
#{lockfile_platforms}
426426
427427
DEPENDENCIES
428428
depends_on_rack!
@@ -803,7 +803,7 @@
803803
zeitwerk (2.4.2)
804804
805805
PLATFORMS
806-
#{local_platform}
806+
#{lockfile_platforms}
807807
808808
DEPENDENCIES
809809
activesupport
@@ -874,7 +874,7 @@
874874
sidekiq (>= 6.1.0)
875875
876876
PLATFORMS
877-
#{local_platform}
877+
#{lockfile_platforms}
878878
879879
DEPENDENCIES
880880
activesupport
@@ -975,7 +975,7 @@
975975
sidekiq (>= 6.1.0)
976976
977977
PLATFORMS
978-
#{local_platform}
978+
#{lockfile_platforms}
979979
980980
DEPENDENCIES
981981
activesupport
@@ -1049,7 +1049,7 @@
10491049
sidekiq (>= 6.1.0)
10501050
10511051
PLATFORMS
1052-
#{local_platform}
1052+
#{lockfile_platforms}
10531053
10541054
DEPENDENCIES
10551055
activesupport
@@ -1146,7 +1146,7 @@
11461146
nokogiri (>= 1.2.3)
11471147
11481148
PLATFORMS
1149-
#{local_platform}
1149+
#{lockfile_platforms}
11501150
11511151
DEPENDENCIES
11521152
handsoap!
@@ -1209,7 +1209,7 @@
12091209
rack (0.9.1)
12101210
12111211
PLATFORMS
1212-
#{local_platform}
1212+
#{lockfile_platforms}
12131213
12141214
DEPENDENCIES
12151215
rack!
@@ -1239,7 +1239,7 @@
12391239
rack (0.9.1)
12401240
12411241
PLATFORMS
1242-
#{local_platform}
1242+
#{lockfile_platforms}
12431243
12441244
DEPENDENCIES
12451245
rack!
@@ -1261,7 +1261,7 @@
12611261
rack (0.9.1)
12621262
12631263
PLATFORMS
1264-
#{local_platform}
1264+
#{lockfile_platforms}
12651265
12661266
DEPENDENCIES
12671267
rack!
@@ -1701,7 +1701,7 @@
17011701
mime-types (3.3.1)
17021702
17031703
PLATFORMS
1704-
#{local_platform}
1704+
#{lockfile_platforms}
17051705
17061706
DEPENDENCIES
17071707
capybara (~> 2.5.0)
@@ -1732,7 +1732,7 @@
17321732
mime-types (3.0.0)
17331733
17341734
PLATFORMS
1735-
#{local_platform}
1735+
#{lockfile_platforms}
17361736
17371737
DEPENDENCIES
17381738
capybara (~> 2.5.0)
@@ -1789,7 +1789,7 @@
17891789
pdf-writer (= 1.1.8)
17901790
17911791
PLATFORMS
1792-
#{local_platform}
1792+
#{lockfile_platforms}
17931793
17941794
DEPENDENCIES
17951795
ruport (= 1.7.0.3)!
@@ -1851,7 +1851,7 @@
18511851
pdf-writer (= 1.1.8)
18521852
18531853
PLATFORMS
1854-
#{local_platform}
1854+
#{lockfile_platforms}
18551855
18561856
DEPENDENCIES
18571857
ruport (= 1.7.0.3)!
@@ -1899,7 +1899,7 @@
18991899
pdf-writer (1.1.8)
19001900
19011901
PLATFORMS
1902-
#{local_platform}
1902+
#{lockfile_platforms}
19031903
19041904
DEPENDENCIES
19051905
pdf-writer (= 1.1.8)

0 commit comments

Comments
 (0)