diff options
| author | David RodrÃguez <deivid.rodriguez@riseup.net> | 2023-03-17 14:18:30 +0100 |
|---|---|---|
| committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2023-11-13 11:06:10 +0900 |
| commit | 435eb56f6175b7c9a16121ec8441f7492fa9aec5 (patch) | |
| tree | 086201ded65f06c9f09d057287ce92778fe9abaf | |
| parent | 59b361aaca0194bd526e32b7053948a49da4e39d (diff) | |
[rubygems/rubygems] 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.
https://github.com/rubygems/rubygems/commit/5f24f06bc5
| -rw-r--r-- | lib/bundler/definition.rb | 15 | ||||
| -rw-r--r-- | lib/bundler/spec_set.rb | 38 | ||||
| -rw-r--r-- | spec/bundler/commands/lock_spec.rb | 11 | ||||
| -rw-r--r-- | spec/bundler/commands/update_spec.rb | 26 | ||||
| -rw-r--r-- | spec/bundler/install/gemfile/sources_spec.rb | 30 | ||||
| -rw-r--r-- | spec/bundler/install/gemfile/specific_platform_spec.rb | 136 | ||||
| -rw-r--r-- | spec/bundler/lock/lockfile_spec.rb | 2 | ||||
| -rw-r--r-- | spec/bundler/support/platforms.rb | 2 |
8 files changed, 216 insertions, 44 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 72fbae1984..9ef0abed93 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -84,7 +84,7 @@ module Bundler @new_platform = nil @removed_platform = nil - if lockfile && File.exist?(lockfile) + if lockfile_exists? @lockfile_contents = Bundler.read_file(lockfile) @locked_gems = LockfileParser.new(@lockfile_contents) @locked_platforms = @locked_gems.platforms @@ -302,6 +302,10 @@ module Bundler end end + def should_complete_platforms? + !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform] + end + def spec_git_paths sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact end @@ -491,6 +495,10 @@ module Bundler private + def lockfile_exists? + lockfile && File.exist?(lockfile) + end + def resolver @resolver ||= Resolver.new(resolution_packages, gem_version_promoter) end @@ -567,11 +575,12 @@ module Bundler end def start_resolution - result = resolver.start + result = SpecSet.new(resolver.start) @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version + @platforms = result.complete_platforms!(platforms) if should_complete_platforms? - SpecSet.new(SpecSet.new(result).for(dependencies, false, @platforms)) + SpecSet.new(result.for(dependencies, false, @platforms)) end def precompute_source_requirements_for_indirect_dependencies? diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 277824c34f..f4fc005ef2 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -52,6 +52,44 @@ module Bundler specs.uniq end + def complete_platforms!(platforms) + return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty? + + new_platforms = @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq.select do |platform| + next if platforms.include?(platform) + next unless GemHelpers.generic(platform) == Gem::Platform::RUBY + + new_specs = [] + + valid_platform = lookup.all? do |_, specs| + spec = specs.first + matching_specs = spec.source.specs.search([spec.name, spec.version]) + platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).first + + if platform_spec + new_specs << LazySpecification.from_spec(platform_spec) + true + else + false + end + end + next unless valid_platform + + @specs.concat(new_specs.uniq) + end + return platforms if new_platforms.empty? + + platforms.concat(new_platforms) + + less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && platform === Bundler.local_platform } + platforms.delete(Bundler.local_platform) if less_specific_platform + + @sorted = nil + @lookup = nil + + platforms + end + def [](key) key = key.name if key.respond_to?(:name) lookup[key].reverse diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index ac220c9318..5c6a2c0e3d 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -733,7 +733,7 @@ RSpec.describe "bundle lock" do gem "libv8" G - simulate_platform(Gem::Platform.new("x86_64-darwin")) { bundle "lock" } + simulate_platform(Gem::Platform.new("x86_64-darwin-19")) { bundle "lock" } expect(lockfile).to eq <<~G GEM @@ -743,7 +743,8 @@ RSpec.describe "bundle lock" do libv8 (8.4.255.0-x86_64-darwin-20) PLATFORMS - x86_64-darwin + x86_64-darwin-19 + x86_64-darwin-20 DEPENDENCIES libv8 @@ -1237,7 +1238,7 @@ RSpec.describe "bundle lock" do activemodel (>= 6.0.4) PLATFORMS - #{lockfile_platforms} + #{local_platform} DEPENDENCIES activeadmin (= 2.13.1) @@ -1273,7 +1274,7 @@ RSpec.describe "bundle lock" do version solving has failed. ERR - lockfile lockfile.gsub(/PLATFORMS\n #{lockfile_platforms}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}") + lockfile lockfile.gsub(/PLATFORMS\n #{local_platform}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}") bundle "lock", :raise_on_error => false @@ -1438,7 +1439,7 @@ RSpec.describe "bundle lock" do nokogiri (1.14.2) PLATFORMS - x86_64-linux + #{lockfile_platforms} DEPENDENCIES foo! diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 8e48758c04..5c7b569fe2 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -559,12 +559,36 @@ RSpec.describe "bundle update" do before do build_repo2 - install_gemfile <<-G + gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "activesupport" gem "rack-obama" gem "platform_specific" G + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo2)}/ + specs: + activesupport (2.3.5) + platform_specific (1.0-#{local_platform}) + rack (1.0.0) + rack-obama (1.0) + rack + + PLATFORMS + #{local_platform} + + DEPENDENCIES + activesupport + platform_specific + rack-obama + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "install" end it "doesn't hit repo2" do diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 64eed1a2f4..15ff15e46d 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -379,7 +379,7 @@ RSpec.describe "bundle install with gems on multiple sources" do rack PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES depends_on_rack! @@ -422,7 +422,7 @@ RSpec.describe "bundle install with gems on multiple sources" do rack PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES depends_on_rack! @@ -803,7 +803,7 @@ RSpec.describe "bundle install with gems on multiple sources" do zeitwerk (2.4.2) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES activesupport @@ -874,7 +874,7 @@ RSpec.describe "bundle install with gems on multiple sources" do sidekiq (>= 6.1.0) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES activesupport @@ -975,7 +975,7 @@ RSpec.describe "bundle install with gems on multiple sources" do sidekiq (>= 6.1.0) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES activesupport @@ -1049,7 +1049,7 @@ RSpec.describe "bundle install with gems on multiple sources" do sidekiq (>= 6.1.0) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES activesupport @@ -1146,7 +1146,7 @@ RSpec.describe "bundle install with gems on multiple sources" do nokogiri (>= 1.2.3) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES handsoap! @@ -1209,7 +1209,7 @@ RSpec.describe "bundle install with gems on multiple sources" do rack (0.9.1) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES rack! @@ -1239,7 +1239,7 @@ RSpec.describe "bundle install with gems on multiple sources" do rack (0.9.1) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES rack! @@ -1261,7 +1261,7 @@ RSpec.describe "bundle install with gems on multiple sources" do rack (0.9.1) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES rack! @@ -1701,7 +1701,7 @@ RSpec.describe "bundle install with gems on multiple sources" do mime-types (3.3.1) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES capybara (~> 2.5.0) @@ -1732,7 +1732,7 @@ RSpec.describe "bundle install with gems on multiple sources" do mime-types (3.0.0) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES capybara (~> 2.5.0) @@ -1789,7 +1789,7 @@ RSpec.describe "bundle install with gems on multiple sources" do pdf-writer (= 1.1.8) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES ruport (= 1.7.0.3)! @@ -1851,7 +1851,7 @@ RSpec.describe "bundle install with gems on multiple sources" do pdf-writer (= 1.1.8) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES ruport (= 1.7.0.3)! @@ -1899,7 +1899,7 @@ RSpec.describe "bundle install with gems on multiple sources" do pdf-writer (1.1.8) PLATFORMS - #{local_platform} + #{lockfile_platforms} DEPENDENCIES pdf-writer (= 1.1.8) diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index 099ef35bbf..0c9816eaac 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -11,11 +11,11 @@ RSpec.describe "bundle install with specific platforms" do setup_multiplatform_gem install_gemfile(google_protobuf) allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) - expect(the_bundle.locked_gems.platforms).to eq([pl("x86_64-darwin-15")]) + expect(the_bundle.locked_gems.platforms).to include(pl("x86_64-darwin-15")) expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin") - expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ - google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin - ]) + expect(the_bundle.locked_gems.specs.map(&:full_name)).to include( + "google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin" + ) end end @@ -309,10 +309,10 @@ RSpec.describe "bundle install with specific platforms" do G allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) - expect(the_bundle.locked_gems.platforms).to eq([pl("x86_64-darwin-15")]) + expect(the_bundle.locked_gems.platforms).to include(pl("x86_64-darwin-15")) expect(the_bundle).to include_gems("facter 2.4.6 universal-darwin", "CFPropertyList 1.0") - expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(["CFPropertyList-1.0", - "facter-2.4.6-universal-darwin"]) + expect(the_bundle.locked_gems.specs.map(&:full_name)).to include("CFPropertyList-1.0", + "facter-2.4.6-universal-darwin") end end @@ -327,8 +327,8 @@ RSpec.describe "bundle install with specific platforms" do install_gemfile(google_protobuf) bundle "lock --add-platform=#{x64_mingw32}" - expect(the_bundle.locked_gems.platforms).to eq([x64_mingw32, pl("x86_64-darwin-15")]) - expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ + expect(the_bundle.locked_gems.platforms).to include(x64_mingw32, pl("x86_64-darwin-15")) + expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(*%w[ google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32 ]) @@ -341,11 +341,11 @@ RSpec.describe "bundle install with specific platforms" do install_gemfile(google_protobuf) bundle "lock --add-platform=#{java}" - expect(the_bundle.locked_gems.platforms).to eq([java, pl("x86_64-darwin-15")]) - expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ - google-protobuf-3.0.0.alpha.5.0.5.1 - google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin - ]) + expect(the_bundle.locked_gems.platforms).to include(java, pl("x86_64-darwin-15")) + expect(the_bundle.locked_gems.specs.map(&:full_name)).to include( + "google-protobuf-3.0.0.alpha.5.0.5.1", + "google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin" + ) end end end @@ -517,7 +517,7 @@ RSpec.describe "bundle install with specific platforms" do sorbet-runtime (= 0.5.10160) PLATFORMS - #{lockfile_platforms("ruby")} + #{lockfile_platforms} DEPENDENCIES sorbet-static-and-runtime @@ -548,7 +548,7 @@ RSpec.describe "bundle install with specific platforms" do sorbet-runtime (= 0.5.10160) PLATFORMS - #{lockfile_platforms} + #{local_platform} DEPENDENCIES sorbet-static-and-runtime @@ -601,7 +601,7 @@ RSpec.describe "bundle install with specific platforms" do DEPENDENCIES nokogiri - sorbet + sorbet-static BUNDLED WITH #{Bundler::VERSION} @@ -702,7 +702,7 @@ RSpec.describe "bundle install with specific platforms" do sorbet-runtime (= 0.5.10160) PLATFORMS - #{lockfile_platforms} + #{local_platform} DEPENDENCIES sorbet-static-and-runtime @@ -1067,6 +1067,106 @@ RSpec.describe "bundle install with specific platforms" do end end + it "locks specific platforms automatically" do + simulate_platform "x86_64-linux" do + build_repo4 do + build_gem "nokogiri", "1.14.0" + build_gem "nokogiri", "1.14.0" do |s| + s.platform = "x86_64-linux" + end + build_gem "nokogiri", "1.14.0" do |s| + s.platform = "arm-linux" + end + build_gem "nokogiri", "1.14.0" do |s| + s.platform = "x64-mingw32" + end + build_gem "nokogiri", "1.14.0" do |s| + s.platform = "java" + end + + build_gem "sorbet-static", "0.5.10696" do |s| + s.platform = "x86_64-linux" + end + build_gem "sorbet-static", "0.5.10696" do |s| + s.platform = "universal-darwin-22" + end + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + + gem "nokogiri" + G + + bundle "lock" + + # locks all compatible platforms, excluding Java and Windows + expect(lockfile).to eq(<<~L) + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + nokogiri (1.14.0) + nokogiri (1.14.0-arm-linux) + nokogiri (1.14.0-x86_64-linux) + + PLATFORMS + arm-linux + ruby + x86_64-linux + + DEPENDENCIES + nokogiri + + CHECKSUMS + #{gem_no_checksum "nokogiri", "1.14.0"} + #{gem_no_checksum "nokogiri", "1.14.0", "arm-linux"} + #{gem_no_checksum "nokogiri", "1.14.0", "x86_64-linux"} + + BUNDLED WITH + #{Bundler::VERSION} + L + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + + gem "nokogiri" + gem "sorbet-static" + G + + FileUtils.rm bundled_app_lock + + bundle "lock" + + # locks only platforms compatible with all gems in the bundle + expect(lockfile).to eq(<<~L) + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + nokogiri (1.14.0) + nokogiri (1.14.0-x86_64-linux) + sorbet-static (0.5.10696-universal-darwin-22) + sorbet-static (0.5.10696-x86_64-linux) + + PLATFORMS + universal-darwin-22 + x86_64-linux + + DEPENDENCIES + nokogiri + sorbet-static + + CHECKSUMS + #{gem_no_checksum "nokogiri", "1.14.0"} + #{gem_no_checksum "nokogiri", "1.14.0", "x86_64-linux"} + #{gem_no_checksum "sorbet-static", "0.5.10696", "universal-darwin-22"} + #{gem_no_checksum "sorbet-static", "0.5.10696", "x86_64-linux"} + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + private def setup_multiplatform_gem diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb index be1fdc37b5..efa5b85788 100644 --- a/spec/bundler/lock/lockfile_spec.rb +++ b/spec/bundler/lock/lockfile_spec.rb @@ -1212,7 +1212,7 @@ RSpec.describe "the lockfile format" do rack (1.0.0) PLATFORMS - #{lockfile_platforms("java")} + #{lockfile_platforms("java", local_platform, :defaults => [])} DEPENDENCIES rack diff --git a/spec/bundler/support/platforms.rb b/spec/bundler/support/platforms.rb index 973d34a43a..3289d5e8e2 100644 --- a/spec/bundler/support/platforms.rb +++ b/spec/bundler/support/platforms.rb @@ -105,7 +105,7 @@ module Spec end def default_locked_platforms - [local_platform] + [local_platform, generic_local_platform] end end end |
