class Gem::RequestSet
A RequestSet
groups a request to activate a set of dependencies.
nokogiri = Gem::Dependency.new 'nokogiri', '~> 1.6' pg = Gem::Dependency.new 'pg', '~> 0.14' set = Gem::RequestSet.new nokogiri, pg requests = set.resolve p requests.map { |r| r.full_name } #=> ["nokogiri-1.6.0", "mini_portile-0.5.1", "pg-0.17.0"]
Attributes
Array of gems to install even if already installed
Set to true if you want to install only direct development dependencies.
Errors fetching gems during resolution.
When true, dependency resolution is not performed, only the requested gems are installed.
If true, allow dependencies to match prerelease gems.
When false no remote sets are used for resolving gems.
Treat missing dependencies as silent errors
The set of source gems imported via load_gemdeps.
Public Class Methods
Creates a RequestSet
for a list of Gem::Dependency
objects, deps
. You can then resolve
and install
the resolved list of dependencies.
nokogiri = Gem::Dependency.new 'nokogiri', '~> 1.6' pg = Gem::Dependency.new 'pg', '~> 0.14' set = Gem::RequestSet.new nokogiri, pg
# File rubygems/request_set.rb, line 94 def initialize(*deps) @dependencies = deps @always_install = [] @conservative = false @dependency_names = {} @development = false @development_shallow = false @errors = [] @git_set = nil @ignore_dependencies = false @install_dir = Gem.dir @prerelease = false @remote = true @requests = [] @sets = [] @soft_missing = false @sorted = nil @specs = nil @vendor_set = nil @source_set = nil yield self if block_given? end
Public Instance Methods
Declare that a gem of name name
with reqs
requirements is needed.
# File rubygems/request_set.rb, line 122 def gem(name, *reqs) if dep = @dependency_names[name] dep.requirement.concat reqs else dep = Gem::Dependency.new name, *reqs @dependency_names[name] = dep @dependencies << dep end end
Add deps
Gem::Dependency
objects to the set.
# File rubygems/request_set.rb, line 135 def import(deps) @dependencies.concat deps end
Installs gems for this RequestSet
using the Gem::Installer
options
.
If a block
is given an activation request
and installer
are yielded. The installer
will be nil
if a gem matching the request was already installed.
# File rubygems/request_set.rb, line 146 def install(options, &block) # :yields: request, installer if dir = options[:install_dir] requests = install_into dir, false, options, &block return requests end @prerelease = options[:prerelease] requests = [] download_queue = Queue.new # Create a thread-safe list of gems to download sorted_requests.each do |req| download_queue << req end # Create N threads in a pool, have them download all the gems threads = Gem.configuration.concurrent_downloads.times.map do # When a thread pops this item, it knows to stop running. The symbol # is queued here so that there will be one symbol per thread. download_queue << :stop Thread.new do # The pop method will block waiting for items, so the only way # to stop a thread from running is to provide a final item that # means the thread should stop. while req = download_queue.pop break if req == :stop req.spec.download options unless req.installed? end end end # Wait for all the downloads to finish before continuing threads.each(&:value) # Install requested gems after they have been downloaded sorted_requests.each do |req| if req.installed? req.spec.spec.build_extensions if @always_install.none? { |spec| spec == req.spec.spec } yield req, nil if block_given? next end end spec = begin req.spec.install options do |installer| yield req, installer if block_given? end rescue Gem::RuntimeRequirementNotMetError => e recent_match = req.spec.set.find_all(req.request).sort_by(&:version).reverse_each.find do |s| s = s.spec s.required_ruby_version.satisfied_by?(Gem.ruby_version) && s.required_rubygems_version.satisfied_by?(Gem.rubygems_version) && Gem::Platform.installable?(s) end if recent_match suggestion = "The last version of #{req.request} to support your Ruby & RubyGems was #{recent_match.version}. Try installing it with `gem install #{recent_match.name} -v #{recent_match.version}`" suggestion += " and then running the current command again" unless @always_install.include?(req.spec.spec) else suggestion = "There are no versions of #{req.request} compatible with your Ruby & RubyGems" suggestion += ". Maybe try installing an older version of the gem you're looking for?" unless @always_install.include?(req.spec.spec) end e.suggestion = suggestion raise end requests << spec end return requests if options[:gemdeps] install_hooks requests, options requests end
Installs from the gem dependencies files in the :gemdeps
option in options
, yielding to the block
as in install
.
If :without_groups
is given in the options
, those groups in the gem dependencies file are not used. See Gem::Installer
for other options
.
# File rubygems/request_set.rb, line 233 def install_from_gemdeps(options, &block) gemdeps = options[:gemdeps] @install_dir = options[:install_dir] || Gem.dir @prerelease = options[:prerelease] @remote = options[:domain] != :local @conservative = true if options[:conservative] gem_deps_api = load_gemdeps gemdeps, options[:without_groups], true resolve if options[:explain] puts "Gems to install:" sorted_requests.each do |spec| puts " #{spec.full_name}" end if Gem.configuration.really_verbose @resolver.stats.display end else installed = install options, &block if options.fetch :lock, true lockfile = Gem::RequestSet::Lockfile.build self, gemdeps, gem_deps_api.dependencies lockfile.write end installed end end
Call hooks on installed gems
# File rubygems/request_set.rb, line 308 def install_hooks(requests, options) specs = requests.map do |request| case request when Gem::Resolver::ActivationRequest then request.spec.spec else request end end require "rubygems/dependency_installer" inst = Gem::DependencyInstaller.new options inst.installed_gems.replace specs Gem.done_installing_hooks.each do |hook| hook.call inst, specs end unless Gem.done_installing_hooks.empty? end
# File rubygems/request_set.rb, line 268 def install_into(dir, force = true, options = {}) gem_home, ENV['GEM_HOME'] = ENV['GEM_HOME'], dir existing = force ? [] : specs_in(dir) existing.delete_if { |s| @always_install.include? s } dir = File.expand_path dir installed = [] options[:development] = false options[:install_dir] = dir options[:only_install_dir] = true @prerelease = options[:prerelease] sorted_requests.each do |request| spec = request.spec if existing.find { |s| s.full_name == spec.full_name } yield request, nil if block_given? next end spec.install options do |installer| yield request, installer if block_given? end installed << request end install_hooks installed, options installed ensure ENV['GEM_HOME'] = gem_home end
Load a dependency management file.
# File rubygems/request_set.rb, line 330 def load_gemdeps(path, without_groups = [], installing = false) @git_set = Gem::Resolver::GitSet.new @vendor_set = Gem::Resolver::VendorSet.new @source_set = Gem::Resolver::SourceSet.new @git_set.root_dir = @install_dir lock_file = "#{File.expand_path(path)}.lock".dup.tap(&Gem::UNTAINT) begin tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file parser = tokenizer.make_parser self, [] parser.parse rescue Errno::ENOENT end gf = Gem::RequestSet::GemDependencyAPI.new self, path gf.installing = installing gf.without_groups = without_groups if without_groups gf.load end
Resolve the requested dependencies and return an Array of Specification objects to be activated.
# File rubygems/request_set.rb, line 397 def resolve(set = Gem::Resolver::BestSet.new) @sets << set @sets << @git_set @sets << @vendor_set @sets << @source_set set = Gem::Resolver.compose_sets(*@sets) set.remote = @remote set.prerelease = @prerelease resolver = Gem::Resolver.new @dependencies, set resolver.development = @development resolver.development_shallow = @development_shallow resolver.ignore_dependencies = @ignore_dependencies resolver.soft_missing = @soft_missing if @conservative installed_gems = {} Gem::Specification.find_all do |spec| (installed_gems[spec.name] ||= []) << spec end resolver.skip_gems = installed_gems end @resolver = resolver @requests = resolver.resolve @errors = set.errors @requests end
Resolve the requested dependencies against the gems available via Gem.path
and return an Array of Specification objects to be activated.
# File rubygems/request_set.rb, line 434 def resolve_current resolve Gem::Resolver::CurrentSet.new end
# File rubygems/request_set.rb, line 438 def sorted_requests @sorted ||= strongly_connected_components.flatten end
# File rubygems/request_set.rb, line 442 def specs @specs ||= @requests.map { |r| r.full_spec } end
# File rubygems/request_set.rb, line 446 def specs_in(dir) Gem::Util.glob_files_in_dir("*.gemspec", File.join(dir, "specifications")).map do |g| Gem::Specification.load g end end