aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorhsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-06-18 05:11:55 +0000
committerhsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-06-18 05:11:55 +0000
commit85b29e19a3a95294c54a0204bb94ce31bd7369b7 (patch)
treeb7bf99329ed8c29768f2502d3bd418e57be32268 /lib
parente255ee2321e51eaf05c364c99b4fe7fdf31a503c (diff)
downloadruby-85b29e19a3a95294c54a0204bb94ce31bd7369b7.tar.gz
* lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems
HEAD(2c6d256). It contains to update vendored Molinillo to 0.5.0. https://github.com/rubygems/rubygems/pull/1638 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55441 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/rubygems.rb42
-rw-r--r--lib/rubygems/installer.rb1
-rw-r--r--lib/rubygems/package.rb4
-rw-r--r--lib/rubygems/package/tar_writer.rb26
-rw-r--r--lib/rubygems/remote_fetcher.rb16
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb50
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb80
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb202
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb35
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb58
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb61
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb53
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb114
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb45
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb35
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb123
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb2
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb2
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb109
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/state.rb6
-rw-r--r--lib/rubygems/security/signer.rb2
-rw-r--r--lib/rubygems/specification.rb4
-rw-r--r--lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRoot.pem18
-rw-r--r--lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem21
-rw-r--r--lib/rubygems/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem (renamed from lib/rubygems/ssl_certs/rubygems.org/AddTrustExternalCARoot-2048.pem)0
25 files changed, 853 insertions, 256 deletions
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index e6cc859cbe..b041dd1042 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -154,6 +154,26 @@ module Gem
specifications/default
]
+ ##
+ # Exception classes used in a Gem.read_binary +rescue+ statement. Not all of
+ # these are defined in Ruby 1.8.7, hence the need for this convoluted setup.
+
+ READ_BINARY_ERRORS = begin
+ read_binary_errors = [Errno::EACCES]
+ read_binary_errors << Errno::ENOTSUP if Errno.const_defined?(:ENOTSUP)
+ read_binary_errors
+ end.freeze
+
+ ##
+ # Exception classes used in Gem.write_binary +rescue+ statement. Not all of
+ # these are defined in Ruby 1.8.7.
+
+ WRITE_BINARY_ERRORS = begin
+ write_binary_errors = []
+ write_binary_errors << Errno::ENOTSUP if Errno.const_defined?(:ENOTSUP)
+ write_binary_errors
+ end.freeze
+
@@win_platform = nil
@configuration = nil
@@ -829,7 +849,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
f.flock(File::LOCK_EX)
f.read
end
- rescue Errno::EACCES
+ rescue *READ_BINARY_ERRORS
open path, 'rb' do |f|
f.read
end
@@ -844,6 +864,26 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
+ # Safely write a file in binary mode on all platforms.
+ def self.write_binary(path, data)
+ open(path, 'wb') do |io|
+ begin
+ io.flock(File::LOCK_EX)
+ rescue *WRITE_BINARY_ERRORS
+ end
+ io.write data
+ end
+ rescue Errno::ENOLCK # NFS
+ if Thread.main != Thread.current
+ raise
+ else
+ open(path, 'wb') do |io|
+ io.write data
+ end
+ end
+ end
+
+ ##
# The path to the running Ruby interpreter.
def self.ruby
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 3269179200..6e77185547 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -284,6 +284,7 @@ class Gem::Installer
# Completely remove any previous gem files
FileUtils.rm_rf gem_dir
+ FileUtils.rm_rf spec.extension_dir
FileUtils.mkdir_p gem_dir
diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
index 0d9adba26e..c36e71d800 100644
--- a/lib/rubygems/package.rb
+++ b/lib/rubygems/package.rb
@@ -211,7 +211,9 @@ class Gem::Package
stat = File.lstat file
if stat.symlink?
- tar.add_symlink file, File.readlink(file), stat.mode
+ relative_dir = File.dirname(file).sub("#{Dir.pwd}/", '')
+ target_path = File.join(relative_dir, File.readlink(file))
+ tar.add_symlink file, target_path, stat.mode
end
next unless stat.file?
diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb
index ab0313c9f8..f68b8d4c5e 100644
--- a/lib/rubygems/package/tar_writer.rb
+++ b/lib/rubygems/package/tar_writer.rb
@@ -310,27 +310,21 @@ class Gem::Package::TarWriter
# Splits +name+ into a name and prefix that can fit in the TarHeader
def split_name(name) # :nodoc:
- if name.bytesize > 256
+ if name.bytesize > 256 then
raise Gem::Package::TooLongFileName.new("File \"#{name}\" has a too long path (should be 256 or less)")
end
- if name.bytesize <= 100 then
- prefix = ""
- else
- parts = name.split(/\//)
- newname = parts.pop
- nxt = ""
-
- loop do
- nxt = parts.pop
- break if newname.bytesize + 1 + nxt.bytesize > 100
- newname = nxt + "/" + newname
+ prefix = ''
+ if name.bytesize > 100 then
+ parts = name.split('/', -1) # parts are never empty here
+ name = parts.pop # initially empty for names with a trailing slash ("foo/.../bar/")
+ prefix = parts.join('/') # if empty, then it's impossible to split (parts is empty too)
+ while !parts.empty? && (prefix.bytesize > 155 || name.empty?)
+ name = parts.pop + '/' + name
+ prefix = parts.join('/')
end
- prefix = (parts + [nxt]).join "/"
- name = newname
-
- if name.bytesize > 100
+ if name.bytesize > 100 or prefix.empty? then
raise Gem::Package::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long name (should be 100 or less)")
end
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index a2d8ba45e3..da4db724a1 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -328,20 +328,7 @@ class Gem::RemoteFetcher
end
if update and path
- begin
- open(path, 'wb') do |io|
- io.flock(File::LOCK_EX)
- io.write data
- end
- rescue Errno::ENOLCK # NFS
- if Thread.main != Thread.current
- raise
- else
- open(path, 'wb') do |io|
- io.write data
- end
- end
- end
+ Gem.write_binary(path, data)
end
data
@@ -427,4 +414,3 @@ class Gem::RemoteFetcher
end
end
end
-
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb
new file mode 100644
index 0000000000..1bbc72c1f6
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+module Gem::Resolver::Molinillo
+ # @!visibility private
+ module Delegates
+ # Delegates all {Gem::Resolver::Molinillo::ResolutionState} methods to a `#state` property.
+ module ResolutionState
+ # (see Gem::Resolver::Molinillo::ResolutionState#name)
+ def name
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.name
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#requirements)
+ def requirements
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.requirements
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#activated)
+ def activated
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.activated
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#requirement)
+ def requirement
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.requirement
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#possibilities)
+ def possibilities
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.possibilities
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#depth)
+ def depth
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.depth
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#conflicts)
+ def conflicts
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.conflicts
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb
new file mode 100644
index 0000000000..71903c7e86
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+module Gem::Resolver::Molinillo
+ module Delegates
+ # Delegates all {Gem::Resolver::Molinillo::SpecificationProvider} methods to a
+ # `#specification_provider` property.
+ module SpecificationProvider
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#search_for)
+ def search_for(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.search_for(dependency)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#dependencies_for)
+ def dependencies_for(specification)
+ with_no_such_dependency_error_handling do
+ specification_provider.dependencies_for(specification)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#requirement_satisfied_by?)
+ def requirement_satisfied_by?(requirement, activated, spec)
+ with_no_such_dependency_error_handling do
+ specification_provider.requirement_satisfied_by?(requirement, activated, spec)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for)
+ def name_for(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for(dependency)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for_explicit_dependency_source)
+ def name_for_explicit_dependency_source
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for_explicit_dependency_source
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for_locking_dependency_source)
+ def name_for_locking_dependency_source
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for_locking_dependency_source
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#sort_dependencies)
+ def sort_dependencies(dependencies, activated, conflicts)
+ with_no_such_dependency_error_handling do
+ specification_provider.sort_dependencies(dependencies, activated, conflicts)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#allow_missing?)
+ def allow_missing?(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.allow_missing?(dependency)
+ end
+ end
+
+ private
+
+ # Ensures any raised {NoSuchDependencyError} has its
+ # {NoSuchDependencyError#required_by} set.
+ # @yield
+ def with_no_such_dependency_error_handling
+ yield
+ rescue NoSuchDependencyError => error
+ if state
+ vertex = activated.vertex_named(name_for(error.dependency))
+ error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
+ error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
+ end
+ raise
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb
index 42563664d6..6189a717cd 100644
--- a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb
@@ -2,6 +2,9 @@
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
class DependencyGraph
@@ -10,15 +13,16 @@ module Gem::Resolver::Molinillo
# Enumerates through the vertices of the graph.
# @return [Array<Vertex>] The graph's vertices.
def each
+ return vertices.values.each unless block_given?
vertices.values.each { |v| yield v }
end
include TSort
- # @visibility private
- alias_method :tsort_each_node, :each
+ # @!visibility private
+ alias tsort_each_node each
- # @visibility private
+ # @!visibility private
def tsort_each_child(vertex, &block)
vertex.successors.each(&block)
end
@@ -44,9 +48,27 @@ module Gem::Resolver::Molinillo
# by {Vertex#name}
attr_reader :vertices
+ # @return [Log] the op log for this graph
+ attr_reader :log
+
# Initializes an empty dependency graph
def initialize
@vertices = {}
+ @log = Log.new
+ end
+
+ # Tags the current state of the dependency as the given tag
+ # @param [Object] tag an opaque tag for the current state of the graph
+ # @return [Void]
+ def tag(tag)
+ log.tag(self, tag)
+ end
+
+ # Rewinds the graph to the state tagged as `tag`
+ # @param [Object] tag the tag to rewind to
+ # @return [Void]
+ def rewind_to(tag)
+ log.rewind_to(self, tag)
end
# Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
@@ -55,6 +77,7 @@ module Gem::Resolver::Molinillo
def initialize_copy(other)
super
@vertices = {}
+ @log = other.log.dup
traverse = lambda do |new_v, old_v|
return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
old_v.outgoing_edges.each do |edge|
@@ -75,6 +98,22 @@ module Gem::Resolver::Molinillo
"#{self.class}:#{vertices.values.inspect}"
end
+ # @return [String] Returns a dot format representation of the graph
+ def to_dot
+ dot_vertices = []
+ dot_edges = []
+ vertices.each do |n, v|
+ dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]"
+ v.outgoing_edges.each do |e|
+ dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=\"#{e.requirement}\"]"
+ end
+ end
+ dot_vertices.sort!
+ dot_edges.sort!
+ dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}')
+ 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}
@@ -93,12 +132,9 @@ module Gem::Resolver::Molinillo
# @param [Object] requirement the requirement that is requiring the child
# @return [void]
def add_child_vertex(name, payload, parent_names, requirement)
- vertex = add_vertex(name, payload)
+ root = !parent_names.delete(nil) { true }
+ vertex = add_vertex(name, payload, root)
parent_names.each do |parent_name|
- unless parent_name
- vertex.root = true
- next
- end
parent_node = vertex_named(parent_name)
add_edge(parent_node, vertex, requirement)
end
@@ -110,10 +146,7 @@ module Gem::Resolver::Molinillo
# @param [Object] payload
# @return [Vertex] the vertex that was added to `self`
def add_vertex(name, payload, root = false)
- vertex = vertices[name] ||= Vertex.new(name, payload)
- vertex.payload ||= payload
- vertex.root ||= root
- vertex
+ log.add_vertex(self, name, payload, root)
end
# Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
@@ -121,16 +154,7 @@ module Gem::Resolver::Molinillo
# @param [String] name
# @return [void]
def detach_vertex_named(name)
- return unless vertex = vertices.delete(name)
- vertex.outgoing_edges.each do |e|
- v = e.destination
- 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
+ log.detach_vertex_named(self, name)
end
# @param [String] name
@@ -158,134 +182,22 @@ module Gem::Resolver::Molinillo
add_edge_no_circular(origin, destination, requirement)
end
+ # Sets the payload of the vertex with the given name
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload
+ # @return [Void]
+ def set_payload(name, payload)
+ log.set_payload(self, name, payload)
+ end
+
private
# Adds a new {Edge} to the dependency graph without checking for
# circularity.
+ # @param (see #add_edge)
+ # @return (see #add_edge)
def add_edge_no_circular(origin, destination, requirement)
- edge = Edge.new(origin, destination, requirement)
- origin.outgoing_edges << edge
- destination.incoming_edges << edge
- edge
- end
-
- # A vertex in a {DependencyGraph} that encapsulates a {#name} and a
- # {#payload}
- class Vertex
- # @return [String] the name of the vertex
- attr_accessor :name
-
- # @return [Object] the payload the vertex holds
- attr_accessor :payload
-
- # @return [Arrary<Object>] the explicit requirements that required
- # this vertex
- attr_reader :explicit_requirements
-
- # @return [Boolean] whether the vertex is considered a root 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)
- @name = name
- @payload = payload
- @explicit_requirements = []
- @outgoing_edges = []
- @incoming_edges = []
- end
-
- # @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
- # {Edge#origin}
- attr_accessor :outgoing_edges
-
- # @return [Array<Edge>] the edges of {#graph} that have `self` as their
- # {Edge#destination}
- attr_accessor :incoming_edges
-
- # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
- # `self` as their {Edge#destination}
- def predecessors
- 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}
- def successors
- 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
- "#{self.class}:#{name}(#{payload.inspect})"
- end
-
- # @return [Boolean] whether the two vertices are equal, determined
- # by a recursive traversal of each {Vertex#successors}
- def ==(other)
- shallow_eql?(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)
- other &&
- name == other.name &&
- payload == other.payload
- end
-
- alias_method :eql?, :==
-
- # @return [Fixnum] a hash for the vertex based upon its {#name}
- def hash
- name.hash
- end
-
- # Is there a path from `self` to `other` following edges in the
- # 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_method :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}
- def ancestor?(other)
- other.path_to?(self)
- end
-
- alias_method :is_reachable_from?, :ancestor?
+ log.add_edge_no_circular(self, origin.name, destination.name, requirement)
end
end
end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb
new file mode 100644
index 0000000000..dbf4b0b803
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # An action that modifies a {DependencyGraph} that is reversible.
+ # @abstract
+ class Action
+ # rubocop:disable Lint/UnusedMethodArgument
+
+ # @return [Symbol] The name of the action.
+ def self.name
+ raise 'Abstract'
+ end
+
+ # Performs the action on the given graph.
+ # @param [DependencyGraph] graph the graph to perform the action on.
+ # @return [Void]
+ def up(graph)
+ raise 'Abstract'
+ end
+
+ # Reverses the action on the given graph.
+ # @param [DependencyGraph] graph the graph to reverse the action on.
+ # @return [Void]
+ def down(graph)
+ raise 'Abstract'
+ end
+
+ # @return [Action,Nil] The previous action
+ attr_accessor :previous
+
+ # @return [Action,Nil] The next action
+ attr_accessor :next
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
new file mode 100644
index 0000000000..b2d569ddc9
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#add_edge_no_circular)
+ class AddEdgeNoCircular < Action
+ # @!group Action
+
+ # (see Action.name)
+ def self.name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges << edge
+ edge.destination.incoming_edges << edge
+ edge
+ end
+
+ # (see Action#down)
+ def down(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges.delete(edge)
+ edge.destination.incoming_edges.delete(edge)
+ end
+
+ # @!group AddEdgeNoCircular
+
+ # @return [String] the name of the origin of the edge
+ attr_reader :origin
+
+ # @return [String] the name of the destination of the edge
+ attr_reader :destination
+
+ # @return [Object] the requirement that the edge represents
+ attr_reader :requirement
+
+ # @param [DependencyGraph] graph the graph to find vertices from
+ # @return [Edge] The edge this action adds
+ def make_edge(graph)
+ Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement)
+ end
+
+ # Initialize an action to add an edge to a dependency graph
+ # @param [String] origin the name of the origin of the edge
+ # @param [String] destination the name of the destination of the edge
+ # @param [Object] requirement the requirement that the edge represents
+ def initialize(origin, destination, requirement)
+ @origin = origin
+ @destination = destination
+ @requirement = requirement
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
new file mode 100644
index 0000000000..e8b4278ba4
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#add_vertex)
+ class AddVertex < Action # :nodoc:
+ # @!group Action
+
+ # (see Action.name)
+ def self.name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ if existing = graph.vertices[name]
+ @existing_payload = existing.payload
+ @existing_root = existing.root
+ end
+ vertex = existing || Vertex.new(name, payload)
+ graph.vertices[vertex.name] = vertex
+ vertex.payload ||= payload
+ vertex.root ||= root
+ vertex
+ end
+
+ # (see Action#down)
+ def down(graph)
+ if defined?(@existing_payload)
+ vertex = graph.vertices[name]
+ vertex.payload = @existing_payload
+ vertex.root = @existing_root
+ else
+ graph.vertices.delete(name)
+ end
+ end
+
+ # @!group AddVertex
+
+ # @return [String] the name of the vertex
+ attr_reader :name
+
+ # @return [Object] the payload for the vertex
+ attr_reader :payload
+
+ # @return [Boolean] whether the vertex is root or not
+ attr_reader :root
+
+ # Initialize an action to add a vertex to a dependency graph
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload for the vertex
+ # @param [Boolean] root whether the vertex is root or not
+ def initialize(name, payload, root)
+ @name = name
+ @payload = payload
+ @root = root
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
new file mode 100644
index 0000000000..59ef7d8c09
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#detach_vertex_named
+ class DetachVertexNamed < Action
+ # @!group Action
+
+ # (see Action#name)
+ def self.name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ return unless @vertex = graph.vertices.delete(name)
+ @vertex.outgoing_edges.each do |e|
+ v = e.destination
+ v.incoming_edges.delete(e)
+ graph.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
+
+ # (see Action#down)
+ def down(graph)
+ return unless @vertex
+ graph.vertices[@vertex.name] = @vertex
+ @vertex.outgoing_edges.each do |e|
+ e.destination.incoming_edges << e
+ end
+ @vertex.incoming_edges.each do |e|
+ e.origin.outgoing_edges << e
+ end
+ end
+
+ # @!group DetachVertexNamed
+
+ # @return [String] the name of the vertex to detach
+ attr_reader :name
+
+ # Initialize an action to detach a vertex from a dependency graph
+ # @param [String] name the name of the vertex to detach
+ def initialize(name)
+ @name = name
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb
new file mode 100644
index 0000000000..874c4480e3
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb
@@ -0,0 +1,114 @@
+# 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/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
+ # A log for dependency graph actions
+ class Log
+ # Initializes an empty log
+ def initialize
+ @current_action = @first_action = nil
+ end
+
+ # @!macro [new] action
+ # {include:DependencyGraph#$0}
+ # @param [Graph] graph the graph to perform the action on
+ # @param (see DependencyGraph#$0)
+ # @return (see DependencyGraph#$0)
+
+ # @macro action
+ def tag(graph, tag)
+ push_action(graph, Tag.new(tag))
+ end
+
+ # @macro action
+ def add_vertex(graph, name, payload, root)
+ push_action(graph, AddVertex.new(name, payload, root))
+ end
+
+ # @macro action
+ def detach_vertex_named(graph, name)
+ push_action(graph, DetachVertexNamed.new(name))
+ end
+
+ # @macro action
+ def add_edge_no_circular(graph, origin, destination, requirement)
+ push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement))
+ end
+
+ # @macro action
+ def set_payload(graph, name, payload)
+ push_action(graph, SetPayload.new(name, payload))
+ end
+
+ # Pops the most recent action from the log and undoes the action
+ # @param [DependencyGraph] graph
+ # @return [Action] the action that was popped off the log
+ def pop!(graph)
+ return unless action = @current_action
+ unless @current_action = action.previous
+ @first_action = nil
+ end
+ action.down(graph)
+ action
+ end
+
+ extend Enumerable
+
+ # @!visibility private
+ # Enumerates each action in the log
+ # @yield [Action]
+ def each
+ return enum_for unless block_given?
+ action = @first_action
+ loop do
+ break unless action
+ yield action
+ action = action.next
+ end
+ self
+ end
+
+ # @!visibility private
+ # Enumerates each action in the log in reverse order
+ # @yield [Action]
+ def reverse_each
+ return enum_for(:reverse_each) unless block_given?
+ action = @current_action
+ loop do
+ break unless action
+ yield action
+ action = action.previous
+ end
+ self
+ end
+
+ # @macro action
+ def rewind_to(graph, tag)
+ loop do
+ action = pop!(graph)
+ raise "No tag #{tag.inspect} found" unless action
+ break if action.class.name == :tag && action.tag == tag
+ end
+ end
+
+ private
+
+ # Adds the given action to the log, running the action
+ # @param [DependencyGraph] graph
+ # @param [Action] action
+ # @return The value returned by `action.up`
+ def push_action(graph, action)
+ action.previous = @current_action
+ @current_action.next = action if @current_action
+ @current_action = action
+ @first_action ||= action
+ action.up(graph)
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb
new file mode 100644
index 0000000000..633bc64601
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#set_payload
+ class SetPayload < Action # :nodoc:
+ # @!group Action
+
+ # (see Action.name)
+ def self.name
+ :set_payload
+ end
+
+ # (see Action#up)
+ def up(graph)
+ vertex = graph.vertex_named(name)
+ @old_payload = vertex.payload
+ vertex.payload = payload
+ end
+
+ # (see Action#down)
+ def down(graph)
+ graph.vertex_named(name).payload = @old_payload
+ end
+
+ # @!group SetPayload
+
+ # @return [String] the name of the vertex
+ attr_reader :name
+
+ # @return [Object] the payload for the vertex
+ attr_reader :payload
+
+ # Initialize an action to add set the payload for a vertex in a dependency
+ # graph
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload for the vertex
+ def initialize(name, payload)
+ @name = name
+ @payload = payload
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb
new file mode 100644
index 0000000000..808cd6a3d8
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#tag
+ class Tag < Action
+ # @!group Action
+
+ # (see Action.name)
+ def self.name
+ :tag
+ end
+
+ # (see Action#up)
+ def up(_graph)
+ end
+
+ # (see Action#down)
+ def down(_graph)
+ end
+
+ # @!group Tag
+
+ # @return [Object] An opaque tag
+ attr_reader :tag
+
+ # Initialize an action to tag a state of a dependency graph
+ # @param [Object] tag an opaque tag
+ def initialize(tag)
+ @tag = tag
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb
new file mode 100644
index 0000000000..88d109c94f
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # A vertex in a {DependencyGraph} that encapsulates a {#name} and a
+ # {#payload}
+ class Vertex
+ # @return [String] the name of the vertex
+ attr_accessor :name
+
+ # @return [Object] the payload the vertex holds
+ attr_accessor :payload
+
+ # @return [Arrary<Object>] the explicit requirements that required
+ # this vertex
+ attr_reader :explicit_requirements
+
+ # @return [Boolean] whether the vertex is considered a root vertex
+ attr_accessor :root
+ alias 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)
+ @name = name.frozen? ? name : name.dup.freeze
+ @payload = payload
+ @explicit_requirements = []
+ @outgoing_edges = []
+ @incoming_edges = []
+ end
+
+ # @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
+ # {Edge#origin}
+ attr_accessor :outgoing_edges
+
+ # @return [Array<Edge>] the edges of {#graph} that have `self` as their
+ # {Edge#destination}
+ attr_accessor :incoming_edges
+
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
+ # `self` as their {Edge#destination}
+ def predecessors
+ 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}
+ def successors
+ 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
+ "#{self.class}:#{name}(#{payload.inspect})"
+ end
+
+ # @return [Boolean] whether the two vertices are equal, determined
+ # by a recursive traversal of each {Vertex#successors}
+ def ==(other)
+ shallow_eql?(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)
+ other &&
+ name == other.name &&
+ payload == other.payload
+ end
+
+ alias eql? ==
+
+ # @return [Fixnum] a hash for the vertex based upon its {#name}
+ def hash
+ name.hash
+ end
+
+ # Is there a path from `self` to `other` following edges in the
+ # 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}
+ def ancestor?(other)
+ other.path_to?(self)
+ end
+
+ alias is_reachable_from? ancestor?
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
index 3fad948392..129246bf4a 100644
--- a/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
@@ -26,7 +26,7 @@ module Gem::Resolver::Molinillo
def message
sources = required_by.map { |r| "`#{r}`" }.join(' and ')
message = "Unable to find a specification for `#{dependency}`"
- message << " depended upon by #{sources}" unless sources.empty?
+ message += " depended upon by #{sources}" unless sources.empty?
message
end
end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb
index 1b66500f0f..1a82da0e7a 100644
--- a/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Gem::Resolver::Molinillo
# The version of Gem::Resolver::Molinillo.
- VERSION = '0.4.3'.freeze
+ VERSION = '0.5.0'.freeze
end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
index 2fc18843fe..1fb7a1e921 100644
--- a/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
@@ -52,6 +52,7 @@ module Gem::Resolver::Molinillo
@base = base
@states = []
@iteration_counter = 0
+ @parent_of = {}
end
# Resolves the {#original_requested} dependencies into a full dependency
@@ -67,7 +68,12 @@ module Gem::Resolver::Molinillo
indicate_progress
if state.respond_to?(:pop_possibility_state) # DependencyState
debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
- state.pop_possibility_state.tap { |s| states.push(s) if s }
+ state.pop_possibility_state.tap do |s|
+ if s
+ states.push(s)
+ activated.tag(s)
+ end
+ end
end
process_topmost_state
end
@@ -118,27 +124,11 @@ module Gem::Resolver::Molinillo
require 'rubygems/resolver/molinillo/lib/molinillo/state'
require 'rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider'
- ResolutionState.new.members.each do |member|
- define_method member do |*args, &block|
- current_state = state || ResolutionState.empty
- current_state.send(member, *args, &block)
- end
- end
+ require 'rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state'
+ require 'rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider'
- SpecificationProvider.instance_methods(false).each do |instance_method|
- define_method instance_method do |*args, &block|
- begin
- specification_provider.send(instance_method, *args, &block)
- rescue NoSuchDependencyError => error
- if state
- vertex = activated.vertex_named(name_for error.dependency)
- error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
- error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
- end
- raise
- end
- end
- end
+ include Gem::Resolver::Molinillo::Delegates::ResolutionState
+ include Gem::Resolver::Molinillo::Delegates::SpecificationProvider
# Processes the topmost available {RequirementState} on the stack
# @return [void]
@@ -169,6 +159,7 @@ module Gem::Resolver::Molinillo
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, {})
@@ -189,8 +180,9 @@ module Gem::Resolver::Molinillo
def unwind_for_conflict
debug(depth) { "Unwinding for conflict: #{requirement}" }
conflicts.tap do |c|
- states.slice!((state_index_for_unwind + 1)..-1)
+ 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
end
end
@@ -217,20 +209,14 @@ module Gem::Resolver::Molinillo
# @return [Object] the requirement that led to `requirement` being added
# to the list of requirements.
def parent_of(requirement)
- return nil unless requirement
- seen = false
- state = states.reverse_each.find do |s|
- seen ||= s.requirement == requirement || s.requirements.include?(requirement)
- seen && s.requirement != requirement && !s.requirements.include?(requirement)
- end
- state && state.requirement
+ @parent_of[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.reverse_each.find { |s| !s.activated.vertex_named(name).payload }.requirement
+ states.find { |s| s.name == name }.requirement
end
# @return [ResolutionState] the state whose `requirement` is the given
@@ -250,19 +236,25 @@ module Gem::Resolver::Molinillo
# the {#possibility} in conjunction with the current {#state}
def create_conflict
vertex = activated.vertex_named(name)
- requirements = {
- name_for_explicit_dependency_source => vertex.explicit_requirements,
- name_for_locking_dependency_source => Array(locked_requirement_named(name)),
- }
+ locked_requirement = locked_requirement_named(name)
+
+ requirements = {}
+ unless vertex.explicit_requirements.empty?
+ 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,
- Hash[requirements.select { |_, r| !r.empty? }],
+ requirements,
vertex.payload,
possibility,
- locked_requirement_named(name),
+ locked_requirement,
requirement_trees,
- Hash[activated.map { |v| [v.name, v.payload] }.select(&:last)]
+ activated_by_name
)
end
@@ -341,15 +333,16 @@ module Gem::Resolver::Molinillo
# spec with the given name
# @return [Boolean] Whether the possibility was swapped into {#activated}
def attempt_to_swap_possibility
- swapped = activated.dup
- vertex = swapped.vertex_named(name)
- vertex.payload = possibility
- return unless vertex.requirements.
- all? { |r| requirement_satisfied_by?(r, swapped, possibility) }
- return unless new_spec_satisfied?
- actual_vertex = activated.vertex_named(name)
- actual_vertex.payload = possibility
- fixup_swapped_children(actual_vertex)
+ 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
@@ -363,7 +356,13 @@ module Gem::Resolver::Molinillo
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)
- requirements.delete_if { |r| name_for(r) == succ.name }
+
+ all_successor_names = succ.recursive_successors.map(&:name)
+
+ requirements.delete_if do |requirement|
+ requirement_name = name_for(requirement)
+ (requirement_name == succ.name) || all_successor_names.include?(requirement_name)
+ end
end
end
end
@@ -406,8 +405,7 @@ module Gem::Resolver::Molinillo
def activate_spec
conflicts.delete(name)
debug(depth) { 'Activated ' + name + ' at ' + possibility.to_s }
- vertex = activated.vertex_named(name)
- vertex.payload = possibility
+ activated.set_payload(name, possibility)
require_nested_dependencies_for(possibility)
end
@@ -418,19 +416,22 @@ module Gem::Resolver::Molinillo
def require_nested_dependencies_for(activated_spec)
nested_dependencies = dependencies_for(activated_spec)
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) }
+ nested_dependencies.each do |d|
+ activated.add_child_vertex(name_for(d), nil, [name_for(activated_spec)], d)
+ @parent_of[d] = requirement
+ end
- push_state_for_requirements(requirements + nested_dependencies, nested_dependencies.size > 0)
+ push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?)
end
# 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.dup)
+ 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) : ''
+ 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,
@@ -451,7 +452,7 @@ module Gem::Resolver::Molinillo
state.activated.detach_vertex_named(state.name)
push_state_for_requirements(state.requirements.dup, false, state.activated)
else
- states.push state
+ states.push(state).tap { activated.tag(state) }
end
end
end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
index ac25538a5a..c20de98854 100644
--- a/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
@@ -36,12 +36,14 @@ module Gem::Resolver::Molinillo
PossibilityState.new(
name,
requirements.dup,
- activated.dup,
+ activated,
requirement,
[possibilities.pop],
depth + 1,
conflicts.dup
- )
+ ).tap do |state|
+ state.activated.tag(state)
+ end
end
end
diff --git a/lib/rubygems/security/signer.rb b/lib/rubygems/security/signer.rb
index 1c9d9b7d3b..0c6ef60a9a 100644
--- a/lib/rubygems/security/signer.rb
+++ b/lib/rubygems/security/signer.rb
@@ -102,6 +102,8 @@ class Gem::Security::Signer
def sign data
return unless @key
+ raise Gem::Security::Exception, 'no certs provided' if @cert_chain.empty?
+
if @cert_chain.length == 1 and @cert_chain.last.not_after < Time.now then
re_sign_key
end
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index c50ff31fdb..bb912ce24c 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -209,9 +209,9 @@ class Gem::Specification < Gem::BasicSpecification
##
# Paths in the gem to add to <code>$LOAD_PATH</code> when this gem is
# activated.
- #
+ #--
# See also #require_paths
- #
+ #++
# If you have an extension you do not need to add <code>"ext"</code> to the
# require path, the extension build process will copy the extension files
# into "lib" for you.
diff --git a/lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRoot.pem b/lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRoot.pem
deleted file mode 100644
index 471f3c553b..0000000000
--- a/lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRoot.pem
+++ /dev/null
@@ -1,18 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
-GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
-b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
-BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
-VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
-DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
-THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
-Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
-c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
-gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
-AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
-Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
-j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
-hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
-X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
------END CERTIFICATE----- \ No newline at end of file
diff --git a/lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem b/lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem
new file mode 100644
index 0000000000..f4ce4ca43d
--- /dev/null
+++ b/lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
diff --git a/lib/rubygems/ssl_certs/rubygems.org/AddTrustExternalCARoot-2048.pem b/lib/rubygems/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem
index 20585f1c01..20585f1c01 100644
--- a/lib/rubygems/ssl_certs/rubygems.org/AddTrustExternalCARoot-2048.pem
+++ b/lib/rubygems/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem