Docs header transparent bg

bundle exec

bundle-exec - 在套件的背景下執行指令

bundle exec [--keep-file-descriptors] command

說明

此指令執行指令,讓所有在 Gemfile(5) 中指定的 gem 都可以在 Ruby 程式中使用 require

基本上,如果你通常會執行類似 rspec spec/my_spec.rb 的指令,而且你想要使用在 Gemfile(5) 中指定的 gem,並透過 bundle install(1) 安裝,你應該執行 bundle exec rspec spec/my_spec.rb

請注意,bundle exec 並不要求可執行檔在你的 shell 的 $PATH 中。

選項

--keep-file-descriptors
將所有檔案描述符傳遞給新程序。從 Bundler 版本 2.2.26 開始,預設為 true。將其設定為 false 現在已不建議使用。

Bundle Install --binstubs

如果你在 bundle install(1) 中使用 --binstubs 旗標,Bundler 會自動建立一個目錄(預設為 app_root/bin),其中包含套件中 gem 提供的所有可執行檔。

使用 --binstubs 之後,bin/rspec spec/my_spec.rb 等同於 bundle exec rspec spec/my_spec.rb

環境修改

bundle exec 會對 shell 環境進行多項變更,然後完整執行你指定的指令。

  • 確保即使在由 bundle exec 呼叫的指令中,仍然可以透過 shell 將指令傳遞給 bundle(使用 $BUNDLE_BIN_PATH
  • 將包含套件中可執行檔(例如 railsrspecrackup)的目錄放在 $PATH
  • 確保如果在子 shell 中呼叫 bundler,它會使用相同的 Gemfile(透過設定 BUNDLE_GEMFILE
  • -rbundler/setup 新增到 $RUBYOPT,這可以確保在子 shell 中呼叫的 Ruby 程式可以看到套件中的 gem

它也會修改 Rubygems

  • 不允許載入套件中沒有的其他 gem
  • 修改 gem 方法,如果套件中有符合需求的 gem,則使其成為空操作;如果沒有,則引發 Gem::LoadError
  • 定義 Gem.refresh 為 no-op,因為使用 bundler 時,來源索引始終凍結,且可防止系統中的 gem 洩漏到環境中
  • 覆寫 Gem.bin_path 以使用 bundle 中的 gem,使系統可執行檔正常運作
  • 將 bundle 中的所有 gem 加入 Gem.loaded_specs

最後,如果鎖定檔和 Gemfile 不相符,bundle exec 也會隱式修改 Gemfile.lock。Bundler 需要 Gemfile 來判斷 gem 的群組、autorequire、平台等資訊,而這些資訊並未儲存在鎖定檔中。Gemfile 和鎖定檔必須同步才能順利執行 bundle exec,因此 bundle exec 會事先更新鎖定檔。

載入

預設情況下,當嘗試將 bundle exec 執行到具有 ruby shebang 的檔案時,Bundler 會 Kernel.load 該檔案,而不是使用 Kernel.exec。在絕大多數情況下,這是一種效能提升。在極少數情況下,這可能會造成一些微妙的副作用(例如依賴 $0__FILE__ 的確切內容),且可以透過啟用 disable_exec_load 設定來停用最佳化。

外殼執行

任何開啟子外殼的 Ruby 程式碼(例如 system、反引號或 %x{})都將自動使用目前的 Bundler 環境。如果您需要外殼執行到不屬於目前 bundle 的 Ruby 指令,請使用 with_unbundled_env 方法搭配區塊。在區塊內建立的任何子外殼都將獲得在 Bundler 啟動前存在的環境。例如,Homebrew 指令會執行 Ruby,但無法在 bundle 內執行

Bundler.with_unbundled_env do
  `brew install wget`
end

如果您要外殼執行到不同的 bundle,也需要使用 with_unbundled_env。在子外殼中執行的任何 Bundler 指令都將繼承目前的 Gemfile,因此需要在不同 bundle 的內容中執行的指令也需要使用 with_unbundled_env

Bundler.with_unbundled_env do
  Dir.chdir "/other/bundler/project" do
    `bundle exec ./script`
  end
end

Bundler 提供包裝 systemexec 的便利輔助函式,它們可以使用如下方式

Bundler.clean_system('brew install wget')
Bundler.clean_exec('brew install wget')

Rubygems 外掛程式

目前,Rubygems 外掛程式系統需要在任何已安裝 gem 的載入路徑上放置所有命名為 rubygems_plugin.rb 的檔案,當任何 Ruby 程式碼需要 rubygems.rb 時。這包括安裝到系統中的可執行檔,例如 railsrackuprspec

由於 Rubygems 外掛程式可以包含任意 Ruby 程式碼,因此它們通常會自行啟動或啟動其依賴項。

例如,gemcutter 0.5 寶石依賴 json_pure。如果您已安裝該版本的 gemcutter(即使您安裝了沒有這個問題的更新版本),Rubygems 會啟用 gemcutter 0.5json_pure <latest>

如果您的 Gemfile(5) 也包含 json_pure(或依賴於 json_pure 的寶石),系統上的最新版本可能會與 Gemfile(5) 中的版本或 Gemfile.lock 中的快照版本產生衝突。

如果發生這種情況,bundler 會說

You have already activated json_pure 1.4.6 but your Gemfile
requires json_pure 1.4.3. Consider using bundle exec.

在這種情況下,您幾乎一定會想要移除具有問題的寶石外掛程式的底層寶石。一般來說,這些外掛程式的作者(在本例中為 gemcutter 寶石)已發布了更新版本,在他們的外掛程式中會更加謹慎。

您可以透過執行以下命令來尋找包含寶石外掛程式的寶石清單

ruby -e "puts Gem.find_files('rubygems_plugin.rb')"

至少,您應該移除每個寶石外掛程式的最新版本以外的所有版本,並移除所有您未使用的寶石外掛程式(gem uninstall gem_name)。

在 GitHub 上編輯此文件,如果您發現錯誤或發現遺漏某些內容。