1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* lib/rubygems: Update to RubyGems 2.4.1 master(713ab65)

Complete history at:
  https://github.com/rubygems/rubygems/blob/master/History.txt#L3-L216
* test/rubygems:  ditto.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47582 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
hsbt 2014-09-14 03:30:02 +00:00
parent e548c09d42
commit 4de117a615
153 changed files with 5400 additions and 981 deletions

View file

@ -38,6 +38,13 @@ class Gem::Resolver::ActivationRequest
end
end
##
# Is this activation request for a development dependency?
def development?
@request.development?
end
##
# Downloads a gem at +path+ and returns the file path.

View file

@ -34,6 +34,8 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
@data = Hash.new { |h,k| h[k] = [] }
@source = Gem::Source.new @uri
@to_fetch = []
end
##
@ -45,6 +47,10 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
return res unless @remote
if @to_fetch.include?(req.name)
prefetch_now
end
versions(req.name).each do |ver|
if req.dependency.match? req.name, ver[:number]
res << Gem::Resolver::APISpecification.new(self, ver)
@ -61,9 +67,13 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
def prefetch reqs
return unless @remote
names = reqs.map { |r| r.dependency.name }
needed = names - @data.keys
needed = names - @data.keys - @to_fetch
return if needed.empty?
@to_fetch += needed
end
def prefetch_now
needed, @to_fetch = @to_fetch, []
uri = @dep_uri + "?gems=#{needed.sort.join ','}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri

View file

@ -34,6 +34,12 @@ 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
@dependencies = spec.dependencies
end
def installable_platform? # :nodoc:
Gem::Platform.match @platform
end

View file

@ -28,6 +28,10 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
pick_sets if @remote and @sets.empty?
super
rescue Gem::RemoteFetcher::FetchError => e
replace_failed_api_set e
retry
end
def prefetch reqs # :nodoc:
@ -46,5 +50,29 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
end
end
##
# Replaces a failed APISet for the URI in +error+ with an IndexSet.
#
# If no matching APISet can be found the original +error+ is raised.
#
# The calling method must retry the exception to repeat the lookup.
def replace_failed_api_set error # :nodoc:
uri = error.uri
uri = URI uri unless URI === uri
uri.query = nil
raise error unless api_set = @sets.find { |set|
Gem::Resolver::APISet === set and set.dep_uri == uri
}
index_set = Gem::Resolver::IndexSet.new api_set.source
@sets.map! do |set|
next set unless set == api_set
index_set
end
end
end

View file

@ -21,6 +21,18 @@ class Gem::Resolver::ComposedSet < Gem::Resolver::Set
@sets = sets
end
##
# When +allow_prerelease+ is set to +true+ prereleases gems are allowed to
# match dependencies.
def prerelease= allow_prerelease
super
sets.each do |set|
set.prerelease = allow_prerelease
end
end
##
# Sets the remote network access for all composed sets.
@ -30,6 +42,10 @@ class Gem::Resolver::ComposedSet < Gem::Resolver::Set
@sets.each { |set| set.remote = remote }
end
def errors
@errors + @sets.map { |set| set.errors }.flatten
end
##
# Finds all specs matching +req+ in all sets.

View file

