lib/bundler/patch/conservative_resolver.rb in bundler-patch-0.6.1 vs lib/bundler/patch/conservative_resolver.rb in bundler-patch-0.7.0
- old
+ new
@@ -1,39 +1,33 @@
module Bundler::Patch
class ConservativeResolver < Bundler::Resolver
- attr_accessor :locked_specs, :gems_to_update, :strict, :minor_allowed
+ attr_accessor :locked_specs, :gems_to_update, :strict, :minor_preferred, :prefer_minimal
def search_for(dependency)
res = super(dependency)
dep = dependency.dep unless dependency.is_a? Gem::Dependency
+
@conservative_search_for ||= {}
- #@conservative_search_for[dep] ||= # TODO turning off caching allowed a real-world sample to work, dunno why yet.
- begin
+ res = @conservative_search_for[dep] ||= begin
gem_name = dep.name
# An Array per version returned, different entries for different platforms.
# We just need the version here so it's ok to hard code this to the first instance.
locked_spec = @locked_specs[gem_name].first
(@strict ?
filter_specs(res, locked_spec) :
sort_specs(res, locked_spec)).tap do |res|
- if ENV['DEBUG_PATCH_RESOLVER']
- # TODO: if we keep this, gotta go through Bundler.ui
- begin
- if res
- p debug_format_result(dep, res)
- else
- p "No res for #{dep.to_s}. Orig res: #{super(dependency)}"
- end
- rescue => e
- p [e.message, e.backtrace[0..5]]
- end
- end
+ STDERR.puts debug_format_result(dep, res).inspect if ENV['DEBUG_PATCH_RESOLVER']
end
end
+
+ # dup is important, in weird (large) cases Bundler will empty the result array corrupting the cache.
+ # Bundler itself doesn't have this problem because the super search_for does a select on its cached
+ # search results, effectively duping it.
+ res.dup
end
def debug_format_result(dep, res)
a = [dep.to_s,
res.map { |sg| [sg.version, sg.dependencies_for_activated_platforms.map { |dp| [dp.name, dp.requirement.to_s] }] }]
@@ -48,11 +42,11 @@
if locked_spec
gsv = gem_spec.version
lsv = locked_spec.version
- must_match = @minor_allowed ? [0] : [0, 1]
+ must_match = @minor_preferred ? [0] : [0, 1]
matches = must_match.map { |idx| gsv.segments[idx] == lsv.segments[idx] }
(matches.uniq == [true]) ? gsv.send(:>=, lsv) : false
else
true
@@ -60,46 +54,49 @@
end
sort_specs(res, locked_spec)
end
+ # reminder: sort still filters anything older than locked version
def sort_specs(specs, locked_spec)
return specs unless locked_spec
gem_name = locked_spec.name
locked_version = locked_spec.version
filtered = specs.select { |s| s.first.version >= locked_version }
filtered.sort do |a, b|
a_ver = a.first.version
b_ver = b.first.version
+ gem_patch = @gems_to_update.gem_patch_for(gem_name)
+ new_version = gem_patch ? gem_patch.new_version : nil
case
when a_ver.segments[0] != b_ver.segments[0]
b_ver <=> a_ver
- when !@minor_allowed && (a_ver.segments[1] != b_ver.segments[1])
+ when !@minor_preferred && (a_ver.segments[1] != b_ver.segments[1])
b_ver <=> a_ver
- when @gems_to_update.patching_but_not_this_gem?(gem_name)
+ when @prefer_minimal && !@gems_to_update.unlocking_gem?(gem_name)
b_ver <=> a_ver
+ when @prefer_minimal && @gems_to_update.unlocking_gem?(gem_name) &&
+ (![a_ver, b_ver].include?(locked_version) &&
+ (!new_version || (new_version && a_ver >= new_version && b_ver >= new_version)))
+ b_ver <=> a_ver
else
a_ver <=> b_ver
end
end.tap do |result|
if @gems_to_update.unlocking_gem?(gem_name)
- if @gems_to_update.patching_gem?(gem_name)
- # this logic will keep a gem from updating past the patched version
- # if a more recent release (or minor, if enabled) version exists.
- # TODO: not sure if we want this special logic to remain or not.
- new_version = @gems_to_update.gem_patch_for(gem_name).new_version
- swap_version_to_end(specs, new_version, result) if new_version
+ gem_patch = @gems_to_update.gem_patch_for(gem_name)
+ if gem_patch && gem_patch.new_version && @prefer_minimal
+ move_version_to_end(specs, gem_patch.new_version, result)
end
else
- # make sure the current locked version is last in list.
- swap_version_to_end(specs, locked_version, result)
+ move_version_to_end(specs, locked_version, result)
end
end
end
- def swap_version_to_end(specs, version, result)
+ def move_version_to_end(specs, version, result)
spec_group = specs.detect { |s| s.first.version.to_s == version.to_s }
if spec_group
result.reject! { |s| s.first.version.to_s === version.to_s }
result << spec_group
end