こんにちは。フリーランスエンジニアのsawadaです。
最近、Capistranoで遊んでいたら、Bundlerの仕様で色々と気になることが出てきたので、今回調べたことを備忘録としてまとめておこうと思います。
(Capistranoの話より、Bundlerの話がメインです。)
今回、色々と検証した環境は以下の通りです。
まずは、bundle install
についてです。
Capistranoの公式サイトに従って、Capistranoをインストールするのを例にしてみます。
bundle init
でGemfileを作る% bundle init Writing new Gemfile to /path/to/Gemfile % cat Gemfile # frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } # gem "rails"
% vi Gemfile % cat Gemfile # frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } # gem "rails" group :development do gem "capistrano", "~> 3.16", require: false end
bundle install
で必要なGemをインストールする% bundle install Fetching gem metadata from https://rubygems.org/....... Resolving dependencies... Using rake 13.0.3 Fetching net-ssh 6.1.0 Installing net-ssh 6.1.0 Fetching net-scp 3.0.0 Installing net-scp 3.0.0 Fetching sshkit 1.21.2 Installing sshkit 1.21.2 Fetching airbrussh 1.4.0 Installing airbrussh 1.4.0 Using bundler 1.17.2 Using concurrent-ruby 1.1.8 Using i18n 1.8.9 Fetching capistrano 3.16.0 Installing capistrano 3.16.0 Bundle complete! 1 Gemfile dependency, 9 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed.
これでbundle exec cap
が実行できるようになりました。
また、今実行したbundle install
によって、Gemの依存関係を記したGemfile.lockが作成されます。
% cat Gemfile.lock GEM remote: https://rubygems.org/ specs: airbrussh (1.4.0) sshkit (>= 1.6.1, != 1.7.0) capistrano (3.16.0) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) sshkit (>= 1.9.0) concurrent-ruby (1.1.8) i18n (1.8.9) concurrent-ruby (~> 1.0) net-scp (3.0.0) net-ssh (>= 2.6.5, = 1.1.2) net-ssh (>= 2.8.0) PLATFORMS ruby DEPENDENCIES capistrano (~> 3.16) BUNDLED WITH 1.17.2
bundle install
はGemfile.lockがある場合、Gemfileではなく、Gemfile.lockを基に必要なGemをインストールします。
Gemfile.lockにはインストールしたGemのバージョンが記載されているので、このファイルを管理することで、他の人や別の環境でも同じバージョンのGemをインストールすることができます。
以上をまとめるとこのような感じです。
bundle install
はGemfile.lockがある場合は、それを基に必要なGemをインストールし、ない場合はGemfileを基にGemをインストールする。bundle install
を実行すると、その時インストールしたGemのバージョンが書かれたGemfile.lockが作られる。次に、bundle install
によって間違ってインストールしてしまったGemのアンインストール方法を紹介します。
使用するのはbundle exec gem uninstall #{gems}
かgem uninstall #{gems}
です。
Gemをアンインストールする前に、そもそもbundle install
によって、何のGemをインストールしたのかを調べる方法を書いておこうと思います。
インストールされたGemを調べるためにも、Gemのインストールされた場所を確認します。bundle show #{gem}
かgem environment
で確認が可能です。
% bundle show capistrano /path/to/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/capistrano-3.16.0 % gem environment RubyGems Environment: 省略 - GEM PATHS: - /path/to/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0 - /path/to/.gem/ruby/2.6.0 省略
私はGemの更新日時で削除するべきGemかどうかを判断しました。(もっといい方法があるかもしれませんが、、、)
# 3月6日のやつがbundle installで追加でインストールされたやつ % ls -ltr /path/to/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/ | tail | awk '{print $6,$7,$8,$9}' 2 18 00:46 turbolinks-source-5.2.0/ 2 18 00:46 turbolinks-5.2.1/ 2 18 00:46 web-console-4.1.0/ 2 18 00:46 webdrivers-4.5.0/ 2 18 00:46 webpacker-4.3.0/ 3 6 16:26 net-ssh-6.1.0/ 3 6 16:26 net-scp-3.0.0/ 3 6 16:26 sshkit-1.21.2/ 3 6 16:26 airbrussh-1.4.0/ 3 6 16:26 capistrano-3.16.0/
アンインストール対象がわかったらbundle exec gem uninstall #{gems}
でGemをアンインストールしていきます。
ただし、Gemを複数アンインストールする場合は、bundle exec gem uninstall
に対象のGemを配列で渡してあげなければいけません。
これは、bundle exec
が、Gemfileを基に必要なGemがすべて存在するかを確認してから実行されるためです。
1回目のbundle exec gem uninstall
で削除したGemがないことにより、2回目以降のbundle exec gem uninstall
がエラーになります。
# 1回目のアンインストール # バージョンの指定は不要 % bundle exec gem uninstall net-ssh You have requested to uninstall the gem: net-ssh-6.1.0 net-scp-3.0.0 depends on net-ssh (>= 2.6.5, = 2.8.0) If you remove this gem, these dependencies will not be met. Continue with Uninstall? [yN] y Successfully uninstalled net-ssh-6.1.0 # 2回目のアンインストール # 先にアンインストールしたnet-sshがないのでエラーになる % bundle exec gem uninstall net-scp Could not find net-ssh-6.1.0 in any of the sources Run `bundle install` to install missing gems.
% bundle exec gem uninstall net-ssh net-scp You have requested to uninstall the gem: net-scp-3.0.0 sshkit-1.21.2 depends on net-scp (>= 1.1.2) If you remove this gem, these dependencies will not be met. Continue with Uninstall? [yN] y Successfully uninstalled net-scp-3.0.0 You have requested to uninstall the gem: net-ssh-6.1.0 net-scp-3.0.0 depends on net-ssh (>= 2.6.5, = 2.8.0) If you remove this gem, these dependencies will not be met. Continue with Uninstall? [yN] y Successfully uninstalled net-ssh-6.1.0
先に書いた通り、bundle exec gem uninstall
は少し癖があるので、Gemをアンインストールする時はgem uninstall
を使用する方が楽だと思います。
gem uninstall
は連続でGemをアンインストールすることもできるし、配列で複数のGemを一気にアンインストールすることもできます。
# 3ついっぺんに消す % gem uninstall sshkit airbrussh capistrano Remove executables: cap, capify in addition to the gem? [Yn] y Removing cap Removing capify Successfully uninstalled capistrano-3.16.0 Successfully uninstalled airbrussh-1.4.0 Successfully uninstalled sshkit-1.21.2
最後に--without
オプションについて説明します。
bundle install
では--without
オプションを使用することで不要なgroupをインストール対象から外すことが可能です。
# capistranoはdevelopment group % cat Gemfile | grep -A 2 group group :development do gem "capistrano", "~> 3.16", require: false end # --without=developmentを指定するとcapistranoがインストールされない % bundle install --without=development Using bundler 1.17.2 Bundle complete! 1 Gemfile dependency, 1 gem now installed. Gems in the group development were not installed. Use `bundle info [gemname]` to see where a bundled gem is installed.
ちなみに、この--without
オプションは記憶されるため、次にbundle install
を実行した時は--without
オプションがなくても先に指定したgroupのGemをインストールしません。
# --withoutオプションがないが、capistranoはインストールされない % bundle install Using bundler 1.17.2 Bundle complete! 1 Gemfile dependency, 1 gem now installed. Gems in the group development were not installed. Use `bundle info [gemname]` to see where a bundled gem is installed.
記憶されたオプションは/path/to/.bundle/config
に記録されているので、設定を変更したい場合はこのconfigを修正します。
% cat .bundle/config --- BUNDLE_WITHOUT: "development" # configを削除するとcapistranoがインストールできる % rm -f .bundle/config % bundle install Fetching gem metadata from https://rubygems.org/...... Using rake 13.0.3 Fetching net-ssh 6.1.0 Installing net-ssh 6.1.0 Fetching net-scp 3.0.0 Installing net-scp 3.0.0 Fetching sshkit 1.21.2 Installing sshkit 1.21.2 Fetching airbrussh 1.4.0 Installing airbrussh 1.4.0 Using bundler 1.17.2 Using concurrent-ruby 1.1.8 Using i18n 1.8.9 Fetching capistrano 3.16.0 Installing capistrano 3.16.0 Bundle complete! 1 Gemfile dependency, 9 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed.
もしくは--with
オプションでも設定を書き換えることができます。
% cat .bundle/config --- BUNDLE_WITHOUT: "development" # --withオプションを付けるとcapistranoがインストールされる % bundle install --with=development Fetching gem metadata from https://rubygems.org/...... Using rake 13.0.3 Fetching net-ssh 6.1.0 Installing net-ssh 6.1.0 Fetching net-scp 3.0.0 Installing net-scp 3.0.0 Fetching sshkit 1.21.2 Installing sshkit 1.21.2 Fetching airbrussh 1.4.0 Installing airbrussh 1.4.0 Using bundler 1.17.2 Using concurrent-ruby 1.1.8 Using i18n 1.8.9 Fetching capistrano 3.16.0 Installing capistrano 3.16.0 Bundle complete! 1 Gemfile dependency, 9 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. # configの内容も変更されている % cat .bundle/config --- BUNDLE_WITH: "development"
(ここを調べるのに一番時間が掛かったのですが、、、)
bundle check
やbundle exec
を実行するときも.bundle/config
の設定は有効となります。
# capistranoがインストールされていなくても、、、 % bundle show capistrano Could not find gem 'capistrano'. Did you mean capistrano? # BUNDLE_WITHOUTが指定されていれば、bundle checkはエラーにならない。 % cat .bundle/config --- BUNDLE_WITHOUT: "development" % bundle check The Gemfile's dependencies are satisfied
Bundler persists this value in app/.bundle/config so that calls to Bundler.setup do not try to find gems from the Gemfile that you didn’t install.
このエントリーを書くに至った発端は、
–withoutオプションが記憶されるのはわかったけど、bundle checkとかbundle installの時もその設定は使われるの?
と疑問に思ってしまったことでした。
調べてみたら意外と答えが見つからなかったので、同じような疑問を持ってしまった誰かの参考になれば幸いです。
(正直、Bundler使う分には絶対に知らなくていい内容ですねw)