mirror of
https://github.com/ruby/ruby.git
synced 2025-08-27 06:56:13 +02:00
* 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:
parent
cd9f9e4719
commit
47f0248b08
113 changed files with 4964 additions and 2610 deletions
109
lib/rubygems/dependency_resolver/activation_request.rb
Normal file
109
lib/rubygems/dependency_resolver/activation_request.rb
Normal 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
|
||||
|
65
lib/rubygems/dependency_resolver/api_set.rb
Normal file
65
lib/rubygems/dependency_resolver/api_set.rb
Normal 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
|
||||
|
36
lib/rubygems/dependency_resolver/api_specification.rb
Normal file
36
lib/rubygems/dependency_resolver/api_specification.rb
Normal 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
|
||||
|
18
lib/rubygems/dependency_resolver/composed_set.rb
Normal file
18
lib/rubygems/dependency_resolver/composed_set.rb
Normal 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
|
||||
|
16
lib/rubygems/dependency_resolver/current_set.rb
Normal file
16
lib/rubygems/dependency_resolver/current_set.rb
Normal 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
|
||||
|
85
lib/rubygems/dependency_resolver/dependency_conflict.rb
Normal file
85
lib/rubygems/dependency_resolver/dependency_conflict.rb
Normal 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
|
||||
|
51
lib/rubygems/dependency_resolver/dependency_request.rb
Normal file
51
lib/rubygems/dependency_resolver/dependency_request.rb
Normal 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
|
||||
|
59
lib/rubygems/dependency_resolver/index_set.rb
Normal file
59
lib/rubygems/dependency_resolver/index_set.rb
Normal 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
|
||||
|
53
lib/rubygems/dependency_resolver/index_specification.rb
Normal file
53
lib/rubygems/dependency_resolver/index_specification.rb
Normal 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
|
||||
|
38
lib/rubygems/dependency_resolver/installed_specification.rb
Normal file
38
lib/rubygems/dependency_resolver/installed_specification.rb
Normal 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
|
||||
|
130
lib/rubygems/dependency_resolver/installer_set.rb
Normal file
130
lib/rubygems/dependency_resolver/installer_set.rb
Normal 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
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue