class Gem::Resolver
Given a set of Gem::Dependency objects as needed and a way to query the set of available specs via set, calculates a set of ActivationRequest objects which indicate all the specs that should be activated to meet the all the requirements.
Constants
- DEBUG_RESOLVER
-
If the
DEBUG_RESOLVERenvironment 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. - SINGLE_POSSIBILITY_CONSTRAINT_PENALTY
Attributes
Set to true if all development dependencies should be considered.
Set to true if immediate development dependencies should be considered.
When true, no dependencies are looked up for requested gems.
Hash of gems to skip resolution. Keyed by gem name, with arrays of gem specifications as values.
List of dependencies that could not be found in the configured sources.
Public Class Methods
Source
# File lib/rubygems/resolver.rb, line 58 def self.compose_sets(*sets) sets.compact! sets = sets.flat_map do |set| case set when Gem::Resolver::BestSet then set when Gem::Resolver::ComposedSet then set.sets else set end end case sets.length when 0 then raise ArgumentError, "one set in the composition must be non-nil" when 1 then sets.first else Gem::Resolver::ComposedSet.new(*sets) end end
Combines sets into a ComposedSet that allows specification lookup in a uniform manner. If one of the sets is itself a ComposedSet its sets are flattened into the result ComposedSet.
Source
# File lib/rubygems/resolver.rb, line 86 def self.for_current_gems(needed) new needed, Gem::Resolver::CurrentSet.new end
Creates a Resolver that queries only against the already installed gems for the needed dependencies.
Source
# File lib/rubygems/resolver.rb, line 98 def initialize(needed, set = nil) @set = set || Gem::Resolver::IndexSet.new @needed = needed @development = false @development_shallow = false @ignore_dependencies = false @skip_gems = {} @soft_missing = false @stats = Gem::Resolver::Stats.new end
Public Instance Methods
Source
# File lib/rubygems/resolver.rb, line 270 def allow_missing?(dependency) @soft_missing end
Source
# File lib/rubygems/resolver.rb, line 251 def dependencies_for(specification) return [] if @ignore_dependencies spec = specification.spec requests(spec, specification) end
Source
# File lib/rubygems/resolver.rb, line 266 def name_for(dependency) dependency.name end
Source
# File lib/rubygems/resolver.rb, line 171 def output @output ||= debug? ? $stdout : File.open(IO::NULL, "w") end
Source
# File lib/rubygems/resolver.rb, line 257 def requirement_satisfied_by?(requirement, activated, spec) matches_spec = requirement.matches_spec? spec return matches_spec if @soft_missing matches_spec && spec.spec.required_ruby_version.satisfied_by?(Gem.ruby_version) && spec.spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version) end
Source
# File lib/rubygems/resolver.rb, line 184 def resolve Gem::Molinillo::Resolver.new(self, self).resolve(@needed.map {|d| DependencyRequest.new d, nil }).tsort.filter_map(&:payload) rescue Gem::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) && !debug? end
Proceed with resolution! Returns an array of ActivationRequest objects.
Source
# File lib/rubygems/resolver.rb, line 222 def search_for(dependency) possibles, all = find_possible(dependency) if !@soft_missing && possibles.empty? exc = Gem::UnsatisfiableDependencyError.new dependency, all exc.errors = @set.errors raise exc end groups = Hash.new {|hash, key| hash[key] = [] } # create groups & sources in the same loop sources = possibles.map do |spec| source = spec.source groups[source] << spec source end.uniq.reverse activation_requests = [] sources.each do |source| groups[source]. sort_by {|spec| [spec.version, -Gem::Platform.platform_specificity_match(spec.platform, Gem::Platform.local)] }. map {|spec| ActivationRequest.new spec, dependency }. each {|activation_request| activation_requests << activation_request } end activation_requests end
Source
# File lib/rubygems/resolver.rb, line 274 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 ] end end
Private Instance Methods
Source
# File lib/rubygems/resolver.rb, line 296 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 end 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