From f7c236892240f8d2960c7404e555cb097625433c Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Sat, 30 Jan 2016 17:23:31 -0600 Subject: [PATCH] [Resolver] Update Molinillo to 0.4.2 --- lib/bundler/vendor/molinillo/lib/molinillo.rb | 4 ++ .../lib/molinillo/dependency_graph.rb | 13 +++++ .../vendor/molinillo/lib/molinillo/errors.rb | 5 ++ .../molinillo/lib/molinillo/gem_metadata.rb | 3 +- .../molinillo/lib/molinillo/modules/ui.rb | 3 +- .../molinillo/lib/molinillo/resolution.rb | 51 ++++++++++++++----- .../molinillo/lib/molinillo/resolver.rb | 3 +- .../vendor/molinillo/lib/molinillo/state.rb | 14 ++--- 8 files changed, 72 insertions(+), 24 deletions(-) diff --git a/lib/bundler/vendor/molinillo/lib/molinillo.rb b/lib/bundler/vendor/molinillo/lib/molinillo.rb index 50af4a912c9..403d7ded6c5 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo.rb @@ -3,3 +3,7 @@ require 'bundler/vendor/molinillo/lib/molinillo/resolver' require 'bundler/vendor/molinillo/lib/molinillo/modules/ui' require 'bundler/vendor/molinillo/lib/molinillo/modules/specification_provider' + +# Bundler::Molinillo is a generic dependency resolution algorithm. +module Bundler::Molinillo +end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb index 655b0ebb970..06e647a7629 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb @@ -14,8 +14,10 @@ def each include TSort + # @visibility private alias_method :tsort_each_node, :each + # @visibility private def tsort_each_child(vertex, &block) vertex.successors.each(&block) end @@ -41,12 +43,14 @@ def self.tsort(vertices) # by {Vertex#name} attr_reader :vertices + # Initializes an empty dependency graph def initialize @vertices = {} end # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices} # are properly copied. + # @param [DependencyGraph] other the graph to copy. def initialize_copy(other) super @vertices = {} @@ -100,6 +104,7 @@ def add_child_vertex(name, payload, parent_names, requirement) vertex end + # Adds a vertex with the given name, or updates the existing one. # @param [String] name # @param [Object] payload # @return [Vertex] the vertex that was added to `self` @@ -121,6 +126,10 @@ def detach_vertex_named(name) v.incoming_edges.delete(e) detach_vertex_named(v.name) unless v.root? || v.predecessors.any? end + vertex.incoming_edges.each do |e| + v = e.origin + v.outgoing_edges.delete(e) + end end # @param [String] name @@ -150,6 +159,8 @@ def add_edge(origin, destination, requirement) private + # Adds a new {Edge} to the dependency graph without checking for + # circularity. def add_edge_no_circular(origin, destination, requirement) edge = Edge.new(origin, destination, requirement) origin.outgoing_edges << edge @@ -174,6 +185,7 @@ class Vertex attr_accessor :root alias_method :root?, :root + # Initializes a vertex with the given name and payload. # @param [String] name see {#name} # @param [Object] payload see {#payload} def initialize(name, payload) @@ -240,6 +252,7 @@ def ==(other) successors.to_set == other.successors.to_set end + # @param [Vertex] other the other vertex to compare to # @return [Boolean] whether the two vertices are equal, determined # solely by {#name} and {#payload} equality def shallow_eql?(other) diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb index b828d0c20d3..f54279e6710 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb @@ -11,6 +11,7 @@ class NoSuchDependencyError < ResolverError # @return [Array] the specifications that depended upon {#dependency} attr_accessor :required_by + # Initializes a new error with the given missing dependency. # @param [Object] dependency @see {#dependency} # @param [Array] required_by @see {#required_by} def initialize(dependency, required_by = []) @@ -19,6 +20,8 @@ def initialize(dependency, required_by = []) super() end + # The error message for the missing dependency, including the specifications + # that had this dependency. def message sources = required_by.map { |r| "`#{r}`" }.join(' and ') message = "Unable to find a specification for `#{dependency}`" @@ -36,6 +39,7 @@ class CircularDependencyError < ResolverError # [Set] the dependencies responsible for causing the error attr_reader :dependencies + # Initializes a new error with the given circular vertices. # @param [Array] nodes the nodes in the dependency # that caused the error def initialize(nodes) @@ -50,6 +54,7 @@ class VersionConflict < ResolverError # 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 = [] diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb index a58ee533148..5c79a2593c0 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb @@ -1,3 +1,4 @@ module Bundler::Molinillo - VERSION = '0.4.0' + # The version of Bundler::Molinillo. + VERSION = '0.4.2'.freeze end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb b/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb index 097c0264ac2..8c1cc391a95 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb @@ -57,7 +57,8 @@ def debug(depth = 0) # # @return [Boolean] def debug? - @debug_mode ||= ENV['MOLINILLO_DEBUG'] + return @debug_mode if defined?(@debug_mode) + @debug_mode = ENV['MOLINILLO_DEBUG'] end end end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb index 51cfa101b1e..e6c1d600d2d 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb @@ -38,6 +38,7 @@ class Resolution # @return [Array] the dependencies that were explicitly required attr_reader :original_requested + # Initializes a new resolution. # @param [SpecificationProvider] specification_provider # see {#specification_provider} # @param [UI] resolver_ui see {#resolver_ui} @@ -340,26 +341,36 @@ def attempt_to_activate_existing_spec(existing_node) # @return [Boolean] Whether the possibility was swapped into {#activated} def attempt_to_swap_possibility swapped = activated.dup - swapped.vertex_named(name).payload = possibility - return unless swapped.vertex_named(name).requirements. + vertex = swapped.vertex_named(name) + vertex.payload = possibility + return unless vertex.requirements. all? { |r| requirement_satisfied_by?(r, swapped, possibility) } - attempt_to_activate_new_spec + return unless new_spec_satisfied? + actual_vertex = activated.vertex_named(name) + actual_vertex.payload = possibility + fixup_swapped_children(actual_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) + payload = vertex.payload + dep_names = dependencies_for(payload).map(&method(:name_for)) + vertex.successors.each do |succ| + if !dep_names.include?(succ.name) && !succ.root? && succ.predecessors.to_a == [vertex] + debug(depth) { "Removing orphaned spec #{succ.name} after swapping #{name}" } + activated.detach_vertex_named(succ.name) + 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 - satisfied = begin - locked_requirement = locked_requirement_named(name) - requested_spec_satisfied = requirement_satisfied_by?(requirement, activated, possibility) - locked_spec_satisfied = !locked_requirement || - requirement_satisfied_by?(locked_requirement, activated, possibility) - debug(depth) { 'Unsatisfied by requested spec' } unless requested_spec_satisfied - debug(depth) { 'Unsatisfied by locked spec' } unless locked_spec_satisfied - requested_spec_satisfied && locked_spec_satisfied - end - if satisfied + if new_spec_satisfied? activate_spec else create_conflict @@ -367,6 +378,18 @@ def attempt_to_activate_new_spec end end + # @return [Boolean] whether the current spec is satisfied as a new + # possibility. + def new_spec_satisfied? + locked_requirement = locked_requirement_named(name) + requested_spec_satisfied = requirement_satisfied_by?(requirement, activated, possibility) + locked_spec_satisfied = !locked_requirement || + requirement_satisfied_by?(locked_requirement, activated, possibility) + debug(depth) { 'Unsatisfied by requested spec' } unless requested_spec_satisfied + debug(depth) { 'Unsatisfied by locked spec' } unless locked_spec_satisfied + requested_spec_satisfied && locked_spec_satisfied + end + # @param [String] requirement_name the spec name to search for # @return [Object] the locked spec named `requirement_name`, if one # is found on {#base} @@ -392,7 +415,7 @@ def activate_spec # @return [void] def require_nested_dependencies_for(activated_spec) nested_dependencies = dependencies_for(activated_spec) - debug(depth) { "Requiring nested dependencies (#{nested_dependencies.map(&:to_s).join(', ')})" } + debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" } nested_dependencies.each { |d| activated.add_child_vertex(name_for(d), nil, [name_for(activated_spec)], d) } push_state_for_requirements(requirements + nested_dependencies, nested_dependencies.size > 0) diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb b/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb index 9a9d8fd1f87..216b74042ee 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb @@ -3,7 +3,7 @@ module Bundler::Molinillo # This class encapsulates a dependency resolver. # The resolver is responsible for determining which set of dependencies to - # activate, with feedback from the the {#specification_provider} + # activate, with feedback from the {#specification_provider} # # class Resolver @@ -17,6 +17,7 @@ class Resolver # during the resolution process attr_reader :resolver_ui + # Initializes a new resolver. # @param [SpecificationProvider] specification_provider # see {#specification_provider} # @param [UI] resolver_ui diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/state.rb b/lib/bundler/vendor/molinillo/lib/molinillo/state.rb index 82744a60707..73cea75983b 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/state.rb @@ -1,12 +1,12 @@ module Bundler::Molinillo # A state that a {Resolution} can be in - # @attr [String] name - # @attr [Array] requirements - # @attr [DependencyGraph] activated - # @attr [Object] requirement - # @attr [Object] possibility - # @attr [Integer] depth - # @attr [Set] conflicts + # @attr [String] name the name of the current requirement + # @attr [Array] requirements currently unsatisfied requirements + # @attr [DependencyGraph] activated the graph of activated dependencies + # @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] conflicts unresolved conflicts ResolutionState = Struct.new( :name, :requirements,