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