summaryrefslogtreecommitdiff
path: root/lib/rubygems/request_set.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/request_set.rb')
-rw-r--r--lib/rubygems/request_set.rb182
1 files changed, 182 insertions, 0 deletions
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb
new file mode 100644
index 0000000000..6c52b90c40
--- /dev/null
+++ b/lib/rubygems/request_set.rb
@@ -0,0 +1,182 @@
+require 'rubygems'
+require 'rubygems/dependency'
+require 'rubygems/dependency_resolver'
+require 'rubygems/dependency_list'
+require 'rubygems/installer'
+require 'tsort'
+
+module Gem
+ class RequestSet
+
+ include TSort
+
+ def initialize(*deps)
+ @dependencies = deps
+
+ yield self if block_given?
+ end
+
+ attr_reader :dependencies
+
+ # Declare that a gem of name +name+ with +reqs+ requirements
+ # is needed.
+ #
+ def gem(name, *reqs)
+ @dependencies << Gem::Dependency.new(name, reqs)
+ end
+
+ # Add +deps+ Gem::Depedency objects to the set.
+ #
+ def import(deps)
+ @dependencies += deps
+ end
+
+ # Resolve the requested dependencies and return an Array of
+ # Specification objects to be activated.
+ #
+ def resolve(set=nil)
+ r = Gem::DependencyResolver.new(@dependencies, set)
+ @requests = r.resolve
+ end
+
+ # Resolve the requested dependencies against the gems
+ # available via Gem.path and return an Array of Specification
+ # objects to be activated.
+ #
+ def resolve_current
+ resolve DependencyResolver::CurrentSet.new
+ end
+
+ # Load a dependency management file.
+ #
+ def load_gemdeps(path)
+ gf = GemDepedencyAPI.new(self, path)
+ gf.load
+ end
+
+ def specs
+ @specs ||= @requests.map { |r| r.full_spec }
+ end
+
+ def tsort_each_node(&block)
+ @requests.each(&block)
+ end
+
+ def tsort_each_child(node)
+ node.spec.dependencies.each do |dep|
+ next if dep.type == :development
+
+ match = @requests.find { |r| dep.match? r.spec.name, r.spec.version }
+ if match
+ begin
+ yield match
+ rescue TSort::Cyclic
+ end
+ else
+ raise Gem::DependencyError, "Unresolved depedency found during sorting - #{dep}"
+ end
+ end
+ end
+
+ def sorted_requests
+ @sorted ||= strongly_connected_components.flatten
+ end
+
+ def specs_in(dir)
+ Dir["#{dir}/specifications/*.gemspec"].map do |g|
+ Gem::Specification.load g
+ end
+ end
+
+ def install_into(dir, force=true, &b)
+ existing = force ? [] : specs_in(dir)
+
+ dir = File.expand_path dir
+
+ installed = []
+
+ sorted_requests.each do |req|
+ if existing.find { |s| s.full_name == req.spec.full_name }
+ b.call req, nil if b
+ next
+ end
+
+ path = req.download(dir)
+
+ inst = Gem::Installer.new path, :install_dir => dir,
+ :only_install_dir => true
+
+ b.call req, inst if b
+
+ inst.install
+
+ installed << req
+ end
+
+ installed
+ end
+
+ def install(options, &b)
+ if dir = options[:install_dir]
+ return install_into(dir, false, &b)
+ end
+
+ cache_dir = options[:cache_dir] || Gem.dir
+
+ specs = []
+
+ sorted_requests.each do |req|
+ if req.installed?
+ b.call req, nil if b
+ next
+ end
+
+ path = req.download cache_dir
+
+ inst = Gem::Installer.new path, options
+
+ b.call req, inst if b
+
+ specs << inst.install
+ end
+
+ specs
+ end
+
+ # A semi-compatible DSL for Bundler's Gemfile format
+ #
+ class GemDepedencyAPI
+ def initialize(set, path)
+ @set = set
+ @path = path
+ end
+
+ def load
+ instance_eval File.read(@path).untaint, @path, 1
+ end
+
+ # DSL
+
+ def source(url)
+ end
+
+ def gem(name, *reqs)
+ # Ignore the opts for now.
+ reqs.pop if reqs.last.kind_of?(Hash)
+
+ @set.gem name, *reqs
+ end
+
+ def platform(what)
+ if what == :ruby
+ yield
+ end
+ end
+
+ alias_method :platforms, :platform
+
+ def group(*what)
+ end
+ end
+ end
+end