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"]
Array
of gems to install even if already installed
Errors fetching gems during resolution.
Set
to true if you want to install only direct development dependencies.
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.
# File tmp/rubies/ruby-3.4.0-preview1/lib/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_requests = nil
@specs = nil
@vendor_set = nil
@source_set = nil
yield self if block_given?
end
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 tmp/rubies/ruby-3.4.0-preview1/lib/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
Declare that a gem of name name
with reqs
requirements is needed.
# File tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 135
def import(deps)
@dependencies.concat deps
end
Add deps
Gem::Dependency
objects to the set.
# File tmp/rubies/ruby-3.4.0-preview1/lib/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 = Thread::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 = Array.new(Gem.configuration.concurrent_downloads) 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
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)
e.suggestion = suggestion
raise
end
requests << spec
end
return requests if options[:gemdeps]
install_hooks requests, options
requests
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 tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 222
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
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 tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 298
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_relative "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
Call hooks on installed gems
# File tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 257
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
# File tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 320
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"
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
Load a dependency management file.
# File tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 387
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 and return an Array
of Specification objects to be activated.
# File tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 424
def resolve_current
resolve Gem::Resolver::CurrentSet.new
end
# File tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 428
def sorted_requests
@sorted_requests ||= strongly_connected_components.flatten
end
# File tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 432
def specs
@specs ||= @requests.map(&:full_spec)
end
# File tmp/rubies/ruby-3.4.0-preview1/lib/rubygems/request_set.rb, line 436
def specs_in(dir)
Gem::Util.glob_files_in_dir("*.gemspec", File.join(dir, "specifications")).map do |g|
Gem::Specification.load g
end
end