diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 454b1d3d54..d9c2670d6d 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -509,7 +509,7 @@ module Bundler def resolution_packages @resolution_packages ||= begin last_resolve = converge_locked_specs - remove_ruby_from_platforms_if_necessary!(current_dependencies) + remove_invalid_platforms!(current_dependencies) packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, :locked_specs => @originally_locked_specs, :unlock => @unlock[:gems], :prerelease => gem_version_promoter.pre?) additional_base_requirements_for_resolve(packages, last_resolve) end @@ -956,17 +956,19 @@ module Bundler resolution_packages end - def remove_ruby_from_platforms_if_necessary!(dependencies) - return if Bundler.frozen_bundle? || - local_platform == Gem::Platform::RUBY || - !platforms.include?(Gem::Platform::RUBY) || - (@new_platform && platforms.last == Gem::Platform::RUBY) || + def remove_invalid_platforms!(dependencies) + return if Bundler.frozen_bundle? + + platforms.each do |platform| + next if local_platform == platform || + (@new_platform && platforms.last == platform) || @path_changes || @dependency_changes || - !@originally_locked_specs.incomplete_ruby_specs?(dependencies) + !@originally_locked_specs.incomplete_for_platform?(dependencies, platform) - remove_platform(Gem::Platform::RUBY) - add_current_platform + remove_platform(platform) + add_current_platform if platform == Gem::Platform::RUBY + end end def source_map diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index c69392d612..912ff8bf2e 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -100,12 +100,12 @@ module Bundler end end - def incomplete_ruby_specs?(deps) + def incomplete_for_platform?(deps, platform) return false if @specs.empty? @incomplete_specs = [] - self.for(deps, true, [Gem::Platform::RUBY]) + self.for(deps, true, [platform]) @incomplete_specs.any? end diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index cab53a663a..30bf50c48e 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -685,6 +685,70 @@ RSpec.describe "bundle install with specific platforms" do L end + it "automatically fixes the lockfile if multiple platforms locked, but no valid versions of direct dependencies for all of them" do + simulate_platform "x86_64-linux" do + build_repo4 do + 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 "sorbet-static", "0.5.10696" do |s| + s.platform = "x86_64-linux" + end + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + + gem "nokogiri" + gem "sorbet-static" + G + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + nokogiri (1.14.0-arm-linux) + nokogiri (1.14.0-x86_64-linux) + sorbet-static (0.5.10696-x86_64-linux) + + PLATFORMS + arm-linux + x86_64-linux + + DEPENDENCIES + nokogiri + sorbet-static + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "update" + + expect(lockfile).to eq <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + nokogiri (1.14.0-x86_64-linux) + sorbet-static (0.5.10696-x86_64-linux) + + PLATFORMS + x86_64-linux + + DEPENDENCIES + nokogiri + sorbet-static + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + it "automatically fixes the lockfile without removing other variants if it's missing platform gems, but they are installed locally" do simulate_platform "x86_64-darwin-21" do build_repo4 do