class Bundler::Installer
属性
公共类方法
开始 Bundler
的安装过程。 更多信息请参阅此类的 run
方法。
# File bundler/installer.rb, line 20 def self.install(root, definition, options = {}) installer = new(root, definition) Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL_ALL, definition.dependencies) installer.run(options) Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL_ALL, definition.dependencies) installer end
# File bundler/installer.rb, line 28 def initialize(root, definition) @root = root @definition = definition @post_install_messages = {} end
公共实例方法
# File bundler/installer.rb, line 93 def generate_bundler_executable_stubs(spec, options = {}) if options[:binstubs_cmd] && spec.executables.empty? options = {} spec.runtime_dependencies.each do |dep| bins = @definition.specs[dep].first.executables options[dep.name] = bins unless bins.empty? end if options.any? Bundler.ui.warn "#{spec.name} has no executables, but you may want " \ "one from a gem it depends on." options.each {|name, bins| Bundler.ui.warn " #{name} has: #{bins.join(", ")}" } else Bundler.ui.warn "There are no executables for the gem #{spec.name}." end return end # double-assignment to avoid warnings about variables that will be used by ERB bin_path = Bundler.bin_path bin_path = bin_path relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) relative_gemfile_path = relative_gemfile_path ruby_command = Thor::Util.ruby_command ruby_command = ruby_command template_path = File.expand_path("templates/Executable", __dir__) if spec.name == "bundler" template_path += ".bundler" spec.executables = %(bundle) end template = File.read(template_path) exists = [] spec.executables.each do |executable| binstub_path = "#{bin_path}/#{executable}" if File.exist?(binstub_path) && !options[:force] exists << executable next end mode = Gem.win_platform? ? "wb:UTF-8" : "w" require "erb" content = ERB.new(template, trim_mode: "-").result(binding) File.write(binstub_path, content, mode: mode, perm: 0o777 & ~File.umask) if Gem.win_platform? || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{binstub_path}.cmd", prefix + content, mode: mode) end end if options[:binstubs_cmd] && exists.any? case exists.size when 1 Bundler.ui.warn "Skipped #{exists[0]} since it already exists." when 2 Bundler.ui.warn "Skipped #{exists.join(" and ")} since they already exist." else items = exists[0...-1].empty? ? nil : exists[0...-1].join(", ") skipped = [items, exists[-1]].compact.join(" and ") Bundler.ui.warn "Skipped #{skipped} since they already exist." end Bundler.ui.warn "If you want to overwrite skipped stubs, use --force." end end
# File bundler/installer.rb, line 158 def generate_standalone_bundler_executable_stubs(spec, options = {}) # double-assignment to avoid warnings about variables that will be used by ERB bin_path = Bundler.bin_path unless path = Bundler.settings[:path] raise "Can't standalone without an explicit path set" end standalone_path = Bundler.root.join(path).relative_path_from(bin_path) standalone_path = standalone_path template = File.read(File.expand_path("templates/Executable.standalone", __dir__)) ruby_command = Thor::Util.ruby_command ruby_command = ruby_command spec.executables.each do |executable| next if executable == "bundle" executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) executable_path = executable_path mode = Gem.win_platform? ? "wb:UTF-8" : "w" require "erb" content = ERB.new(template, trim_mode: "-").result(binding) File.write("#{bin_path}/#{executable}", content, mode: mode, perm: 0o755) if Gem.win_platform? || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{bin_path}/#{executable}.cmd", prefix + content, mode: mode) end end end
为特定的 Gemfile 运行安装过程。
首先,此方法将检查 `Bundler.bundle_path` 是否存在,如果不存在,则 Bundler
将创建该目录。 这通常与 RubyGems 的位置相同,通常是 `~/.gem` 目录,除非另有指定。
其次,它会检查 Bundler
是否被配置为“冻结”。 冻结确保 Gemfile 和 Gemfile.lock 文件匹配。 这可以防止开发人员可能更新 Gemfile 但可能不运行 `bundle install` 的情况,这会导致 Gemfile.lock 文件没有正确更新。 如果此文件没有正确更新,那么任何其他运行 `bundle install` 的开发人员都可能无法安装正确的 gem。
第三,Bundler
检查 Gemfile 中是否指定了任何依赖项。 如果未指定任何依赖项,则 Bundler
返回一条警告消息,指出此情况,并且此方法返回。
第四,Bundler
检查 Gemfile.lock 是否存在,如果存在,则继续根据 Gemfile 和 Gemfile.lock 设置定义。 在此步骤中,Bundler
还会下载有关 Gemfile.lock 中不存在的任何新 gem 的信息,并在需要时解析任何依赖项。
第五,Bundler
通过 gem 缓存或远程解析依赖项。 然后导致 gem 被安装,以及它们的执行程序的存根,但只有在传递了 –binstubs 选项或之前设置了 Bundler.options 时才会这样。
第六,从已安装的 gem 创建一个新的 Gemfile.lock,以确保下次用户运行 `bundle install` 时,他们将收到此过程中的任何更新。
最后,如果用户指定了 standalone 标志,Bundler
将生成所需的 require 路径并将它们保存在 `setup.rb` 文件中。 有关详细信息,请参阅 `bundle standalone –help`。
# File bundler/installer.rb, line 68 def run(options) Bundler.create_bundle_path ProcessLock.lock do @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment]) if @definition.dependencies.empty? Bundler.ui.warn "The Gemfile specifies no dependencies" lock return end if @definition.setup_domain!(options) ensure_specs_are_compatible! Bundler.load_plugins(@definition) end install(options) Gem::Specification.reset # invalidate gem specification cache so that installed gems are immediately available lock Standalone.new(options[:standalone], @definition).generate if options[:standalone] end end
私有实例方法
# File bundler/installer.rb, line 212 def ensure_specs_are_compatible! @definition.specs.each do |spec| unless spec.matches_current_ruby? raise InstallError, "#{spec.full_name} requires ruby version #{spec.required_ruby_version}, " \ "which is incompatible with the current version, #{Gem.ruby_version}" end unless spec.matches_current_rubygems? raise InstallError, "#{spec.full_name} requires rubygems version #{spec.required_rubygems_version}, " \ "which is incompatible with the current version, #{Gem.rubygems_version}" end end end
解析器提供的顺序很重要,因为依赖项可能会影响 gem 的安装。 也就是说,这种情况很少见(rake 除外),并且并行安装速度快得多。 所以我们允许人们选择加入。
# File bundler/installer.rb, line 193 def install(options) standalone = options[:standalone] force = options[:force] local = options[:local] jobs = installation_parallelization spec_installations = ParallelInstaller.call(self, @definition.specs, jobs, standalone, force, local: local) spec_installations.each do |installation| post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message? end end
# File bundler/installer.rb, line 204 def installation_parallelization if jobs = Bundler.settings[:jobs] return jobs end Bundler.settings.processor_count end
# File bundler/installer.rb, line 225 def lock @definition.lock end