@ -52,11 +52,40 @@ class Gem::Resolver::Conflict
def explanation
activated = @activated.spec.full_name
requirement = @failed_dep.dependency.requirement
dependency = @failed_dep.dependency
requirement = dependency.requirement
alternates = dependency.matching_specs.map { |spec| spec.full_name }
" Activated %s via:\n %s\n instead of (%s) via:\n %s\n" % [
activated, request_path(@activated).join(', '),
requirement, request_path(requester).join(', '),
unless alternates.empty? then
matching = <<-MATCHING.chomp
Gems matching %s:
%s
MATCHING
matching = matching % [
dependency,
alternates.join(', '),
]
end
explanation = <<-EXPLANATION
Activated %s
which does not match conflicting dependency (%s)
Conflicting dependency chains:
%s
versus:
%s
%s
EXPLANATION
explanation % [
activated, requirement,
request_path(@activated).reverse.join(", depends on\n "),
request_path(@failed_dep).reverse.join(", depends on\n "),
matching,
]
end
@ -95,10 +124,19 @@ class Gem::Resolver::Conflict
path = []
while current do
requirement = current.request.dependency.requirement
path << "#{current.spec.full_name} (#{requirement})"
case current
when Gem::Resolver::ActivationRequest then
path <<
"#{current.request.dependency}, #{current.spec.version} activated"
current = current.parent
current = current.parent
when Gem::Resolver::DependencyRequest then
path << "#{current.dependency}"
current = current.requester
else
raise Gem::Exception, "[BUG] unknown request class #{current.class}"
end
end
path = ['user request (gem command or Gemfile)'] if path.empty?

View file

@ -35,7 +35,26 @@ class Gem::Resolver::DependencyRequest
end
##
# Does this dependency request match +spec+
# Is this dependency a development dependency?
def development?
@dependency.type == :development
end
##
# Does this dependency request match +spec+?
#
# NOTE: #match? only matches prerelease versions when #dependency is a
# prerelease dependency.
def match? spec, allow_prerelease = false
@dependency.match? spec, nil, allow_prerelease
end
##
# Does this dependency request match +spec+?
#
# NOTE: #matches_spec? matches prerelease versions. See also #match?
def matches_spec?(spec)
@dependency.matches_spec? spec

View file

@ -80,7 +80,7 @@ class Gem::Resolver::GitSet < Gem::Resolver::Set
prefetch nil
specs.values.select do |spec|
req.matches_spec? spec
req.match? spec
end
end

View file

@ -12,11 +12,15 @@ class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification
@source == other.source
end
def add_dependency dependency # :nodoc:
spec.dependencies << dependency
end
##
# Installing a git gem only involves building the extensions and generating
# the executables.
def install options
def install options = {}
require 'rubygems/installer'
installer = Gem::Installer.new '', options
@ -31,5 +35,25 @@ class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification
installer.run_post_install_hooks
end
def pretty_print q # :nodoc:
q.group 2, '[GitSpecification', ']' do
q.breakable
q.text "name: #{name}"
q.breakable
q.text "version: #{version}"
q.breakable
q.text 'dependencies:'
q.breakable
q.pp dependencies
q.breakable
q.text "source:"
q.breakable
q.pp @source
end
end
end

View file

@ -18,7 +18,9 @@ class Gem::Resolver::IndexSet < Gem::Resolver::Set
@all = Hash.new { |h,k| h[k] = [] }
list, = @f.available_specs :released
list, errors = @f.available_specs :complete
@errors.concat errors
list.each do |uri, specs|
specs.each do |n|
@ -41,7 +43,7 @@ class Gem::Resolver::IndexSet < Gem::Resolver::Set
name = req.dependency.name
@all[name].each do |uri, n|
if req.dependency.match? n then
if req.match? n, @prerelease then
res << Gem::Resolver::IndexSpecification.new(
self, n.name, n.version, uri, n.platform)
end

View file

@ -14,7 +14,7 @@ class Gem::Resolver::InstalledSpecification < Gem::Resolver::SpecSpecification
# This is a null install as this specification is already installed.
# +options+ are ignored.
def install options
def install options = {}
yield nil
end
@ -29,6 +29,24 @@ class Gem::Resolver::InstalledSpecification < Gem::Resolver::SpecSpecification
super
end
def pretty_print q # :nodoc:
q.group 2, '[InstalledSpecification', ']' do
q.breakable
q.text "name: #{name}"
q.breakable
q.text "version: #{version}"
q.breakable
q.text "platform: #{platform}"
q.breakable
q.text 'dependencies:'
q.breakable
q.pp spec.dependencies
end
end
##
# The source for this specification

View file

@ -20,6 +20,11 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
attr_accessor :ignore_installed # :nodoc:
##
# The remote_set looks up remote gems for installation.
attr_reader :remote_set # :nodoc:
##
# Creates a new InstallerSet that will look for gems in +domain+.
@ -34,10 +39,52 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
@always_install = []
@ignore_dependencies = false
@ignore_installed = false
@local = {}
@remote_set = Gem::Resolver::BestSet.new
@specs = {}
end
##
# Looks up the latest specification for +dependency+ and adds it to the
# always_install list.
def add_always_install dependency
request = Gem::Resolver::DependencyRequest.new dependency, nil
found = find_all request
found.delete_if { |s|
s.version.prerelease? and not s.local?
} unless dependency.prerelease?
found = found.select do |s|
Gem::Source::SpecificFile === s.source or
Gem::Platform::RUBY == s.platform or
Gem::Platform.local === s.platform
end
if found.empty? then
exc = Gem::UnsatisfiableDependencyError.new request
exc.errors = errors
raise exc
end
newest = found.max_by do |s|
[s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
end
@always_install << newest.spec
end
##
# Adds a local gem requested using +dep_name+ with the given +spec+ that can
# be loaded and installed using the +source+.
def add_local dep_name, spec, source
@local[dep_name] = [spec, source]
end
##
# Should local gems should be considered?
@ -52,6 +99,13 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
@domain == :both or @domain == :remote
end
##
# Errors encountered while resolving gems
def errors
@errors + @remote_set.errors
end
##
# Returns an array of IndexSpecification objects matching DependencyRequest
# +req+.
@ -62,30 +116,53 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
dep = req.dependency
return res if @ignore_dependencies and
@always_install.none? { |spec| dep.matches_spec? spec }
@always_install.none? { |spec| dep.match? spec }
name = dep.name
dep.matching_specs.each do |gemspec|
next if @always_install.include? gemspec
next if @always_install.any? { |spec| spec.name == gemspec.name }
res << Gem::Resolver::InstalledSpecification.new(self, gemspec)
end unless @ignore_installed
if consider_local? then
matching_local = @local.values.select do |spec, _|
req.match? spec
end.map do |spec, source|
Gem::Resolver::LocalSpecification.new self, spec, source
end
res.concat matching_local
local_source = Gem::Source::Local.new
if spec = local_source.find_gem(name, dep.requirement) then
if local_spec = local_source.find_gem(name, dep.requirement) then
res << Gem::Resolver::IndexSpecification.new(
self, spec.name, spec.version, local_source, spec.platform)
self, local_spec.name, local_spec.version,
local_source, local_spec.platform)
end
end
res.delete_if do |spec|
spec.version.prerelease? and not dep.prerelease?
end
res.concat @remote_set.find_all req if consider_remote?
res
end
def prefetch(reqs)
@remote_set.prefetch(reqs)
end
def prerelease= allow_prerelease
super
@remote_set.prerelease = allow_prerelease
end
def inspect # :nodoc:
always_install = @always_install.map { |s| s.full_name }
@ -108,6 +185,15 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
end
end
##
# Has a local gem for +dep_name+ been added to this set?
def local? dep_name # :nodoc:
spec, = @local[dep_name]
spec
end
def pretty_print q # :nodoc:
q.group 2, '[InstallerSet', ']' do
q.breakable

View file

@ -12,5 +12,30 @@ class Gem::Resolver::LocalSpecification < Gem::Resolver::SpecSpecification
super
end
def local? # :nodoc:
true
end
def pretty_print q # :nodoc:
q.group 2, '[LocalSpecification', ']' do
q.breakable
q.text "name: #{name}"
q.breakable
q.text "version: #{version}"
q.breakable
q.text "platform: #{platform}"
q.breakable
q.text 'dependencies:'
q.breakable
q.pp dependencies
q.breakable
q.text "source: #{@source.path}"
end
end
end

View file

@ -6,13 +6,16 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
attr_reader :specs # :nodoc:
##
# Creates a new LockSet from the given +source+
# Creates a new LockSet from the given +sources+
def initialize source
def initialize sources
super()
@source = Gem::Source::Lock.new source
@specs = []
@sources = sources.map do |source|
Gem::Source::Lock.new source
end
@specs = []
end
##
@ -25,13 +28,14 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
def add name, version, platform # :nodoc:
version = Gem::Version.new version
spec =
Gem::Resolver::LockSpecification.new self, name, version, @source,
specs = @sources.map do |source|
Gem::Resolver::LockSpecification.new self, name, version, source,
platform
end
@specs << spec
@specs.concat specs
spec
specs
end
##
@ -40,7 +44,7 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
def find_all req
@specs.select do |spec|
req.matches_spec? spec
req.match? spec
end
end

View file

@ -23,7 +23,7 @@ class Gem::Resolver::LockSpecification < Gem::Resolver::Specification
# This is a null install as a locked specification is considered installed.
# +options+ are ignored.
def install options
def install options = {}
destination = options[:install_dir] || Gem.dir
if File.exist? File.join(destination, 'specifications', spec.spec_name) then
@ -41,10 +41,36 @@ class Gem::Resolver::LockSpecification < Gem::Resolver::Specification
@dependencies << dependency
end
def pretty_print q # :nodoc:
q.group 2, '[LockSpecification', ']' do
q.breakable
q.text "name: #{@name}"
q.breakable
q.text "version: #{@version}"
unless @platform == Gem::Platform::RUBY then
q.breakable
q.text "platform: #{@platform}"
end
unless @dependencies.empty? then
q.breakable
q.text 'dependencies:'
q.breakable
q.pp @dependencies
end
end
end
##
# A specification constructed from the lockfile is returned
def spec
@spec ||= Gem::Specification.find { |spec|
spec.name == @name and spec.version == @version
}
@spec ||= Gem::Specification.new do |s|
s.name = @name
s.version = @version

View file

@ -9,8 +9,20 @@ class Gem::Resolver::Set
attr_accessor :remote
##
# Errors encountered when resolving gems
attr_accessor :errors
##
# When true, allows matching of requests to prerelease gems.
attr_accessor :prerelease
def initialize # :nodoc:
@remote = true
@prerelease = false
@remote = true
@errors = []
end
##

View file

@ -4,8 +4,6 @@
class Gem::Resolver::SpecSpecification < Gem::Resolver::Specification
attr_reader :spec # :nodoc:
##
# A SpecSpecification is created for a +set+ for a Gem::Specification in
# +spec+. The +source+ is either where the +spec+ came from, or should be

View file

@ -30,6 +30,14 @@ class Gem::Resolver::Specification
attr_reader :source
##
# The Gem::Specification for this Resolver::Specification.
#
# Implementers, note that #install updates @spec, so be sure to cache the
# Gem::Specification in @spec when overriding.
attr_reader :spec
##
# The version of the gem for this specification.
@ -47,6 +55,13 @@ class Gem::Resolver::Specification
@version = nil
end
##
# Fetches development dependencies if the source does not provide them by
# default (see APISpecification).
def fetch_development_dependencies # :nodoc:
end
##
# The name and version of the specification.
#
@ -61,8 +76,11 @@ class Gem::Resolver::Specification
# install method yields a Gem::Installer instance, which indicates the
# gem will be installed, or +nil+, which indicates the gem is already
# installed.
#
# After installation #spec is updated to point to the just-installed
# specification.
def install options
def install options = {}
require 'rubygems/installer'
destination = options[:install_dir] || Gem.dir
@ -75,7 +93,7 @@ class Gem::Resolver::Specification
yield installer if block_given?
installer.install
@spec = installer.install
end
##
@ -85,5 +103,8 @@ class Gem::Resolver::Specification
Gem::Platform.match spec.platform
end
def local? # :nodoc:
false
end
end

View file

@ -43,6 +43,8 @@ class Gem::Resolver::VendorSet < Gem::Resolver::Set
@specs[spec.name] = spec
@directories[spec] = directory
spec
end
##
@ -51,7 +53,7 @@ class Gem::Resolver::VendorSet < Gem::Resolver::Set
def find_all req
@specs.values.select do |spec|
req.matches_spec? spec
req.match? spec
end.map do |spec|
source = Gem::Source::Vendor.new @directories[spec]
Gem::Resolver::VendorSpecification.new self, spec, source

View file

@ -16,7 +16,7 @@ class Gem::Resolver::VendorSpecification < Gem::Resolver::SpecSpecification
# This is a null install as this gem was unpacked into a directory.
# +options+ are ignored.
def install options
def install options = {}
yield nil
end