@@ -9,7 +9,8 @@ class LazySpecification
99 include ForcePlatform
1010
1111 attr_reader :name , :version , :platform , :materialization
12- attr_accessor :source , :remote , :force_ruby_platform , :dependencies , :required_ruby_version , :required_rubygems_version , :overrides
12+ attr_accessor :source , :remote , :force_ruby_platform , :dependencies , :required_ruby_version , :required_rubygems_version
13+ attr_accessor :overrides , :locked_platforms
1314
1415 #
1516 # For backwards compatibility with existing lockfiles, if the most specific
@@ -49,6 +50,7 @@ def initialize(name, version, platform, source = nil, **materialization_options)
4950 @force_ruby_platform = default_force_ruby_platform
5051 @most_specific_locked_platform = nil
5152 @materialization = nil
53+ @locked_platforms = nil
5254 end
5355
5456 def missing?
@@ -145,7 +147,7 @@ def materialize_for_installation
145147 # Exact spec is incompatible; in frozen mode, try to find a compatible platform variant
146148 # In non-frozen mode, return nil to trigger re-resolution and lockfile update
147149 if Bundler . frozen_bundle?
148- materialize ( [ name , version ] ) { |specs | resolve_best_platform ( specs ) }
150+ materialize ( [ name , version ] ) { |specs | resolve_best_platform ( specs , locked_platforms_only : true ) }
149151 end
150152 else
151153 materialize ( [ name , version ] ) { |specs | resolve_best_platform ( specs ) }
@@ -186,12 +188,12 @@ def use_exact_resolved_specifications?
186188 # Try platforms in order of preference until finding a compatible spec.
187189 # Used for legacy lockfiles and as a fallback when the exact locked spec
188190 # is incompatible. Falls back to frozen bundle behavior if none match.
189- def resolve_best_platform ( specs )
190- find_compatible_platform_spec ( specs ) || frozen_bundle_fallback ( specs )
191+ def resolve_best_platform ( specs , locked_platforms_only : false )
192+ find_compatible_platform_spec ( specs , locked_platforms_only : locked_platforms_only ) || frozen_bundle_fallback ( specs )
191193 end
192194
193- def find_compatible_platform_spec ( specs )
194- candidate_platforms . each do |plat |
195+ def find_compatible_platform_spec ( specs , locked_platforms_only : false )
196+ candidate_platforms ( locked_platforms_only : locked_platforms_only ) . each do |plat |
195197 candidates = MatchPlatform . select_best_platform_match ( specs , plat )
196198 spec = choose_compatible ( candidates , fallback_to_non_installable : false )
197199 return spec if spec
@@ -201,9 +203,12 @@ def find_compatible_platform_spec(specs)
201203
202204 # Platforms to try in order of preference. Ruby platform is last since it
203205 # requires compilation, but works when precompiled gems are incompatible.
204- def candidate_platforms
206+ def candidate_platforms ( locked_platforms_only : false )
205207 target = source . is_a? ( Source ::Path ) ? platform : Bundler . local_platform
206- [ target , platform , Gem ::Platform ::RUBY ] . uniq
208+ platforms = [ target , platform , Gem ::Platform ::RUBY ] . uniq
209+ return platforms unless locked_platforms_only && locked_platforms
210+
211+ platforms & locked_platforms
207212 end
208213
209214 # In frozen mode, accept any candidate. Will error at install time.
0 commit comments