summaryrefslogtreecommitdiff
path: root/lib/rubygems/resolver
diff options
context:
space:
mode:
authorHiroshi SHIBATA <[email protected]>2020-12-08 16:33:39 +0900
committerHiroshi SHIBATA <[email protected]>2020-12-08 17:30:02 +0900
commit4aca77edde91f826aa243e268bf1ef5214530583 ()
treeef0cf1a95fcced00ca5fa40f3412c567bf95d705 /lib/rubygems/resolver
parent6a6a24df9b72750d12f9b15192bdb7517e668efb (diff)
Merge prepare version of RubyGems 3.2.0
Notes: Merged: https://.com/ruby/ruby/pull/3864
-rw-r--r--lib/rubygems/resolver/activation_request.rb10
-rw-r--r--lib/rubygems/resolver/api_specification.rb6
-rw-r--r--lib/rubygems/resolver/conflict.rb2
-rw-r--r--lib/rubygems/resolver/dependency_request.rb2
-rw-r--r--lib/rubygems/resolver/index_specification.rb11
-rw-r--r--lib/rubygems/resolver/installer_set.rb3
-rw-r--r--lib/rubygems/resolver/lock_set.rb2
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo.rb11
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb7
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb1
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb44
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb1
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb3
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb3
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb3
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb3
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb13
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb3
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb7
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb53
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb82
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb3
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb1
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb4
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb671
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb5
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/state.rb12
-rw-r--r--lib/rubygems/resolver/specification.rb2
28 files changed, 746 insertions, 222 deletions
@@ -28,12 +28,20 @@ class Gem::Resolver::ActivationRequest
when Gem::Specification
@spec == other
when Gem::Resolver::ActivationRequest
- @spec == other.spec && @request == other.request
else
false
end
end
##
# Is this activation request for a development dependency?
@@ -46,6 +46,10 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
@dependencies == other.dependencies
end
def fetch_development_dependencies # :nodoc:
spec = source.fetch_spec Gem::NameTuple.new @name, @version, @platform
@@ -53,7 +57,7 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
end
def installable_platform? # :nodoc:
- Gem::Platform.match @platform
end
def pretty_print(q) # :nodoc:
@@ -85,7 +85,7 @@ class Gem::Resolver::Conflict
activated, requirement,
request_path(@activated).reverse.join(", depends on\n "),
request_path(@failed_dep).reverse.join(", depends on\n "),
- matching,
]
end
@@ -28,7 +28,7 @@ class Gem::Resolver::DependencyRequest
when Gem::Dependency
@dependency == other
when Gem::Resolver::DependencyRequest
- @dependency == other.dependency && @requester == other.requester
else
false
end
@@ -33,6 +33,17 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
spec.dependencies
end
def inspect # :nodoc:
'#<%s %s source %s>' % [self.class, full_name, @source]
end
@@ -32,7 +32,6 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
super()
@domain = domain
- @remote = consider_remote?
@f = Gem::SpecFetcher.fetcher
@@ -170,7 +169,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
always_install = @always_install.map {|s| s.full_name }
'#<%s domain: %s specs: %p always install: %p>' % [
- self.class, @domain, @specs.keys, always_install,
]
end
@@ -28,7 +28,7 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
def add(name, version, platform) # :nodoc:
version = Gem::Version.new version
specs = [
- Gem::Resolver::LockSpecification.new(self, name, version, @sources, platform)
]
@specs.concat specs
@@ -1,9 +1,10 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/gem_metadata'
-require 'rubygems/resolver/molinillo/lib/molinillo/errors'
-require 'rubygems/resolver/molinillo/lib/molinillo/resolver'
-require 'rubygems/resolver/molinillo/lib/molinillo/modules/ui'
-require 'rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider'
# Gem::Resolver::Molinillo is a generic dependency resolution algorithm.
module Gem::Resolver::Molinillo
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
# @!visibility private
module Delegates
@@ -45,6 +46,12 @@ module Gem::Resolver::Molinillo
current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
current_state.conflicts
end
end
end
end
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
module Delegates
# Delegates all {Gem::Resolver::Molinillo::SpecificationProvider} methods to a
@@ -1,9 +1,10 @@
# frozen_string_literal: true
require 'set'
require 'tsort'
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log'
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex'
module Gem::Resolver::Molinillo
# A directed acyclic graph that is tuned to hold named dependencies
@@ -123,6 +124,7 @@ module Gem::Resolver::Molinillo
dot.join("\n")
end
# @return [Boolean] whether the two dependency graphs are equal, determined
# by a recursive traversal of each {#root_vertices} and its
# {Vertex#successors}
@@ -147,8 +149,8 @@ module Gem::Resolver::Molinillo
vertex = add_vertex(name, payload, root)
vertex.explicit_requirements << requirement if root
parent_names.each do |parent_name|
- parent_node = vertex_named(parent_name)
- add_edge(parent_node, vertex, requirement)
end
vertex
end
@@ -189,7 +191,7 @@ module Gem::Resolver::Molinillo
# @return [Edge] the added edge
def add_edge(origin, destination, requirement)
if destination.path_to?(origin)
- raise CircularDependencyError.new([origin, destination])
end
add_edge_no_circular(origin, destination, requirement)
end
@@ -218,5 +220,37 @@ module Gem::Resolver::Molinillo
def add_edge_no_circular(origin, destination, requirement)
log.add_edge_no_circular(self, origin.name, destination.name, requirement)
end
end
end
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
class DependencyGraph
# An action that modifies a {DependencyGraph} that is reversible.
@@ -1,5 +1,6 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
module Gem::Resolver::Molinillo
class DependencyGraph
# @!visibility private
@@ -1,5 +1,6 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
module Gem::Resolver::Molinillo
class DependencyGraph
# @!visibility private
@@ -1,5 +1,6 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
module Gem::Resolver::Molinillo
class DependencyGraph
# @!visibility private
@@ -1,5 +1,6 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
module Gem::Resolver::Molinillo
class DependencyGraph
# @!visibility private
@@ -1,10 +1,11 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular'
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex'
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge'
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named'
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload'
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag'
module Gem::Resolver::Molinillo
class DependencyGraph
@@ -1,5 +1,6 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
module Gem::Resolver::Molinillo
class DependencyGraph
# @!visibility private
@@ -1,5 +1,6 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
module Gem::Resolver::Molinillo
class DependencyGraph
# @!visibility private
@@ -13,11 +14,11 @@ module Gem::Resolver::Molinillo
end
# (see Action#up)
- def up(_graph)
end
# (see Action#down)
- def down(_graph)
end
# @!group Tag
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
class DependencyGraph
# A vertex in a {DependencyGraph} that encapsulates a {#name} and a
@@ -32,7 +33,7 @@ module Gem::Resolver::Molinillo
# @return [Array<Object>] all of the requirements that required
# this vertex
def requirements
- incoming_edges.map(&:requirement) + explicit_requirements
end
# @return [Array<Edge>] the edges of {#graph} that have `self` as their
@@ -49,14 +50,25 @@ module Gem::Resolver::Molinillo
incoming_edges.map(&:origin)
end
- # @return [Array<Vertex>] the vertices of {#graph} where `self` is a
# {#descendent?}
def recursive_predecessors
- vertices = predecessors
- vertices += vertices.map(&:recursive_predecessors).flatten(1)
- vertices.uniq!
vertices
end
# @return [Array<Vertex>] the vertices of {#graph} that have an edge with
# `self` as their {Edge#origin}
@@ -64,14 +76,25 @@ module Gem::Resolver::Molinillo
outgoing_edges.map(&:destination)
end
- # @return [Array<Vertex>] the vertices of {#graph} where `self` is an
# {#ancestor?}
def recursive_successors
- vertices = successors
- vertices += vertices.map(&:recursive_successors).flatten(1)
- vertices.uniq!
vertices
end
# @return [String] a string suitable for debugging
def inspect
@@ -107,11 +130,21 @@ module Gem::Resolver::Molinillo
# dependency graph?
# @return true iff there is a path following edges within this {#graph}
def path_to?(other)
- equal?(other) || successors.any? { |v| v.path_to?(other) }
end
alias descendent? path_to?
# Is there a path from `other` to `self` following edges in the
# dependency graph?
# @return true iff there is a path following edges within this {#graph}
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
# An error that occurred during the resolution process
class ResolverError < StandardError; end
@@ -17,7 +18,7 @@ module Gem::Resolver::Molinillo
# @param [Array<Object>] required_by @see {#required_by}
def initialize(dependency, required_by = [])
@dependency = dependency
- @required_by = required_by
super()
end
@@ -41,11 +42,11 @@ module Gem::Resolver::Molinillo
attr_reader :dependencies
# Initializes a new error with the given circular vertices.
- # @param [Array<DependencyGraph::Vertex>] nodes the nodes in the dependency
# that caused the error
- def initialize(nodes)
- super "There is a circular dependency between #{nodes.map(&:name).join(' and ')}"
- @dependencies = nodes.map(&:payload).to_set
end
end
@@ -55,11 +56,16 @@ module Gem::Resolver::Molinillo
# resolution to fail
attr_reader :conflicts
# Initializes a new error with the given version conflicts.
# @param [{String => Resolution::Conflict}] conflicts see {#conflicts}
- def initialize(conflicts)
pairs = []
- conflicts.values.flatten.map(&:requirements).flatten.each do |conflicting|
conflicting.each do |source, conflict_requirements|
conflict_requirements.each do |c|
pairs << [c, source]
@@ -69,7 +75,69 @@ module Gem::Resolver::Molinillo
super "Unable to satisfy the following requirements:\n\n" \
"#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}"
@conflicts = conflicts
end
end
end
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
# The version of Gem::Resolver::Molinillo.
- VERSION = '0.5.7'.freeze
end
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
# Provides information about specifcations and dependencies to the resolver,
# allowing the {Resolver} class to remain generic while still providing power
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
# Conveys information about the resolution process to a user.
module UI
@@ -48,7 +49,8 @@ module Gem::Resolver::Molinillo
if debug?
debug_info = yield
debug_info = debug_info.inspect unless debug_info.is_a?(String)
- output.puts debug_info.split("\n").map { |s| ' ' * depth + s }
end
end
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
class Resolver
# A specific resolution from a given {Resolver}
@@ -8,22 +9,125 @@ module Gem::Resolver::Molinillo
# @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict
# @attr [Object, nil] existing the existing spec that was in conflict with
# the {#possibility}
- # @attr [Object] possibility the spec that was unable to be activated due
- # to a conflict
# @attr [Object] locked_requirement the relevant locking requirement.
# @attr [Array<Array<Object>>] requirement_trees the different requirement
# trees that led to every requirement for the conflicting name.
# @attr [{String=>Object}] activated_by_name the already-activated specs.
Conflict = Struct.new(
:requirement,
:requirements,
:existing,
- :possibility,
:locked_requirement,
:requirement_trees,
- :activated_by_name
)
# @return [SpecificationProvider] the provider that knows about
# dependencies, requirements, specifications, versions, etc.
attr_reader :specification_provider
@@ -64,7 +168,7 @@ module Gem::Resolver::Molinillo
start_resolution
while state
- break unless state.requirements.any? || state.requirement
indicate_progress
if state.respond_to?(:pop_possibility_state) # DependencyState
debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
@@ -78,7 +182,7 @@ module Gem::Resolver::Molinillo
process_topmost_state
end
- activated.freeze
ensure
end_resolution
end
@@ -103,12 +207,25 @@ module Gem::Resolver::Molinillo
def start_resolution
@started_at = Time.now
- handle_missing_or_push_dependency_state(initial_state)
debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" }
resolver_ui.before_resolution
end
# Ends the resolution process
# @return [void]
def end_resolution
@@ -121,11 +238,11 @@ module Gem::Resolver::Molinillo
debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
end
- require 'rubygems/resolver/molinillo/lib/molinillo/state'
- require 'rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider'
- require 'rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state'
- require 'rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider'
include Gem::Resolver::Molinillo::Delegates::ResolutionState
include Gem::Resolver::Molinillo::Delegates::SpecificationProvider
@@ -136,9 +253,12 @@ module Gem::Resolver::Molinillo
if possibility
attempt_to_activate
else
- create_conflict if state.is_a? PossibilityState
- unwind_for_conflict until possibility && state.is_a?(DependencyState)
end
end
# @return [Object] the current possibility that the resolution is trying
@@ -153,63 +273,292 @@ module Gem::Resolver::Molinillo
states.last
end
- # Creates the initial state for the resolution, based upon the
# {#requested} dependencies
- # @return [DependencyState] the initial state for the resolution
- def initial_state
graph = DependencyGraph.new.tap do |dg|
- original_requested.each { |r| dg.add_vertex(name_for(r), nil, true).tap { |v| v.explicit_requirements << r } }
dg.tag(:initial_state)
end
- requirements = sort_dependencies(original_requested, graph, {})
- initial_requirement = requirements.shift
- DependencyState.new(
- initial_requirement && name_for(initial_requirement),
- requirements,
- graph,
- initial_requirement,
- initial_requirement && search_for(initial_requirement),
- 0,
- {}
- )
end
# Unwinds the states stack because a conflict has been encountered
# @return [void]
def unwind_for_conflict
- debug(depth) { "Unwinding for conflict: #{requirement} to #{state_index_for_unwind / 2}" }
conflicts.tap do |c|
- sliced_states = states.slice!((state_index_for_unwind + 1)..-1)
- raise VersionConflict.new(c) unless state
activated.rewind_to(sliced_states.first || :initial_state) if sliced_states
state.conflicts = c
index = states.size - 1
@parents_of.each { |_, a| a.reject! { |i| i >= index } }
end
end
- # @return [Integer] The index to which the resolution should unwind in the
- # case of conflict.
- def state_index_for_unwind
- current_requirement = requirement
- existing_requirement = requirement_for_existing_name(name)
- index = -1
- [current_requirement, existing_requirement].each do |r|
- until r.nil?
- current_state = find_state_for(r)
- if state_any?(current_state)
- current_index = states.index(current_state)
- index = current_index if current_index > index
- break
end
- r = parent_of(r)
end
end
- index
end
# @return [Object] the requirement that led to `requirement` being added
# to the list of requirements.
def parent_of(requirement)
@@ -219,29 +568,27 @@ module Gem::Resolver::Molinillo
parent_state.requirement
end
# @return [Object] the requirement that led to a version of a possibility
# with the given name being activated.
def requirement_for_existing_name(name)
- return nil unless activated.vertex_named(name).payload
states.find { |s| s.name == name }.requirement
end
# @return [ResolutionState] the state whose `requirement` is the given
# `requirement`.
def find_state_for(requirement)
return nil unless requirement
- states.reverse_each.find { |i| requirement == i.requirement && i.is_a?(DependencyState) }
- end
-
- # @return [Boolean] whether or not the given state has any possibilities
- # left.
- def state_any?(state)
- state && state.possibilities.any?
end
# @return [Conflict] a {Conflict} that reflects the failure to activate
# the {#possibility} in conjunction with the current {#state}
- def create_conflict
vertex = activated.vertex_named(name)
locked_requirement = locked_requirement_named(name)
@@ -250,18 +597,21 @@ module Gem::Resolver::Molinillo
requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements
end
requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement
- vertex.incoming_edges.each { |edge| (requirements[edge.origin.payload] ||= []).unshift(edge.requirement) }
activated_by_name = {}
- activated.each { |v| activated_by_name[v.name] = v.payload if v.payload }
conflicts[name] = Conflict.new(
requirement,
requirements,
- vertex.payload,
possibility,
locked_requirement,
requirement_trees,
- activated_by_name
)
end
@@ -272,6 +622,7 @@ module Gem::Resolver::Molinillo
vertex.requirements.map { |r| requirement_tree_for(r) }
end
# @return [Array<Object>] the list of requirements that led to
# `requirement` being required.
def requirement_tree_for(requirement)
@@ -311,116 +662,47 @@ module Gem::Resolver::Molinillo
# @return [void]
def attempt_to_activate
debug(depth) { 'Attempting to activate ' + possibility.to_s }
- existing_node = activated.vertex_named(name)
- if existing_node.payload
- debug(depth) { "Found existing spec (#{existing_node.payload})" }
- attempt_to_activate_existing_spec(existing_node)
else
- attempt_to_activate_new_spec
- end
- end
-
- # Attempts to activate the current {#possibility} (given that it has
- # already been activated)
- # @return [void]
- def attempt_to_activate_existing_spec(existing_node)
- existing_spec = existing_node.payload
- if requirement_satisfied_by?(requirement, activated, existing_spec)
- new_requirements = requirements.dup
- push_state_for_requirements(new_requirements, false)
- else
- return if attempt_to_swap_possibility
- create_conflict
- debug(depth) { "Unsatisfied by existing spec (#{existing_node.payload})" }
- unwind_for_conflict
- end
- end
-
- # Attempts to swp the current {#possibility} with the already-activated
- # spec with the given name
- # @return [Boolean] Whether the possibility was swapped into {#activated}
- def attempt_to_swap_possibility
- activated.tag(:swap)
- vertex = activated.vertex_named(name)
- activated.set_payload(name, possibility)
- if !vertex.requirements.
- all? { |r| requirement_satisfied_by?(r, activated, possibility) } ||
- !new_spec_satisfied?
- activated.rewind_to(:swap)
- return
- end
- fixup_swapped_children(vertex)
- activate_spec
- end
-
- # Ensures there are no orphaned successors to the given {vertex}.
- # @param [DependencyGraph::Vertex] vertex the vertex to fix up.
- # @return [void]
- def fixup_swapped_children(vertex) # rubocop:disable Metrics/CyclomaticComplexity
- payload = vertex.payload
- deps = dependencies_for(payload).group_by(&method(:name_for))
- vertex.outgoing_edges.each do |outgoing_edge|
- requirement = outgoing_edge.requirement
- parent_index = @parents_of[requirement].last
- succ = outgoing_edge.destination
- matching_deps = Array(deps[succ.name])
- dep_matched = matching_deps.include?(requirement)
-
- # only push the current index when it was originally required by the
- # same named spec
- if parent_index && states[parent_index].name == name
- @parents_of[requirement].push(states.size - 1)
end
-
- if matching_deps.empty? && !succ.root? && succ.predecessors.to_a == [vertex]
- debug(depth) { "Removing orphaned spec #{succ.name} after swapping #{name}" }
- succ.requirements.each { |r| @parents_of.delete(r) }
-
- removed_names = activated.detach_vertex_named(succ.name).map(&:name)
- requirements.delete_if do |r|
- # the only removed vertices are those with no other requirements,
- # so it's safe to delete only based upon name here
- removed_names.include?(name_for(r))
- end
- elsif !dep_matched
- debug(depth) { "Removing orphaned dependency #{requirement} after swapping #{name}" }
- # also reset if we're removing the edge, but only if its parent has
- # already been fixed up
- @parents_of[requirement].push(states.size - 1) if @parents_of[requirement].empty?
-
- activated.delete_edge(outgoing_edge)
- requirements.delete(requirement)
end
end
end
- # Attempts to activate the current {#possibility} (given that it hasn't
- # already been activated)
# @return [void]
- def attempt_to_activate_new_spec
- if new_spec_satisfied?
- activate_spec
else
create_conflict
unwind_for_conflict
end
end
- # @return [Boolean] whether the current spec is satisfied as a new
- # possibility.
- def new_spec_satisfied?
- unless requirement_satisfied_by?(requirement, activated, possibility)
- debug(depth) { 'Unsatisfied by requested spec' }
- return false
- end
-
- locked_requirement = locked_requirement_named(name)
-
- locked_spec_satisfied = !locked_requirement ||
- requirement_satisfied_by?(locked_requirement, activated, possibility)
- debug(depth) { 'Unsatisfied by locked spec' } unless locked_spec_satisfied
-
- locked_spec_satisfied
end
# @param [String] requirement_name the spec name to search for
@@ -434,7 +716,7 @@ module Gem::Resolver::Molinillo
# Add the current {#possibility} to the dependency graph of the current
# {#state}
# @return [void]
- def activate_spec
conflicts.delete(name)
debug(depth) { "Activated #{name} at #{possibility}" }
activated.set_payload(name, possibility)
@@ -442,14 +724,14 @@ module Gem::Resolver::Molinillo
end
# Requires the dependencies that the recently activated spec has
- # @param [Object] activated_spec the specification that has just been
# activated
# @return [void]
- def require_nested_dependencies_for(activated_spec)
- nested_dependencies = dependencies_for(activated_spec)
debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" }
nested_dependencies.each do |d|
- activated.add_child_vertex(name_for(d), nil, [name_for(activated_spec)], d)
parent_index = states.size - 1
parents = @parents_of[d]
parents << parent_index if parents.empty?
@@ -461,23 +743,82 @@ module Gem::Resolver::Molinillo
# Pushes a new {DependencyState} that encapsulates both existing and new
# requirements
# @param [Array] new_requirements
# @return [void]
def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated)
new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
- new_requirement = new_requirements.shift
new_name = new_requirement ? name_for(new_requirement) : ''.freeze
- possibilities = new_requirement ? search_for(new_requirement) : []
handle_missing_or_push_dependency_state DependencyState.new(
new_name, new_requirements, new_activated,
- new_requirement, possibilities, depth, conflicts.dup
)
end
# Pushes a new {DependencyState}.
# If the {#specification_provider} says to
# {SpecificationProvider#allow_missing?} that particular requirement, and
# there are no possibilities for that requirement, then `state` is not
- # pushed, and the node in {#activated} is removed, and we continue
# resolving the remaining requirements.
# @param [DependencyState] state
# @return [void]
@@ -1,5 +1,6 @@
# frozen_string_literal: true
-require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph'
module Gem::Resolver::Molinillo
# This class encapsulates a dependency resolver.
@@ -8,7 +9,7 @@ module Gem::Resolver::Molinillo
#
#
class Resolver
- require 'rubygems/resolver/molinillo/lib/molinillo/resolution'
# @return [SpecificationProvider] the specification provider used
# in the resolution process
@@ -1,4 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
# A state that a {Resolution} can be in
# @attr [String] name the name of the current requirement
@@ -7,7 +8,8 @@ module Gem::Resolver::Molinillo
# @attr [Object] requirement the current requirement
# @attr [Object] possibilities the possibilities to satisfy the current requirement
# @attr [Integer] depth the depth of the resolution
- # @attr [Set<Object>] conflicts unresolved conflicts
ResolutionState = Struct.new(
:name,
:requirements,
@@ -15,14 +17,15 @@ module Gem::Resolver::Molinillo
:requirement,
:possibilities,
:depth,
- :conflicts
)
class ResolutionState
# Returns an empty resolution state
# @return [ResolutionState] an empty state
def self.empty
- new(nil, [], DependencyGraph.new, nil, nil, 0, Set.new)
end
end
@@ -40,7 +43,8 @@ module Gem::Resolver::Molinillo
requirement,
[possibilities.pop],
depth + 1,
- conflicts.dup
).tap do |state|
state.activated.tag(state)
end
@@ -104,7 +104,7 @@ class Gem::Resolver::Specification
# Returns true if this specification is installable on this platform.
def installable_platform?
- Gem::Platform.match spec.platform
end
def local? # :nodoc: