* lib/rubygems: Import RubyGems 2.1

* test/rubygems:  Ditto.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41873 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2013-07-09 23:21:36 +00:00
parent cd9f9e4719
commit 47f0248b08
113 changed files with 4964 additions and 2610 deletions

View file

@ -0,0 +1,109 @@
##
# Specifies a Specification object that should be activated.
# Also contains a dependency that was used to introduce this
# activation.
class Gem::DependencyResolver::ActivationRequest
attr_reader :request
attr_reader :spec
def initialize spec, req, others_possible = true
@spec = spec
@request = req
@others_possible = others_possible
end
def == other
case other
when Gem::Specification
@spec == other
when Gem::DependencyResolver::ActivationRequest
@spec == other.spec && @request == other.request
else
false
end
end
def download path
if @spec.respond_to? :source
source = @spec.source
else
source = Gem.sources.first
end
Gem.ensure_gem_subdirectories path
source.download full_spec, path
end
def full_name
@spec.full_name
end
def full_spec
Gem::Specification === @spec ? @spec : @spec.spec
end
def inspect # :nodoc:
others_possible = nil
others_possible = ' (others possible)' if @others_possible
'#<%s for %p from %s%s>' % [
self.class, @spec, @request, others_possible
]
end
##
# Indicates if the requested gem has already been installed.
def installed?
this_spec = full_spec
Gem::Specification.any? do |s|
s == this_spec
end
end
def name
@spec.name
end
##
# Indicate if this activation is one of a set of possible
# requests for the same Dependency request.
def others_possible?
@others_possible
end
##
# Return the ActivationRequest that contained the dependency
# that we were activated for.
def parent
@request.requester
end
def pretty_print q # :nodoc:
q.group 2, '[Activation request', ']' do
q.breakable
q.pp @spec
q.breakable
q.text ' for '
q.pp @request
q.breakable
q.text ' (other possible)' if @others_possible
end
end
def version
@spec.version
end
end

View file

@ -0,0 +1,65 @@
##
# The global rubygems pool, available via the rubygems.org API.
# Returns instances of APISpecification.
class Gem::DependencyResolver::APISet
def initialize
@data = Hash.new { |h,k| h[k] = [] }
@dep_uri = URI 'https://rubygems.org/api/v1/dependencies'
end
##
# Return an array of APISpecification objects matching
# DependencyRequest +req+.
def find_all req
res = []
versions(req.name).each do |ver|
if req.dependency.match? req.name, ver[:number]
res << Gem::DependencyResolver::APISpecification.new(self, ver)
end
end
res
end
##
# A hint run by the resolver to allow the Set to fetch
# data for DependencyRequests +reqs+.
def prefetch reqs
names = reqs.map { |r| r.dependency.name }
needed = names.find_all { |d| !@data.key?(d) }
return if needed.empty?
uri = @dep_uri + "?gems=#{needed.sort.join ','}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri
Marshal.load(str).each do |ver|
@data[ver[:name]] << ver
end
end
##
# Return data for all versions of the gem +name+.
def versions name
if @data.key?(name)
return @data[name]
end
uri = @dep_uri + "?gems=#{name}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri
Marshal.load(str).each do |ver|
@data[ver[:name]] << ver
end
@data[name]
end
end

View file

@ -0,0 +1,36 @@
##
# Represents a specification retrieved via the rubygems.org
# API. This is used to avoid having to load the full
# Specification object when all we need is the name, version,
# and dependencies.
class Gem::DependencyResolver::APISpecification
attr_reader :dependencies
attr_reader :name
attr_reader :set # :nodoc:
attr_reader :version
def initialize(set, api_data)
@set = set
@name = api_data[:name]
@version = Gem::Version.new api_data[:number]
@dependencies = api_data[:dependencies].map do |name, ver|
Gem::Dependency.new name, ver.split(/\s*,\s*/)
end
end
def == other # :nodoc:
self.class === other and
@set == other.set and
@name == other.name and
@version == other.version and
@dependencies == other.dependencies
end
def full_name
"#{@name}-#{@version}"
end
end

View file

@ -0,0 +1,18 @@
class Gem::DependencyResolver::ComposedSet
def initialize *sets
@sets = sets
end
def find_all req
res = []
@sets.each { |s| res += s.find_all(req) }
res
end
def prefetch reqs
@sets.each { |s| s.prefetch(reqs) }
end
end

View file

@ -0,0 +1,16 @@
##
# A set which represents the installed gems. Respects
# all the normal settings that control where to look
# for installed gems.
class Gem::DependencyResolver::CurrentSet
def find_all req
req.dependency.matching_specs
end
def prefetch gems
end
end

View file

@ -0,0 +1,85 @@
##
# Used internally to indicate that a dependency conflicted
# with a spec that would be activated.
class Gem::DependencyResolver::DependencyConflict
attr_reader :activated
attr_reader :dependency
def initialize(dependency, activated, failed_dep=dependency)
@dependency = dependency
@activated = activated
@failed_dep = failed_dep
end
##
# Return the 2 dependency objects that conflicted
def conflicting_dependencies
[@failed_dep.dependency, @activated.request.dependency]
end
##
# Explanation of the conflict used by exceptions to print useful messages
def explanation
activated = @activated.spec.full_name
requirement = @failed_dep.dependency.requirement
" Activated %s instead of (%s) via:\n %s\n" % [
activated, requirement, request_path.join(', ')
]
end
def for_spec?(spec)
@dependency.name == spec.name
end
def pretty_print q # :nodoc:
q.group 2, '[Dependency conflict: ', ']' do
q.breakable
q.text 'activated '
q.pp @activated
q.breakable
q.text ' dependency '
q.pp @dependency
q.breakable
if @dependency == @failed_dep then
q.text ' failed'
else
q.text ' failed dependency '
q.pp @failed_dep
end
end
end
##
# Path of specifications that requested this dependency
def request_path
current = requester
path = []
while current do
path << current.spec.full_name
current = current.request.requester
end
path
end
##
# Return the Specification that listed the dependency
def requester
@failed_dep.requester
end
end

View file

@ -0,0 +1,51 @@
##
# Used Internally. Wraps a Dependency object to also track which spec
# contained the Dependency.
class Gem::DependencyResolver::DependencyRequest
attr_reader :dependency
attr_reader :requester
def initialize(dep, act)
@dependency = dep
@requester = act
end
def ==(other)
case other
when Gem::Dependency
@dependency == other
when Gem::DependencyResolver::DependencyRequest
@dependency == other.dependency && @requester == other.requester
else
false
end
end
def matches_spec?(spec)
@dependency.matches_spec? spec
end
def name
@dependency.name
end
def pretty_print q # :nodoc:
q.group 2, '[Dependency request ', ']' do
q.breakable
q.text @dependency.to_s
q.breakable
q.text ' requested by '
q.pp @requester
end
end
def to_s # :nodoc:
@dependency.to_s
end
end

View file

@ -0,0 +1,59 @@
##
# The global rubygems pool represented via the traditional
# source index.
class Gem::DependencyResolver::IndexSet
def initialize
@f = Gem::SpecFetcher.fetcher
@all = Hash.new { |h,k| h[k] = [] }
list, = @f.available_specs :released
list.each do |uri, specs|
specs.each do |n|
@all[n.name] << [uri, n]
end
end
@specs = {}
end
##
# Return an array of IndexSpecification objects matching
# DependencyRequest +req+.
def find_all req
res = []
name = req.dependency.name
@all[name].each do |uri, n|
if req.dependency.match? n
res << Gem::DependencyResolver::IndexSpecification.new(
self, n.name, n.version, uri, n.platform)
end
end
res
end
##
# Called from IndexSpecification to get a true Specification
# object.
def load_spec name, ver, source
key = "#{name}-#{ver}"
@specs[key] ||= source.fetch_spec(Gem::NameTuple.new(name, ver))
end
##
# No prefetching needed since we load the whole index in
# initially.
def prefetch gems
end
end

View file

@ -0,0 +1,53 @@
##
# Represents a possible Specification object returned
# from IndexSet. Used to delay needed to download full
# Specification objects when only the +name+ and +version+
# are needed.
class Gem::DependencyResolver::IndexSpecification
attr_reader :name
attr_reader :source
attr_reader :version
def initialize set, name, version, source, plat
@set = set
@name = name
@version = version
@source = source
@platform = plat
@spec = nil
end
def dependencies
spec.dependencies
end
def full_name
"#{@name}-#{@version}"
end
def inspect # :nodoc:
'#<%s %s source %s>' % [self.class, full_name, @source]
end
def pretty_print q # :nodoc:
q.group 2, '[Index specification', ']' do
q.breakable
q.text full_name
q.breakable
q.text ' source '
q.pp @source
end
end
def spec
@spec ||= @set.load_spec(@name, @version, @source)
end
end

View file

@ -0,0 +1,38 @@
class Gem::DependencyResolver::InstalledSpecification
attr_reader :spec
def initialize set, spec, source=nil
@set = set
@source = source
@spec = spec
end
def == other # :nodoc:
self.class === other and
@set == other.set and
@spec == other.spec
end
def dependencies
@spec.dependencies
end
def full_name
"#{@spec.name}-#{@spec.version}"
end
def name
@spec.name
end
def source
@source ||= Gem::Source::Installed.new
end
def version
@spec.version
end
end

View file

@ -0,0 +1,130 @@
class Gem::DependencyResolver::InstallerSet
##
# List of Gem::Specification objects that must always be installed.
attr_reader :always_install
##
# Only install gems in the always_install list
attr_accessor :ignore_dependencies
##
# Do not look in the installed set when finding specifications. This is
# used by the --install-dir option to `gem install`
attr_accessor :ignore_installed
def initialize domain
@domain = domain
@f = Gem::SpecFetcher.fetcher
@all = Hash.new { |h,k| h[k] = [] }
@always_install = []
@ignore_dependencies = false
@ignore_installed = false
@loaded_remote_specs = []
@specs = {}
end
##
# Should local gems should be considered?
def consider_local?
@domain == :both or @domain == :local
end
##
# Should remote gems should be considered?
def consider_remote?
@domain == :both or @domain == :remote
end
##
# Returns an array of IndexSpecification objects matching DependencyRequest
# +req+.
def find_all req
res = []
dep = req.dependency
return res if @ignore_dependencies and
@always_install.none? { |spec| dep.matches_spec? spec }
name = dep.name
dep.matching_specs.each do |gemspec|
next if @always_install.include? gemspec
res << Gem::DependencyResolver::InstalledSpecification.new(self, gemspec)
end unless @ignore_installed
if consider_local? then
local_source = Gem::Source::Local.new
if spec = local_source.find_gem(name, dep.requirement) then
res << Gem::DependencyResolver::IndexSpecification.new(
self, spec.name, spec.version, local_source, spec.platform)
end
end
if consider_remote? then
load_remote_specs dep
@all[name].each do |remote_source, n|
if dep.match? n then
res << Gem::DependencyResolver::IndexSpecification.new(
self, n.name, n.version, remote_source, n.platform)
end
end
end
res
end
def inspect # :nodoc:
'#<%s domain: %s specs: %p>' % [ self.class, @domain, @specs.keys ]
end
##
# Loads remote prerelease specs if +dep+ is a prerelease dependency
def load_remote_specs dep
types = [:released]
types << :prerelease if dep.prerelease?
types.each do |type|
next if @loaded_remote_specs.include? type
@loaded_remote_specs << type
list, = @f.available_specs type
list.each do |uri, specs|
specs.each do |n|
@all[n.name] << [uri, n]
end
end
end
end
##
# Called from IndexSpecification to get a true Specification
# object.
def load_spec name, ver, source
key = "#{name}-#{ver}"
@specs[key] ||= source.fetch_spec Gem::NameTuple.new name, ver
end
##
# No prefetching needed since we load the whole index in initially.
def prefetch(reqs)
end
end