class Gem::RequestSet
RequestSet
对激活一组依赖项的请求进行分组。
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"]
属性
即使已经安装,也要安装的 gem 的 Array
如果你只想安装直接开发依赖项,则将 Set
设置为 true。
解析期间获取 gem 时发生的错误。
如果为 true,则不执行依赖项解析,只安装请求的 gem。
如果为 true,允许依赖项匹配预发布 gem。
如果为 false,则不使用任何远程集合来解析 gem。
将缺失的依赖项视为静默错误
通过 load_gemdeps 导入的源 gem 集合。
公共类方法
源代码
# File 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
为 Gem::Dependency
对象列表 deps
创建一个 RequestSet
。然后,您可以 resolve
并 install
已解析的依赖项列表。
nokogiri = Gem::Dependency.new 'nokogiri', '~> 1.6' pg = Gem::Dependency.new 'pg', '~> 0.14' set = Gem::RequestSet.new nokogiri, pg
公共实例方法
源代码
# File 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
声明需要一个名为 name
的 gem,其需求为 reqs
。
源代码
# File lib/rubygems/request_set.rb, line 135 def import(deps) @dependencies.concat deps end
将 deps
Gem::Dependency
对象添加到集合中。
源代码
# File 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
使用 Gem::Installer
options
为此 RequestSet
安装 gem。
如果给出了 block
,则会产生一个激活的 request
和 installer
。如果已经安装了与请求匹配的 gem,则 installer
将为 nil
。
源代码
# File 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
从 options
中 :gemdeps
选项中的 gem 依赖项文件安装,并像在 install
中一样传递给 block
。
如果在 options
中给出了 :without_groups
,则不使用 gem 依赖项文件中的那些组。有关其他 options
,请参阅 Gem::Installer
。
源代码
# File 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
在安装的 gem 上调用钩子
源代码
# File 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 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
加载依赖管理文件。
源代码
# File 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
解析请求的依赖项,并返回要激活的 Specification 对象的 Array
。
源代码
源代码
# File lib/rubygems/request_set.rb, line 428 def sorted_requests @sorted_requests ||= strongly_connected_components.flatten end
源代码
# File lib/rubygems/request_set.rb, line 432 def specs @specs ||= @requests.map(&:full_spec) end
源代码
# File 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