class Bundler::Installer

属性

ambiguous_gems[RW]
definition[R]
post_install_messages[R]

公共类方法

install(root, definition, options = {}) 点击以切换源代码

开始 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
new(root, definition) 点击以切换源代码
# File bundler/installer.rb, line 28
def initialize(root, definition)
  @root = root
  @definition = definition
  @post_install_messages = {}
end

公共实例方法

generate_bundler_executable_stubs(spec, options = {}) 点击以切换源代码
# 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
generate_standalone_bundler_executable_stubs(spec, options = {}) 点击以切换源代码
# 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
run(options) 点击以切换源代码

为特定的 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

私有实例方法

ensure_specs_are_compatible!() 点击以切换源代码
# 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
install(options) 点击以切换源代码

解析器提供的顺序很重要,因为依赖项可能会影响 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
installation_parallelization() 点击以切换源代码
# File bundler/installer.rb, line 204
def installation_parallelization
  if jobs = Bundler.settings[:jobs]
    return jobs
  end

  Bundler.settings.processor_count
end
lock() 点击以切换源代码
# File bundler/installer.rb, line 225
def lock
  @definition.lock
end