diff options
Diffstat (limited to 'lib/bundler/gem_version_promoter.rb')
-rw-r--r-- | lib/bundler/gem_version_promoter.rb | 176 |
1 files changed, 0 insertions, 176 deletions
diff --git a/lib/bundler/gem_version_promoter.rb b/lib/bundler/gem_version_promoter.rb deleted file mode 100644 index 52b5386045..0000000000 --- a/lib/bundler/gem_version_promoter.rb +++ /dev/null @@ -1,176 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # This class contains all of the logic for determining the next version of a - # Gem to update to based on the requested level (patch, minor, major). - # Primarily designed to work with Resolver which will provide it the list of - # available dependency versions as found in its index, before returning it to - # to the resolution engine to select the best version. - class GemVersionPromoter - attr_reader :level, :locked_specs, :unlock_gems - - # By default, strict is false, meaning every available version of a gem - # is returned from sort_versions. The order gives preference to the - # requested level (:patch, :minor, :major) but in complicated requirement - # cases some gems will by necessity by promoted past the requested level, - # or even reverted to older versions. - # - # If strict is set to true, the results from sort_versions will be - # truncated, eliminating any version outside the current level scope. - # This can lead to unexpected outcomes or even VersionConflict exceptions - # that report a version of a gem not existing for versions that indeed do - # existing in the referenced source. - attr_accessor :strict - - # Given a list of locked_specs and a list of gems to unlock creates a - # GemVersionPromoter instance. - # - # @param locked_specs [SpecSet] All current locked specs. Unlike Definition - # where this list is empty if all gems are being updated, this should - # always be populated for all gems so this class can properly function. - # @param unlock_gems [String] List of gem names being unlocked. If empty, - # all gems will be considered unlocked. - # @return [GemVersionPromoter] - def initialize(locked_specs = SpecSet.new([]), unlock_gems = []) - @level = :major - @strict = false - @locked_specs = locked_specs - @unlock_gems = unlock_gems - @sort_versions = {} - end - - # @param value [Symbol] One of three Symbols: :major, :minor or :patch. - def level=(value) - v = case value - when String, Symbol - value.to_sym - end - - raise ArgumentError, "Unexpected level #{v}. Must be :major, :minor or :patch" unless [:major, :minor, :patch].include?(v) - @level = v - end - - # Given a Dependency and an Array of SpecGroups of available versions for a - # gem, this method will return the Array of SpecGroups sorted (and possibly - # truncated if strict is true) in an order to give preference to the current - # level (:major, :minor or :patch) when resolution is deciding what versions - # best resolve all dependencies in the bundle. - # @param dep [Dependency] The Dependency of the gem. - # @param spec_groups [SpecGroup] An array of SpecGroups for the same gem - # named in the @dep param. - # @return [SpecGroup] A new instance of the SpecGroup Array sorted and - # possibly filtered. - def sort_versions(dep, spec_groups) - before_result = "before sort_versions: #{debug_format_result(dep, spec_groups).inspect}" if ENV["DEBUG_RESOLVER"] - - @sort_versions[dep] ||= begin - gem_name = dep.name - - # An Array per version returned, different entries for different platforms. - # We only need the version here so it's ok to hard code this to the first instance. - locked_spec = locked_specs[gem_name].first - - if strict - filter_dep_specs(spec_groups, locked_spec) - else - sort_dep_specs(spec_groups, locked_spec) - end.tap do |specs| - if ENV["DEBUG_RESOLVER"] - STDERR.puts before_result - STDERR.puts " after sort_versions: #{debug_format_result(dep, specs).inspect}" - end - end - end - end - - # @return [bool] Convenience method for testing value of level variable. - def major? - level == :major - end - - # @return [bool] Convenience method for testing value of level variable. - def minor? - level == :minor - end - - private - - def filter_dep_specs(spec_groups, locked_spec) - res = spec_groups.select do |spec_group| - if locked_spec && !major? - gsv = spec_group.version - lsv = locked_spec.version - - must_match = minor? ? [0] : [0, 1] - - matches = must_match.map {|idx| gsv.segments[idx] == lsv.segments[idx] } - (matches.uniq == [true]) ? (gsv >= lsv) : false - else - true - end - end - - sort_dep_specs(res, locked_spec) - end - - def sort_dep_specs(spec_groups, locked_spec) - return spec_groups unless locked_spec - @gem_name = locked_spec.name - @locked_version = locked_spec.version - - result = spec_groups.sort do |a, b| - @a_ver = a.version - @b_ver = b.version - if major? - @a_ver <=> @b_ver - elsif either_version_older_than_locked - @a_ver <=> @b_ver - elsif segments_do_not_match(:major) - @b_ver <=> @a_ver - elsif !minor? && segments_do_not_match(:minor) - @b_ver <=> @a_ver - else - @a_ver <=> @b_ver - end - end - post_sort(result) - end - - def either_version_older_than_locked - @a_ver < @locked_version || @b_ver < @locked_version - end - - def segments_do_not_match(level) - index = [:major, :minor].index(level) - @a_ver.segments[index] != @b_ver.segments[index] - end - - def unlocking_gem? - unlock_gems.empty? || unlock_gems.include?(@gem_name) - end - - # Specific version moves can't always reliably be done during sorting - # as not all elements are compared against each other. - def post_sort(result) - # default :major behavior in Bundler does not do this - return result if major? - if unlocking_gem? - result - else - move_version_to_end(result, @locked_version) - end - end - - def move_version_to_end(result, version) - move, keep = result.partition {|s| s.version.to_s == version.to_s } - keep.concat(move) - end - - def debug_format_result(dep, spec_groups) - a = [dep.to_s, - spec_groups.map {|sg| [sg.version, sg.dependencies_for_activated_platforms.map {|dp| [dp.name, dp.requirement.to_s] }] }] - last_map = a.last.map {|sg_data| [sg_data.first.version, sg_data.last.map {|aa| aa.join(" ") }] } - [a.first, last_map, level, strict ? :strict : :not_strict] - end - end -end |