# 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
attr_accessor :pre
# 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 be 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
# Creates a GemVersionPromoter instance.
#
# @return [GemVersionPromoter]
def initialize
@level = :major
@strict = false
@pre = false
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 Resolver::Package and an Array of Specifications of available
# versions for a gem, this method will return the Array of Specifications
# 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 package [Resolver::Package] The package being resolved.
# @param specs [Specification] An array of Specifications for the package.
# @return [Specification] A new instance of the Specification Array sorted and
# possibly filtered.
def sort_versions(package, specs)
specs = filter_dep_specs(specs, package) if strict
sort_dep_specs(specs, package)
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
# @return [bool] Convenience method for testing value of pre variable.
def pre?
pre == true
end
private
def filter_dep_specs(specs, package)
locked_version = package.locked_version
return specs if locked_version.nil? || major?
specs.select do |spec|
gsv = spec.version
must_match = minor? ? [0] : [0, 1]
all_match = must_match.all? {|idx| gsv.segments[idx] == locked_version.segments[idx] }
all_match && gsv >= locked_version
end
end
def sort_dep_specs(specs, package)
locked_version = package.locked_version
result = specs.sort do |a, b|
unless package.prerelease_specified? || pre?
a_pre = a.prerelease?
b_pre = b.prerelease?
next -1 if a_pre && !b_pre
next 1 if b_pre && !a_pre
end
if major?
a <=> b
elsif either_version_older_than_locked?(a, b, locked_version)
a <=> b
elsif segments_do_not_match?(a, b, :major)
b <=> a
elsif !minor? && segments_do_not_match?(a, b, :minor)
b <=> a
else
a <=> b
end
end
post_sort(result, package.unlock?, locked_version)
end
def either_version_older_than_locked?(a, b, locked_version)
locked_version && (a.version < locked_version || b.version < locked_version)
end
def segments_do_not_match?(a, b, level)
index = [:major, :minor].index(level)
a.segments[index] != b.segments[index]
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, unlock, locked_version)
# default :major behavior in Bundler does not do this
return result if major?
if unlock || locked_version.nil?
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
end
end
| Name | Type | Size | Permission | Actions |
|---|---|---|---|---|
| cli | Folder | 0755 |
|
|
| compact_index_client | Folder | 0755 |
|
|
| fetcher | Folder | 0755 |
|
|
| installer | Folder | 0755 |
|
|
| man | Folder | 0755 |
|
|
| plugin | Folder | 0755 |
|
|
| resolver | Folder | 0755 |
|
|
| settings | Folder | 0755 |
|
|
| source | Folder | 0755 |
|
|
| templates | Folder | 0755 |
|
|
| ui | Folder | 0755 |
|
|
| vendor | Folder | 0755 |
|
|
| build_metadata.rb | File | 1.2 KB | 0644 |
|
| capistrano.rb | File | 883 B | 0644 |
|
| cli.rb | File | 41 KB | 0644 |
|
| compact_index_client.rb | File | 3.36 KB | 0644 |
|
| constants.rb | File | 224 B | 0644 |
|
| current_ruby.rb | File | 2.43 KB | 0644 |
|
| definition.rb | File | 32.33 KB | 0644 |
|
| dependency.rb | File | 3.11 KB | 0644 |
|
| deployment.rb | File | 3.19 KB | 0644 |
|
| deprecate.rb | File | 876 B | 0644 |
|
| digest.rb | File | 2.16 KB | 0644 |
|
| dsl.rb | File | 19.97 KB | 0644 |
|
| endpoint_specification.rb | File | 3.65 KB | 0644 |
|
| env.rb | File | 5.01 KB | 0644 |
|
| environment_preserver.rb | File | 1.94 KB | 0644 |
|
| errors.rb | File | 5.17 KB | 0644 |
|
| feature_flag.rb | File | 1.79 KB | 0644 |
|
| fetcher.rb | File | 11.19 KB | 0644 |
|
| force_platform.rb | File | 557 B | 0644 |
|
| friendly_errors.rb | File | 3.75 KB | 0644 |
|
| gem_helper.rb | File | 6.89 KB | 0644 |
|
| gem_helpers.rb | File | 4.08 KB | 0644 |
|
| gem_tasks.rb | File | 138 B | 0644 |
|
| gem_version_promoter.rb | File | 4.76 KB | 0644 |
|
| graph.rb | File | 4.99 KB | 0644 |
|
| index.rb | File | 4.14 KB | 0644 |
|
| injector.rb | File | 10.08 KB | 0644 |
|
| inline.rb | File | 2.47 KB | 0644 |
|
| installer.rb | File | 10.25 KB | 0644 |
|
| lazy_specification.rb | File | 5.35 KB | 0644 |
|
| lockfile_generator.rb | File | 2.18 KB | 0644 |
|
| lockfile_parser.rb | File | 7.01 KB | 0644 |
|
| match_metadata.rb | File | 290 B | 0644 |
|
| match_platform.rb | File | 583 B | 0644 |
|
| match_remote_metadata.rb | File | 863 B | 0644 |
|
| mirror.rb | File | 5.78 KB | 0644 |
|
| plugin.rb | File | 11.25 KB | 0644 |
|
| process_lock.rb | File | 686 B | 0644 |
|
| remote_specification.rb | File | 3.71 KB | 0644 |
|
| resolver.rb | File | 14.62 KB | 0644 |
|
| retry.rb | File | 1.61 KB | 0644 |
|
| ruby_dsl.rb | File | 961 B | 0644 |
|
| ruby_version.rb | File | 4.17 KB | 0644 |
|
| rubygems_ext.rb | File | 10.88 KB | 0644 |
|
| rubygems_gem_installer.rb | File | 5.24 KB | 0644 |
|
| rubygems_integration.rb | File | 15.82 KB | 0644 |
|
| runtime.rb | File | 10.15 KB | 0644 |
|
| safe_marshal.rb | File | 597 B | 0644 |
|
| self_manager.rb | File | 4.76 KB | 0644 |
|
| settings.rb | File | 13.19 KB | 0644 |
|
| setup.rb | File | 963 B | 0644 |
|
| shared_helpers.rb | File | 10.76 KB | 0644 |
|
| similarity_detector.rb | File | 1.84 KB | 0644 |
|
| source.rb | File | 2.98 KB | 0644 |
|
| source_list.rb | File | 6.18 KB | 0644 |
|
| source_map.rb | File | 2.17 KB | 0644 |
|
| spec_set.rb | File | 5.08 KB | 0644 |
|
| stub_specification.rb | File | 2.79 KB | 0644 |
|
| ui.rb | File | 255 B | 0644 |
|
| uri_credentials_filter.rb | File | 1.28 KB | 0644 |
|
| uri_normalizer.rb | File | 715 B | 0644 |
|
| vendored_fileutils.rb | File | 101 B | 0644 |
|
| vendored_persistent.rb | File | 270 B | 0644 |
|
| vendored_pub_grub.rb | File | 99 B | 0644 |
|
| vendored_thor.rb | File | 180 B | 0644 |
|
| vendored_tsort.rb | File | 93 B | 0644 |
|
| vendored_uri.rb | File | 89 B | 0644 |
|
| version.rb | File | 260 B | 0644 |
|
| vlad.rb | File | 468 B | 0644 |
|
| worker.rb | File | 2.85 KB | 0644 |
|
| yaml_serializer.rb | File | 2.36 KB | 0644 |
|