summaryrefslogtreecommitdiff
path: root/lib/rubygems/resolver
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/resolver')
-rw-r--r--lib/rubygems/resolver/api_set.rb49
-rw-r--r--lib/rubygems/resolver/api_specification.rb37
-rw-r--r--lib/rubygems/resolver/composed_set.rb19
-rw-r--r--lib/rubygems/resolver/conflict.rb41
-rw-r--r--lib/rubygems/resolver/git_set.rb33
-rw-r--r--lib/rubygems/resolver/requirement_list.rb4
6 files changed, 144 insertions, 39 deletions
diff --git a/lib/rubygems/resolver/api_set.rb b/lib/rubygems/resolver/api_set.rb
index 60bf911063..89ee3c9b15 100644
--- a/lib/rubygems/resolver/api_set.rb
+++ b/lib/rubygems/resolver/api_set.rb
@@ -10,13 +10,28 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
attr_reader :dep_uri # :nodoc:
##
+ # The Gem::Source that gems are fetched from
+
+ attr_reader :source
+
+ ##
+ # The corresponding place to fetch gems.
+
+ attr_reader :uri
+
+ ##
# Creates a new APISet that will retrieve gems from +uri+ using the RubyGems
- # API described at http://guides.rubygems.org/rubygems-org-api
+ # API URL +dep_uri+ which is described at
+ # http://guides.rubygems.org/rubygems-org-api
+
+ def initialize dep_uri = 'https://rubygems.org/api/v1/dependencies'
+ dep_uri = URI dep_uri unless URI === dep_uri # for ruby 1.8
- def initialize uri = 'https://rubygems.org/api/v1/dependencies'
- uri = URI uri unless URI === uri # for ruby 1.8
- @data = Hash.new { |h,k| h[k] = [] }
- @dep_uri = uri
+ @dep_uri = dep_uri
+ @uri = dep_uri + '../../..'
+
+ @data = Hash.new { |h,k| h[k] = [] }
+ @source = Gem::Source.new @uri
end
##
@@ -41,15 +56,35 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
def prefetch reqs
names = reqs.map { |r| r.dependency.name }
- needed = names.find_all { |d| !@data.key?(d) }
+ needed = names - @data.keys
return if needed.empty?
uri = @dep_uri + "?gems=#{needed.sort.join ','}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri
+ loaded = []
+
Marshal.load(str).each do |ver|
- @data[ver[:name]] << ver
+ name = ver[:name]
+
+ @data[name] << ver
+ loaded << name
+ end
+
+ (needed - loaded).each do |missing|
+ @data[missing] = []
+ end
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, '[APISet', ']' do
+ q.breakable
+ q.text "URI: #{@dep_uri}"
+
+ q.breakable
+ q.text 'gem names:'
+ q.pp @data.keys
end
end
diff --git a/lib/rubygems/resolver/api_specification.rb b/lib/rubygems/resolver/api_specification.rb
index 19611e17d8..0ab8e830c6 100644
--- a/lib/rubygems/resolver/api_specification.rb
+++ b/lib/rubygems/resolver/api_specification.rb
@@ -34,5 +34,42 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
@dependencies == other.dependencies
end
+ def pretty_print q # :nodoc:
+ q.group 2, '[APISpecification', ']' 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 "set uri: #{@set.dep_uri}"
+ end
+ end
+
+ ##
+ # Fetches a Gem::Specification for this APISpecification.
+
+ def spec # :nodoc:
+ @spec ||=
+ begin
+ tuple = Gem::NameTuple.new @name, @version, @platform
+
+ source.fetch_spec tuple
+ end
+ end
+
+ def source # :nodoc:
+ @set.source
+ end
+
end
diff --git a/lib/rubygems/resolver/composed_set.rb b/lib/rubygems/resolver/composed_set.rb
index e4aa15e4d0..702bd9ccfc 100644
--- a/lib/rubygems/resolver/composed_set.rb
+++ b/lib/rubygems/resolver/composed_set.rb
@@ -1,17 +1,36 @@
+##
+# A ComposedSet allows multiple sets to be queried like a single set.
+#
+# To create a composed set with any number of sets use:
+#
+# Gem::Resolver.compose_sets set1, set2
+#
+# This method will eliminate nesting of composed sets.
+
class Gem::Resolver::ComposedSet < Gem::Resolver::Set
attr_reader :sets # :nodoc:
+ ##
+ # Creates a new ComposedSet containing +sets+. Use
+ # Gem::Resolver::compose_sets instead.
+
def initialize *sets
@sets = sets
end
+ ##
+ # Finds all specs matching +req+ in all sets.
+
def find_all req
res = []
@sets.each { |s| res += s.find_all(req) }
res
end
+ ##
+ # Prefetches +reqs+ in all sets.
+
def prefetch reqs
@sets.each { |s| s.prefetch(reqs) }
end
diff --git a/lib/rubygems/resolver/conflict.rb b/lib/rubygems/resolver/conflict.rb
index b081972658..20c6eced31 100644
--- a/lib/rubygems/resolver/conflict.rb
+++ b/lib/rubygems/resolver/conflict.rb
@@ -4,25 +4,38 @@
class Gem::Resolver::Conflict
+ ##
+ # The specification that was activated prior to the conflict
+
attr_reader :activated
+ ##
+ # The dependency that is in conflict with the activated gem.
+
attr_reader :dependency
attr_reader :failed_dep # :nodoc:
+ ##
+ # Creates a new resolver conflict when +dependency+ is in conflict with an
+ # already +activated+ specification.
+
def initialize(dependency, activated, failed_dep=dependency)
@dependency = dependency
@activated = activated
@failed_dep = failed_dep
end
- def == other
+ def == other # :nodoc:
self.class === other and
@dependency == other.dependency and
@activated == other.activated and
@failed_dep == other.failed_dep
end
+ ##
+ # A string explanation of the conflict.
+
def explain
"<Conflict wanted: #{@failed_dep}, had: #{activated.spec.full_name}>"
end
@@ -41,11 +54,15 @@ class Gem::Resolver::Conflict
activated = @activated.spec.full_name
requirement = @failed_dep.dependency.requirement
- " Activated %s instead of (%s) via:\n %s\n" % [
- activated, requirement, request_path.join(', ')
+ " Activated %s via:\n %s\n instead of (%s) via:\n %s\n" % [
+ activated, request_path(@activated).join(', '),
+ requirement, request_path(requester).join(', '),
]
end
+ ##
+ # Returns true if the conflicting dependency's name matches +spec+.
+
def for_spec?(spec)
@dependency.name == spec.name
end
@@ -72,16 +89,17 @@ class Gem::Resolver::Conflict
end
##
- # Path of specifications that requested this dependency
+ # Path of activations from the +current+ list.
- def request_path
- current = requester
- path = []
+ def request_path current
+ path = []
while current do
- path << current.spec.full_name
+ spec_name = current.spec.full_name
+ requirement = current.request.dependency.requirement
+ path << "#{current.spec.full_name} (#{requirement})"
- current = current.request.requester
+ current = current.parent
end
path = ['user request (gem command or Gemfile)'] if path.empty?
@@ -98,5 +116,8 @@ class Gem::Resolver::Conflict
end
-Gem::Resolver::DependencyConflict = Gem::Resolver::Conflict
+##
+# TODO: Remove in RubyGems 3
+
+Gem::Resolver::DependencyConflict = Gem::Resolver::Conflict # :nodoc:
diff --git a/lib/rubygems/resolver/git_set.rb b/lib/rubygems/resolver/git_set.rb
index 3c38d3dca0..c912e367d9 100644
--- a/lib/rubygems/resolver/git_set.rb
+++ b/lib/rubygems/resolver/git_set.rb
@@ -42,38 +42,27 @@ class Gem::Resolver::GitSet < Gem::Resolver::Set
# Finds all git gems matching +req+
def find_all req
- @repositories.keys.select do |name|
- name == req.name
- end.map do |name|
- @specs[name] || load_spec(name)
- end.select do |spec|
+ prefetch nil
+
+ specs.values.select do |spec|
req.matches_spec? spec
end
end
- def load_spec name
- repository, reference = @repositories[name]
-
- source = Gem::Source::Git.new name, repository, reference
-
- spec = source.load_spec name
-
- git_spec =
- Gem::Resolver::GitSpecification.new self, spec, source
-
- @specs[name] = git_spec
- end
-
##
# Prefetches specifications from the git repositories in this set.
def prefetch reqs
- names = reqs.map { |req| req.name }
+ return unless @specs.empty?
+
+ @repositories.each do |name, (repository, reference)|
+ source = Gem::Source::Git.new name, repository, reference
- @repositories.each_key do |name|
- next unless names.include? name
+ source.specs.each do |spec|
+ git_spec = Gem::Resolver::GitSpecification.new self, spec, source
- load_spec name
+ @specs[spec.name] = git_spec
+ end
end
end
diff --git a/lib/rubygems/resolver/requirement_list.rb b/lib/rubygems/resolver/requirement_list.rb
index 8123e84fc7..04e437b2a9 100644
--- a/lib/rubygems/resolver/requirement_list.rb
+++ b/lib/rubygems/resolver/requirement_list.rb
@@ -37,4 +37,8 @@ class Gem::Resolver::RequirementList
def remove
@list.shift
end
+
+ def next5
+ @list[0,5]
+ end
end