summaryrefslogtreecommitdiff
path: root/lib/rubygems/resolver.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/resolver.rb')
-rw-r--r--lib/rubygems/resolver.rb607
1 files changed, 412 insertions, 195 deletions
diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb
index 13ee035e4c..788206c056 100644
--- a/lib/rubygems/resolver.rb
+++ b/lib/rubygems/resolver.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
-require 'rubygems/dependency'
-require 'rubygems/exceptions'
-require 'rubygems/util'
-require 'rubygems/util/list'
+
+require_relative "dependency"
+require_relative "exceptions"
##
# Given a set of Gem::Dependency objects as +needed+ and a way to query the
@@ -11,14 +10,14 @@ require 'rubygems/util/list'
# all the requirements.
class Gem::Resolver
- require 'rubygems/resolver/molinillo'
+ require_relative "vendored_pub_grub"
##
# If the DEBUG_RESOLVER environment variable is set then debugging mode is
# enabled for the resolver. This will display information about the state
# of the resolver while a set of dependencies is being resolved.
- DEBUG_RESOLVER = !ENV['DEBUG_RESOLVER'].nil?
+ DEBUG_RESOLVER = !ENV["DEBUG_RESOLVER"].nil?
##
# Set to true if all development dependencies should be considered.
@@ -36,21 +35,13 @@ class Gem::Resolver
attr_accessor :ignore_dependencies
##
- # List of dependencies that could not be found in the configured sources.
-
- attr_reader :missing
-
- attr_reader :stats
-
- ##
# Hash of gems to skip resolution. Keyed by gem name, with arrays of
# gem specifications as values.
attr_accessor :skip_gems
##
- # When a missing dependency, don't stop. Just go on and record what was
- # missing.
+ #
attr_accessor :soft_missing
@@ -59,10 +50,10 @@ class Gem::Resolver
# uniform manner. If one of the +sets+ is itself a ComposedSet its sets are
# flattened into the result ComposedSet.
- def self.compose_sets *sets
+ def self.compose_sets(*sets)
sets.compact!
- sets = sets.map do |set|
+ sets = sets.flat_map do |set|
case set
when Gem::Resolver::BestSet then
set
@@ -71,11 +62,11 @@ class Gem::Resolver
else
set
end
- end.flatten
+ end
case sets.length
when 0 then
- raise ArgumentError, 'one set in the composition must be non-nil'
+ raise ArgumentError, "one set in the composition must be non-nil"
when 1 then
sets.first
else
@@ -87,7 +78,7 @@ class Gem::Resolver
# Creates a Resolver that queries only against the already installed gems
# for the +needed+ dependencies.
- def self.for_current_gems needed
+ def self.for_current_gems(needed)
new needed, Gem::Resolver::CurrentSet.new
end
@@ -99,250 +90,476 @@ class Gem::Resolver
# satisfy the Dependencies. This defaults to IndexSet, which will query
# rubygems.org.
- def initialize needed, set = nil
+ def initialize(needed, set = nil)
@set = set || Gem::Resolver::IndexSet.new
@needed = needed
@development = false
@development_shallow = false
@ignore_dependencies = false
- @missing = []
@skip_gems = {}
@soft_missing = false
- @stats = Gem::Resolver::Stats.new
- end
- def explain stage, *data # :nodoc:
- return unless DEBUG_RESOLVER
+ @root_package = RootPackage.new
+ @root_version = Gem::PubGrub::Package.root_version
+
+ @packages = {}
- d = data.map { |x| x.pretty_inspect }.join(", ")
- $stderr.printf "%10s %s\n", stage.to_s.upcase, d
+ @unfiltered_specs = Hash.new {|h, name| h[name] = find_unfiltered_specs_for(name) }
+ @all_specs = Hash.new {|h, name| h[name] = filter_specs(@unfiltered_specs[name]) }
+ @all_versions = Hash.new {|h, pkg| h[pkg] = @all_specs[pkg.to_s].map(&:version).uniq.sort }
+ @sorted_versions = Hash.new do |h, pkg|
+ h[pkg] = Gem::PubGrub::Package.root?(pkg) ? [@root_version] : @all_versions[pkg]
+ end
+ @cached_dependencies = Hash.new do |h, pkg|
+ h[pkg] = if Gem::PubGrub::Package.root?(pkg)
+ { @root_version => root_dependencies }
+ else
+ Hash.new {|v, ver| v[ver] = compute_dependencies(pkg, ver) }
+ end
+ end
+ @version_to_index = Hash.new {|h, pkg| h[pkg] = @sorted_versions[pkg].each_with_index.to_h }
+ @versions_for_cache = Hash.new {|h, pkg| h[pkg] = {} }
+ @spec_for_cache = Hash.new {|h, name| h[name] = build_spec_for_cache(name) }
end
- def explain_list stage # :nodoc:
- return unless DEBUG_RESOLVER
+ ##
+ # Proceed with resolution! Returns an array of ActivationRequest objects.
+
+ def resolve
+ # Pre-check: raise UnsatisfiableDependencyError for root deps with no
+ # platform match. We filter by platform ONLY here (not required_ruby_version
+ # / required_rubygems_version): a foreign-platform gem is genuinely "not
+ # found", but a gem that exists yet is incompatible with the running Ruby
+ # should flow through the solver to a DependencyResolutionError that names
+ # the Ruby requirement. That matches Bundler (which models Ruby as a
+ # synthetic dependency, so this surfaces as a solve failure) and gives a
+ # clearer message than the platform-oriented UnsatisfiableDependencyError.
+ @needed.each do |dep|
+ next if @soft_missing
+ dep_request = DependencyRequest.new(dep, nil)
+ all = @set.find_all(dep_request)
+ matching = select_local_platforms(all)
+
+ next unless matching.empty?
+
+ exc = Gem::UnsatisfiableDependencyError.new(dep_request, all)
+ exc.errors = @set.errors
+ raise exc
+ end
- data = yield
- $stderr.printf "%10s (%d entries)\n", stage.to_s.upcase, data.size
- PP.pp data, $stderr unless data.empty?
+ solver = Gem::PubGrub::VersionSolver.new(
+ source: self,
+ root: @root_package,
+ strategy: Gem::Resolver::Strategy.new(self),
+ logger: make_logger
+ )
+ result = solver.solve
+
+ # Convert to Array<ActivationRequest>
+ needed_by_name = @needed.group_by(&:name)
+ result.filter_map do |package, version|
+ next if Gem::PubGrub::Package.root?(package)
+ spec = spec_for(package.to_s, version)
+ dep = needed_by_name[package.to_s]&.first || Gem::Dependency.new(package.to_s)
+ dep_request = DependencyRequest.new(dep, nil)
+ ActivationRequest.new(spec, dep_request)
+ end
+ rescue Gem::PubGrub::SolveFailure => e
+ extended = extract_extended_explanation(e.incompatibility)
+ if extended
+ message = "#{e.explanation}\n\n#{extended}"
+ raise Gem::DependencyResolutionError, Struct.new(:explanation).new(message)
+ else
+ raise Gem::DependencyResolutionError, e
+ end
end
- ##
- # Creates an ActivationRequest for the given +dep+ and the last +possible+
- # specification.
- #
- # Returns the Specification and the ActivationRequest
+ # PubGrub source interface methods
+
+ def all_versions_for(package)
+ versions = @sorted_versions[package].reverse # highest first
+ name = package.to_s
+
+ if (skip_dep_gems = skip_gems[name]) && !skip_dep_gems.empty?
+ # Conservative mode: float the already-installed (skip) versions to the
+ # front so the solver prefers them. This sets *preference* only (it feeds
+ # the strategy's version-index map); it does not restrict availability, so
+ # every version stays selectable via versions_for. When an installed
+ # version is made impossible by a downstream conflict, the solver
+ # backtracks to a newer version instead of failing. Molinillo instead
+ # hard-restricted the candidate set to skip versions and raised.
+ #
+ # This reaches the same outcome as Bundler (upgrade-over-raise) for the
+ # common single-blocked-gem case, though the mechanism differs: Bundler
+ # hard-pins locked gems and selectively unlocks + re-solves on conflict,
+ # whereas we float as a preference and let PubGrub backtrack in one solve.
+ # The float can therefore over-upgrade when several installed gems are
+ # jointly involved in a conflict; that outcome-level divergence is
+ # accepted (see test_conservative_upgrades_when_installed_blocked).
+ skip_versions = skip_dep_gems.map(&:version)
+ preferred, rest = versions.partition {|v| skip_versions.include?(v) }
+ preferred + rest
+ else
+ # Prefer already-installed versions to avoid unnecessary upgrades
+ installed_versions = @all_specs[name].
+ select {|s| s.is_a?(Gem::Resolver::InstalledSpecification) }.
+ map(&:version)
+ if installed_versions.any?
+ preferred, rest = versions.partition {|v| installed_versions.include?(v) }
+ preferred + rest
+ else
+ versions
+ end
+ end
+ end
+
+ def versions_for(package, range = Gem::PubGrub::VersionRange.any)
+ @versions_for_cache[package][range] ||= begin
+ candidates = range.select_versions(@sorted_versions[package])
- def activation_request dep, possible # :nodoc:
- spec = possible.pop
+ if Gem::PubGrub::Package.root?(package) ||
+ (@set.respond_to?(:prerelease) && @set.prerelease) ||
+ range_admits_prerelease?(range)
+ candidates
+ elsif @all_versions[package].any? {|v| !v.prerelease? }
+ candidates.reject(&:prerelease?)
+ else
+ # Only prereleases exist for this gem; fall back to them so
+ # dependencies like `>= 1.0` can still be satisfied.
+ candidates
+ end
+ end
+ end
+
+ def no_versions_incompatibility_for(_package, unsatisfied_term)
+ cause = Gem::PubGrub::Incompatibility::NoVersions.new(unsatisfied_term)
- explain :activate, [spec.full_name, possible.size]
- explain :possible, possible
+ name = unsatisfied_term.package.to_s
+ constraint = unsatisfied_term.constraint
+ extended_explanation = build_extended_explanation(name, constraint)
- activation_request =
- Gem::Resolver::ActivationRequest.new spec, dep, possible
+ custom_explanation = if extended_explanation
+ "#{constraint} could not be found in any repository"
+ end
- return spec, activation_request
+ Gem::Resolver::Incompatibility.new(
+ [unsatisfied_term],
+ cause: cause,
+ custom_explanation: custom_explanation,
+ extended_explanation: extended_explanation
+ )
end
- def requests s, act, reqs=[] # :nodoc:
- return reqs if @ignore_dependencies
+ def incompatibilities_for(package, version)
+ package_deps = @cached_dependencies[package]
+ sorted_versions = @sorted_versions[package]
+ package_deps[version].filter_map do |dep_package_name, dep_constraint|
+ dep_package = dep_constraint.package
- s.fetch_development_dependencies if @development
+ low = high = @version_to_index[package][version]
- s.dependencies.reverse_each do |d|
- next if d.type == :development and not @development
- next if d.type == :development and @development_shallow and
- act.development?
- next if d.type == :development and @development_shallow and
- act.parent
+ # find version low such that all >= low share the same dep
+ while low > 0 &&
+ package_deps[sorted_versions[low - 1]][dep_package_name] == dep_constraint
+ low -= 1
+ end
+ low =
+ if low == 0
+ nil
+ else
+ sorted_versions[low]
+ end
+
+ # find version high such that all < high share the same dep
+ while high < sorted_versions.length &&
+ package_deps[sorted_versions[high]][dep_package_name] == dep_constraint
+ high += 1
+ end
+ high =
+ if high == sorted_versions.length
+ nil
+ else
+ sorted_versions[high]
+ end
+
+ range = Gem::PubGrub::VersionRange.new(min: low, max: high, include_min: !low.nil?)
+ self_constraint = Gem::PubGrub::VersionConstraint.new(package, range: range)
+
+ # No specs anywhere means an unknown package. Check @unfiltered_specs, not
+ # the filtered set, so a dep filtered out by platform/Ruby/prerelease falls
+ # through to NoVersions for proper hints instead. The band-scoped
+ # self_constraint lets clean sibling versions still resolve via backtracking.
+ if @unfiltered_specs[dep_package_name].empty?
+ cause = Gem::PubGrub::Incompatibility::InvalidDependency.new(dep_package, dep_constraint)
+ self_term = Gem::PubGrub::Term.new(self_constraint, true)
+ # PubGrub's default InvalidDependency rendering drops the version
+ # requirement ("depends on unknown package bar"). Supply a custom
+ # explanation so the missing dependency's constraint is preserved
+ # ("depends on bar = 0.5 which could not be found in any repository"),
+ # matching Molinillo's diagnostics.
+ return [Gem::PubGrub::Incompatibility.new(
+ [self_term],
+ cause: cause,
+ custom_explanation: "#{self_term.to_s(allow_every: true)} depends on #{dep_constraint} which could not be found in any repository"
+ )]
+ end
- reqs << Gem::Resolver::DependencyRequest.new(d, act)
- @stats.requirement!
+ # An empty range means the requirement is self-contradictory (e.g. `> 2, < 1`).
+ if dep_constraint.range.empty?
+ return [Gem::Resolver::Incompatibility.new(
+ [Gem::PubGrub::Term.new(self_constraint, true)],
+ cause: Gem::PubGrub::Incompatibility::NoVersions.new(dep_constraint),
+ custom_explanation: "#{dep_package_name} cannot satisfy contradictory requirements #{dep_constraint.constraint_string}"
+ )]
+ end
+
+ Gem::PubGrub::Incompatibility.new(
+ [Gem::PubGrub::Term.new(self_constraint, true), Gem::PubGrub::Term.new(dep_constraint, false)],
+ cause: :dependency
+ )
end
+ end
- @set.prefetch reqs
+ ##
+ # Returns the gems in +specs+ that match the local platform.
+
+ def select_local_platforms(specs) # :nodoc:
+ specs.select do |spec|
+ Gem::Platform.installable? spec
+ end
+ end
- @stats.record_requirements reqs
+ private
- reqs
+ def package_for(name)
+ @packages[name] ||= Gem::PubGrub::Package.new(name)
end
- include Molinillo::UI
+ def root_dependencies
+ deps = {}
+ @needed.each do |dep|
+ constraint = Gem::PubGrub::RubyGems.requirement_to_constraint(package_for(dep.name), dep.requirement)
+ deps[dep.name] = deps.key?(dep.name) ? deps[dep.name].intersect(constraint) : constraint
+ end
+ deps
+ end
- def output
- @output ||= debug? ? $stdout : File.open(Gem::Util::NULL_DEVICE, 'w')
+ # Only the min bound is inspected: `~>` synthesises a max like `X.A`
+ # whose suffix looks prerelease to Gem::Version but is not the user's
+ # intent, so checking max would mis-admit prereleases for every `~>`.
+ def range_admits_prerelease?(range)
+ range.ranges.any? do |r|
+ next false if r.empty?
+ r.min&.prerelease?
+ end
end
- def debug?
- DEBUG_RESOLVER
+ def find_unfiltered_specs_for(name)
+ dep = Gem::Dependency.new(name, ">= 0.a")
+ dep_request = DependencyRequest.new(dep, nil)
+ @set.find_all(dep_request)
end
- include Molinillo::SpecificationProvider
+ def filter_specs(specs)
+ filtered = select_local_platforms(specs)
- ##
- # Proceed with resolution! Returns an array of ActivationRequest objects.
+ unless @soft_missing
+ filtered = filtered.select do |s|
+ s.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
+ s.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
+ rescue StandardError
+ true
+ end
+ end
- def resolve
- locking_dg = Molinillo::DependencyGraph.new
- Molinillo::Resolver.new(self, self).resolve(@needed.map { |d| DependencyRequest.new d, nil }, locking_dg).tsort.map(&:payload).compact
- rescue Molinillo::VersionConflict => e
- conflict = e.conflicts.values.first
- raise Gem::DependencyResolutionError, Conflict.new(conflict.requirement_trees.first.first, conflict.existing, conflict.requirement)
- ensure
- @output.close if defined?(@output) and !debug?
+ filtered
end
- ##
- # Extracts the specifications that may be able to fulfill +dependency+ and
- # returns those that match the local platform and all those that match.
+ def spec_for(name, version)
+ @spec_for_cache[name][version]
+ end
- def find_possible dependency # :nodoc:
- all = @set.find_all dependency
+ def build_spec_for_cache(name)
+ # Rank sources by the order they were first supplied so that, when multiple
+ # sources offer the same version and platform, the earlier source wins.
+ source_rank = {}
+ @all_specs[name].each do |s|
+ source_rank[s.source] ||= source_rank.size
+ end
- if (skip_dep_gems = skip_gems[dependency.name]) && !skip_dep_gems.empty?
- matching = all.select do |api_spec|
- skip_dep_gems.any? { |s| api_spec.version == s.version }
- end
+ @all_specs[name].group_by(&:version).transform_values do |candidates|
+ next candidates.first if candidates.length == 1
- all = matching unless matching.empty?
+ # Prefer already-installed specs to avoid unnecessary downloads
+ installed = candidates.select {|s| s.is_a?(Gem::Resolver::InstalledSpecification) }
+ next installed.first if installed.length == 1
+ candidates = installed if installed.any?
+
+ # Among remaining candidates, prefer the most specific platform, then the
+ # earlier-supplied source.
+ candidates.min_by do |s|
+ [Gem::Platform.platform_specificity_match(s.platform, Gem::Platform.local),
+ source_rank[s.source]]
+ end
end
+ end
- matching_platform = select_local_platforms all
+ def compute_dependencies(package, version)
+ spec = spec_for(package.to_s, version)
+ return {} unless spec
+ return {} if @ignore_dependencies
- return matching_platform, all
- end
+ spec.fetch_development_dependencies if @development && spec.respond_to?(:fetch_development_dependencies)
- ##
- # Returns the gems in +specs+ that match the local platform.
+ deps = {}
+ root_names = @needed.map(&:name)
- def select_local_platforms specs # :nodoc:
- specs.select do |spec|
- Gem::Platform.installable? spec
+ spec.dependencies.each do |d|
+ next if d.name == package.to_s
+ next if d.type == :development && !@development
+ next if d.type == :development && @development_shallow && !root_names.include?(package.to_s)
+
+ dep_package = package_for(d.name)
+
+ # In force mode, skip deps that can't be satisfied - either no
+ # specs at all, or no specs matching the version requirement.
+ if @soft_missing
+ dep_specs = @all_specs[d.name]
+ matching = dep_specs.select {|s| d.requirement.satisfied_by?(s.version) }
+ next if matching.empty?
+ end
+
+ deps[d.name] = Gem::PubGrub::RubyGems.requirement_to_constraint(dep_package, d.requirement)
end
+
+ deps
end
- def search_for(dependency)
- possibles, all = find_possible(dependency)
- if !@soft_missing && possibles.empty?
- @missing << dependency
- exc = Gem::UnsatisfiableDependencyError.new dependency, all
- exc.errors = @set.errors
- raise exc
- end
+ def build_extended_explanation(name, constraint)
+ unfiltered = @unfiltered_specs[name]
+ return if unfiltered.empty?
- sources = []
+ filtered = @all_specs[name]
+ pkg = package_for(name)
- groups = Hash.new { |hash, key| hash[key] = [] }
+ # A prerelease hint applies when the source would strip prereleases for
+ # this constraint (global prerelease flag off and the constraint's range
+ # doesn't itself reach into prerelease territory) AND a prerelease of
+ # the gem exists somewhere.
+ prerelease_gated = !(@set.respond_to?(:prerelease) && @set.prerelease) &&
+ !range_admits_prerelease?(constraint.range)
+ has_prerelease_candidate = prerelease_gated &&
+ @all_versions[pkg].any?(&:prerelease?)
- # create groups & sources in the same loop
- sources = possibles.map { |spec|
- source = spec.source
- groups[source] << spec
- source
- }.uniq.reverse
+ return if filtered.length == unfiltered.length && !has_prerelease_candidate
- activation_requests = []
+ hints = []
- sources.each do |source|
- groups[source].
- sort_by { |spec| [spec.version, Gem::Platform.local =~ spec.platform ? 1 : 0] }.
- map { |spec| ActivationRequest.new spec, dependency, [] }.
- each { |activation_request| activation_requests << activation_request }
+ # Check for specs that exist for other platforms
+ platform_specs = unfiltered.select do |s|
+ !Gem::Platform.installable?(s) && constraint.range.include?(s.version)
+ end
+ if platform_specs.any?
+ label = "#{name} (#{constraint.constraint_string})"
+ hints << "The source contains the following gems matching '#{label}':"
+ platform_specs.each do |s|
+ actual = s.respond_to?(:spec) ? s.spec : s
+ hints << " * #{actual.full_name}"
+ end
end
- activation_requests
- end
+ # Check for specs filtered by Ruby version
+ installable = select_local_platforms(unfiltered)
+ ruby_specs = installable.select do |s|
+ actual = s.respond_to?(:spec) ? s.spec : s
+ constraint.range.include?(s.version) &&
+ !actual.required_ruby_version.satisfied_by?(Gem.ruby_version)
+ rescue StandardError
+ false
+ end
+ if ruby_specs.any?
+ versions = ruby_specs.map(&:version).uniq.sort.reverse.first(3)
+ sample = ruby_specs.find {|s| s.version == versions.first }
+ actual = sample.respond_to?(:spec) ? sample.spec : sample
+ ruby_req = actual.required_ruby_version
+ hints << "#{name} #{versions.join(", ")} requires Ruby #{ruby_req} (you have #{Gem.ruby_version})"
+ end
- def dependencies_for(specification)
- return [] if @ignore_dependencies
- spec = specification.spec
- requests(spec, specification)
- end
+ # Check for specs filtered by prerelease status
+ if prerelease_gated
+ prerelease_versions = @all_versions[pkg].select(&:prerelease?)
+ if prerelease_versions.any?
+ versions = prerelease_versions.sort.reverse.first(3) # limit to avoid cluttering error output
+ hints << "#{name} #{versions.join(", ")} are pre-release versions. Use --prerelease to allow pre-release gems."
+ end
+ end
- def requirement_satisfied_by?(requirement, activated, spec)
- requirement.matches_spec? spec
+ hints.empty? ? nil : hints.join("\n")
end
- def name_for(dependency)
- dependency.name
+ def extract_extended_explanation(incompatibility)
+ while incompatibility.cause.is_a?(Gem::PubGrub::Incompatibility::ConflictCause)
+ cause = incompatibility.cause
+
+ [cause.conflict, cause.other].each do |incompat|
+ if incompat.cause.is_a?(Gem::PubGrub::Incompatibility::NoVersions) &&
+ incompat.respond_to?(:extended_explanation) &&
+ incompat.extended_explanation
+ return incompat.extended_explanation
+ end
+ end
+
+ incompatibility = cause.conflict
+ end
+
+ nil
end
- def allow_missing?(dependency)
- @missing << dependency
- @soft_missing
+ def make_logger
+ DEBUG_RESOLVER ? Gem::PubGrub::StderrLogger.new : Gem::PubGrub::NullLogger.new
end
- def sort_dependencies(dependencies, activated, conflicts)
- dependencies.sort_by.with_index do |dependency, i|
- name = name_for(dependency)
- [
- activated.vertex_named(name).payload ? 0 : 1,
- amount_constrained(dependency),
- conflicts[name] ? 0 : 1,
- activated.vertex_named(name).payload ? 0 : search_for(dependency).count,
- i # for stable sort
- ]
+ # Custom root package so error messages say "your request depends on..."
+ # instead of PubGrub's default "root depends on...".
+ class RootPackage < Gem::PubGrub::Package
+ def initialize
+ super(:root)
end
- end
- SINGLE_POSSIBILITY_CONSTRAINT_PENALTY = 1_000_000
- private_constant :SINGLE_POSSIBILITY_CONSTRAINT_PENALTY if defined?(private_constant)
+ def root?
+ true
+ end
- # returns an integer \in (-\infty, 0]
- # a number closer to 0 means the dependency is less constraining
- #
- # dependencies w/ 0 or 1 possibilities (ignoring version requirements)
- # are given very negative values, so they _always_ sort first,
- # before dependencies that are unconstrained
- def amount_constrained(dependency)
- @amount_constrained ||= {}
- @amount_constrained[dependency.name] ||= begin
- name_dependency = Gem::Dependency.new(dependency.name)
- dependency_request_for_name = Gem::Resolver::DependencyRequest.new(name_dependency, dependency.requester)
- all = @set.find_all(dependency_request_for_name).size
-
- if all <= 1
- all - SINGLE_POSSIBILITY_CONSTRAINT_PENALTY
- else
- search = search_for(dependency).size
- search - all
- end
+ def to_s
+ "your request"
end
end
- private :amount_constrained
-
end
-##
-# TODO remove in RubyGems 3
-
-Gem::DependencyResolver = Gem::Resolver # :nodoc:
-
-require 'rubygems/resolver/activation_request'
-require 'rubygems/resolver/conflict'
-require 'rubygems/resolver/dependency_request'
-require 'rubygems/resolver/requirement_list'
-require 'rubygems/resolver/stats'
-
-require 'rubygems/resolver/set'
-require 'rubygems/resolver/api_set'
-require 'rubygems/resolver/composed_set'
-require 'rubygems/resolver/best_set'
-require 'rubygems/resolver/current_set'
-require 'rubygems/resolver/git_set'
-require 'rubygems/resolver/index_set'
-require 'rubygems/resolver/installer_set'
-require 'rubygems/resolver/lock_set'
-require 'rubygems/resolver/vendor_set'
-require 'rubygems/resolver/source_set'
-
-require 'rubygems/resolver/specification'
-require 'rubygems/resolver/spec_specification'
-require 'rubygems/resolver/api_specification'
-require 'rubygems/resolver/git_specification'
-require 'rubygems/resolver/index_specification'
-require 'rubygems/resolver/installed_specification'
-require 'rubygems/resolver/local_specification'
-require 'rubygems/resolver/lock_specification'
-require 'rubygems/resolver/vendor_specification'
+require_relative "resolver/activation_request"
+require_relative "resolver/dependency_request"
+require_relative "resolver/incompatibility"
+require_relative "resolver/strategy"
+require_relative "resolver/requirement_list"
+require_relative "resolver/set"
+require_relative "resolver/api_set"
+require_relative "resolver/composed_set"
+require_relative "resolver/best_set"
+require_relative "resolver/current_set"
+require_relative "resolver/git_set"
+require_relative "resolver/index_set"
+require_relative "resolver/installer_set"
+require_relative "resolver/lock_set"
+require_relative "resolver/vendor_set"
+require_relative "resolver/source_set"
+
+require_relative "resolver/specification"
+require_relative "resolver/spec_specification"
+require_relative "resolver/api_specification"
+require_relative "resolver/git_specification"
+require_relative "resolver/index_specification"
+require_relative "resolver/installed_specification"
+require_relative "resolver/local_specification"
+require_relative "resolver/lock_specification"
+require_relative "resolver/vendor_specification"