summaryrefslogtreecommitdiff
path: root/lib/rubygems/resolver/installer_set.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/resolver/installer_set.rb')
-rw-r--r--lib/rubygems/resolver/installer_set.rb94
1 files changed, 90 insertions, 4 deletions
diff --git a/lib/rubygems/resolver/installer_set.rb b/lib/rubygems/resolver/installer_set.rb
index 045c893fdc..f53b496dc7 100644
--- a/lib/rubygems/resolver/installer_set.rb
+++ b/lib/rubygems/resolver/installer_set.rb
@@ -21,6 +21,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+.
def initialize domain
@@ -34,11 +39,53 @@ 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?
def consider_local? # :nodoc:
@@ -53,6 +100,13 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
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