@@ -13,7 +13,6 @@ def initialize(name, version, platform, source = nil)
1313 @dependencies = [ ]
1414 @platform = platform || Gem ::Platform ::RUBY
1515 @source = source
16- @specification = nil
1716 end
1817
1918 def full_name
@@ -76,37 +75,46 @@ def to_lock
7675 def materialize_for_installation
7776 source . local!
7877
79- candidates = if source . is_a? ( Source :: Path ) || ! ruby_platform_materializes_to_ruby_platform?
80- target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : local_platform
78+ matching_specs = source . specs . search ( use_exact_resolved_specifications? ? self : [ name , version ] )
79+ return self if matching_specs . empty?
8180
82- GemHelpers . select_best_platform_match ( source . specs . search ( Dependency . new ( name , version ) ) , target_platform )
81+ candidates = if use_exact_resolved_specifications?
82+ matching_specs
8383 else
84- source . specs . search ( self )
85- end
84+ target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : local_platform
8685
87- return self if candidates . empty?
86+ installable_candidates = GemHelpers . select_best_platform_match ( matching_specs , target_platform )
8887
89- __materialize__ ( candidates )
90- end
88+ specification = __materialize__ ( installable_candidates , :fallback_to_non_installable => false )
89+ return specification unless specification . nil?
9190
92- def __materialize__ ( candidates )
93- @specification = begin
94- search = candidates . reverse . find do |spec |
95- spec . is_a? ( StubSpecification ) ||
96- ( spec . matches_current_ruby? &&
97- spec . matches_current_rubygems? )
98- end
99- if search . nil? && Bundler . frozen_bundle?
100- search = candidates . last
101- else
102- search . dependencies = dependencies if search && search . full_name == full_name && ( search . is_a? ( RemoteSpecification ) || search . is_a? ( EndpointSpecification ) )
91+ if target_platform != platform
92+ installable_candidates = GemHelpers . select_best_platform_match ( matching_specs , platform )
10393 end
104- search
94+
95+ installable_candidates
10596 end
97+
98+ __materialize__ ( candidates )
10699 end
107100
108- def respond_to? ( *args )
109- super || @specification ? @specification . respond_to? ( *args ) : nil
101+ # If in frozen mode, we fallback to a non-installable candidate because by
102+ # doing this we avoid re-resolving and potentially end up changing the
103+ # lock file, which is not allowed. In that case, we will give a proper error
104+ # about the mismatch higher up the stack, right before trying to install the
105+ # bad gem.
106+ def __materialize__ ( candidates , fallback_to_non_installable : Bundler . frozen_bundle? )
107+ search = candidates . reverse . find do |spec |
108+ spec . is_a? ( StubSpecification ) ||
109+ ( spec . matches_current_ruby? &&
110+ spec . matches_current_rubygems? )
111+ end
112+ if search . nil? && fallback_to_non_installable
113+ search = candidates . last
114+ else
115+ search . dependencies = dependencies if search && search . full_name == full_name && ( search . is_a? ( RemoteSpecification ) || search . is_a? ( EndpointSpecification ) )
116+ end
117+ search
110118 end
111119
112120 def to_s
@@ -128,16 +136,8 @@ def git_version
128136
129137 private
130138
131- def to_ary
132- nil
133- end
134-
135- def method_missing ( method , *args , &blk )
136- raise "LazySpecification has not been materialized yet (calling :#{ method } #{ args . inspect } )" unless @specification
137-
138- return super unless respond_to? ( method )
139-
140- @specification . send ( method , *args , &blk )
139+ def use_exact_resolved_specifications?
140+ @use_exact_resolved_specifications ||= !source . is_a? ( Source ::Path ) && ruby_platform_materializes_to_ruby_platform?
141141 end
142142
143143 #
0 commit comments