不具合
先日知った以下の件。
この問題は gem update --system
によって default gems としての Bundler を 1.17.3 にすれば回避可能でしょうか?
Ruby 2.6.1 は Ruby 2.5.3 と比較して、メモリ使用量が大きく(数百 MB 単位で)削減される(ケースがある)ことが確認できているため、簡単な Workaround で回避可能であれば個人的には積極的に利用したいところです。
比較
default gems としての Bundler のバージョンと、通常の gem としての Bundler のバージョンの組み合わせについて、実行に問題がなさそうなのかを確認。確認内容があっているのか、あまり自信がない。
Bundler 1.17.3 で作った Gemfile.lock
# | default gems | gem install | ruby -rbundler/setup |
bundle exec ruby -rbundler/setup |
---|---|---|---|---|
A | 1.17.2 | None | 指定バージョンを利用可能 | default gems のものを利用してしまう |
B | 1.17.2 | 1.17.3 | bundler の取り違い | 指定バージョンを利用可能 |
C | 1.17.3 | None | 指定バージョンを利用可能 | 指定バージョンを利用可能 |
D | 1.17.3 | 2.0.1 | 指定バージョンを利用可能 | 指定バージョンを利用可能 |
Bundler 2.0.1 で作った Gemfile.lock
# | default gems | gem install | ruby -rbundler/setup |
bundle exec ruby -rbundler/setup |
---|---|---|---|---|
E | 1.17.2 | None |
bundle install --deployment 不可 |
bundle install --deployment 不可 |
F | 1.17.2 | 2.0.1 | You must use Bundler 2 or greater with this lockfile. |
指定バージョンを利用可能 |
G | 1.17.3 | 2.0.1 | 指定バージョンを利用可能 | 指定バージョンを利用可能 |
補足(1): Bundler 1.17.3 で作った Gemfile.lock
$ bundle -v
Bundler version 1.17.3
$ bundle init
$ echo 'gem "csv", "3.0.3"' >> Gemfile
$ bundle install
$ cat Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
csv (3.0.3)
PLATFORMS
ruby
DEPENDENCIES
csv (= 3.0.3)
BUNDLED WITH
1.17.3
A
$ docker run --rm -it -v(pwd):/mnt centos:7 bash
# yum install -y https://github.com/feedforce/ruby-rpm/releases/download/2.6.1/ruby-2.6.1-1.el7.centos.x86_64.rpm
# ruby -v
ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-linux]
# gem -v
3.0.1
# bundle -v
Bundler version 1.17.2
# gem list bundler
*** LOCAL GEMS ***
bundler (default: 1.17.2)
# cp /mnt/Gemfile* .
# bundle install --deployment
# ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
# bundle exec ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.4
B
$ docker run --rm -it -v(pwd):/mnt centos:7 bash
# yum install -y https://github.com/feedforce/ruby-rpm/releases/download/2.6.1/ruby-2.6.1-1.el7.centos.x86_64.rpm
# gem install bundler -v 1.17.3 --no-document
# bundle -v
Bundler version 1.17.3
# gem list bundler
*** LOCAL GEMS ***
bundler (1.17.3, default: 1.17.2)
# cp /mnt/Gemfile* .
# bundle install --deployment
# ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
Traceback (most recent call last):
9: from /usr/lib64/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
8: from /usr/lib64/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
7: from /usr/lib64/ruby/2.6.0/bundler/setup.rb:10:in `<top (required)>'
6: from /usr/lib64/ruby/gems/2.6.0/gems/bundler-1.17.3/lib/bundler.rb:107:in `setup'
5: from /usr/lib64/ruby/gems/2.6.0/gems/bundler-1.17.3/lib/bundler/runtime.rb:26:in `setup'
4: from /usr/lib64/ruby/gems/2.6.0/gems/bundler-1.17.3/lib/bundler/runtime.rb:26:in `map'
3: from /usr/lib64/ruby/2.6.0/forwardable.rb:230:in `each'
2: from /usr/lib64/ruby/2.6.0/forwardable.rb:230:in `each'
1: from /usr/lib64/ruby/gems/2.6.0/gems/bundler-1.17.3/lib/bundler/runtime.rb:31:in `block in setup'
/usr/lib64/ruby/gems/2.6.0/gems/bundler-1.17.3/lib/bundler/runtime.rb:319:in `check_for_activated_spec!': You have already activated bundler 1.17.3, but your Gemfile requires bundler 1.17.2. Prepending `bundle exec` to your command may solve this. (Gem::LoadError)
# bundle exec ruby -rbundler/setup -e 'puts Bundler::VERSION'
1.17.3
# bundle exec ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
C
$ docker run --rm -it -v(pwd):/mnt centos:7 bash
# yum install -y https://github.com/feedforce/ruby-rpm/releases/download/2.6.1/ruby-2.6.1-1.el7.centos.x86_64.rpm
# gem update --system
# bundle -v
Bundler version 1.17.3
# gem list bundler
*** LOCAL GEMS ***
bundler (default: 1.17.3)
# cp /mnt/Gemfile* .
# bundle install --deployment
# ruby -rbundler/setup -e 'puts Bundler::VERSION'
1.17.3
# ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
# bundle exec ruby -rbundler/setup -e 'puts Bundler::VERSION'
1.17.3
# bundle exec ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
D
$ docker run --rm -it -v(pwd):/mnt centos:7 bash
# yum install -y https://github.com/feedforce/ruby-rpm/releases/download/2.6.1/ruby-2.6.1-1.el7.centos.x86_64.rpm
# gem install bundler --no-document
# gem update --system
# gem -v
3.0.2
# bundle -v
Bundler version 2.0.1
# gem list bundler
*** LOCAL GEMS ***
bundler (2.0.1, default: 1.17.3)
# cp /mnt/Gemfile* .
# bundle install --deployment
# ruby -rbundler/setup -e 'puts Bundler::VERSION'
1.17.3
# ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
# bundle exec ruby -rbundler/setup -e 'puts Bundler::VERSION'
1.17.3
# bundle exec ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
補足: Bundler 2.0.1 で作った Gemfile.lock
$ bundle -v
Bundler version 2.0.1
$ bundle init
$ echo 'gem "csv", "3.0.3"' >> Gemfile
$ bundle install
$ cat Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
csv (3.0.3)
PLATFORMS
ruby
DEPENDENCIES
csv (= 3.0.3)
BUNDLED WITH
2.0.1
E
$ docker run --rm -it -v(pwd):/mnt centos:7 bash
# yum install -y https://github.com/feedforce/ruby-rpm/releases/download/2.6.1/ruby-2.6.1-1.el7.centos.x86_64.rpm
# ruby -v
ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-linux]
# gem -v
3.0.1
# bundle -v
Bundler version 1.17.2
# gem list bundler
*** LOCAL GEMS ***
bundler (default: 1.17.2)
# cp /mnt/Gemfile* .
# bundle install --deployment
Traceback (most recent call last):
2: from /usr/bin/bundle:23:in `<main>'
1: from /usr/lib64/ruby/2.6.0/rubygems.rb:302:in `activate_bin_path'
/usr/lib64/ruby/2.6.0/rubygems.rb:283:in `find_spec_for_exe': Could not find 'bundler' (2.0.1) required by your /Gemfile.lock. (Gem::GemNotFoundException)
To update to the latest version installed on your system, run `bundle update --bundler`.
To install the missing version, run `gem install bundler:2.0.1`
F
$ docker run --rm -it -v(pwd):/mnt centos:7 bash
# yum install -y https://github.com/feedforce/ruby-rpm/releases/download/2.6.1/ruby-2.6.1-1.el7.centos.x86_64.rpm
# gem install bundler -v 2.0.1 --no-document
# bundle -v
Bundler version 2.0.1
# gem list bundler
*** LOCAL GEMS ***
bundler (2.0.1, default: 1.17.2)
# cp /mnt/Gemfile* .
# bundle install --deployment
# ruby -rbundler/setup -e 'puts Bundler::VERSION'
You must use Bundler 2 or greater with this lockfile.
# ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
You must use Bundler 2 or greater with this lockfile.
# bundle exec ruby -rbundler/setup -e 'puts Bundler::VERSION'
2.0.1
# bundle exec ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
G
$ docker run --rm -it -v(pwd):/mnt centos:7 bash
# yum install -y https://github.com/feedforce/ruby-rpm/releases/download/2.6.1/ruby-2.6.1-1.el7.centos.x86_64.rpm
# gem install bundler --no-document
# gem update --system
# gem -v
3.0.2
# bundle -v
Bundler version 2.0.1
# gem list bundler
*** LOCAL GEMS ***
bundler (2.0.1, default: 1.17.3)
# cp /mnt/Gemfile* .
# bundle install --deployment
# ruby -rbundler/setup -e 'puts Bundler::VERSION'
2.0.1
# ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
# bundle exec ruby -rbundler/setup -e 'puts Bundler::VERSION'
2.0.1
# bundle exec ruby -rbundler/setup -rcsv -e 'puts CSV::VERSION'
3.0.3
おまけ
gem install bundler
と gem update --system
の実行順序によって、実行ファイル(ラッパー) bundle
が conflict する様です。
ruby 2.6.1 に対して、 bundler 2.0.1 → gem update --system (=rubygems 3.0.2) の順で入れると問題ないけど、逆にやると bundler 2.0.1 のインストール時にラッパースクリプトが conflict する。
— さく (@sakuro) 2019年2月6日
bundler → rubygems
特に警告が出ることなく、また /usr/bin/bundle
の内容が変わることはなかった。
# gem install bundler --no-document
...
# gem update --system
...
rubygems → bundler
gem update --system
によって /usr/bin/bundle
が更新され、 gem install bundler
で上書きすると Ruby 同梱同等の内容に戻った。
# gem update --system
...
# gem install bundler --no-document
...
bundler's executable "bundle" conflicts with /usr/bin/bundle
Overwrite the executable? [yN] y
...
RPM でインストールした /usr/bin/bundle
#!/usr/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'bundler' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0.a"
str = ARGV.first
if str
str = str.b[/\A_(.*)_\z/, 1]
if str and Gem::Version.correct?(str)
version = str
ARGV.shift
end
end
if Gem.respond_to?(:activate_bin_path)
load Gem.activate_bin_path('bundler', 'bundle', version)
else
gem "bundler", version
load Gem.bin_path("bundler", "bundle", version)
end
gem update --system
で暗黙的に上書きされた /usr/bin/bundle
Bundler の exe/bundle
とほぼ同等。違いは shebang のみ。
#!/usr/bin/ruby
# frozen_string_literal: true
# Exit cleanly from an early interrupt
Signal.trap("INT") do
Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler)
exit 1
end
require "bundler"
# Check if an older version of bundler is installed
$LOAD_PATH.each do |path|
next unless path =~ %r{/bundler-0\.(\d+)} && $1.to_i < 9
err = String.new
err << "Looks like you have a version of bundler that's older than 0.9.\n"
err << "Please remove your old versions.\n"
err << "An easy way to do this is by running `gem cleanup bundler`."
abort(err)
end
require "bundler/friendly_errors"
Bundler.with_friendly_errors do
require "bundler/cli"
# Allow any command to use --help flag to show help for that command
help_flags = %w[--help -h]
help_flag_used = ARGV.any? {|a| help_flags.include? a }
args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV
Bundler::CLI.start(args, :debug => true)
end
gem install bundler
で上書きした /usr/bin/bundle
#!/usr/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'bundler' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0.a"
str = ARGV.first
if str
str = str.b[/\A_(.*)_\z/, 1]
if str and Gem::Version.correct?(str)
version = str
ARGV.shift
end
end
if Gem.respond_to?(:activate_bin_path)
load Gem.activate_bin_path('bundler', 'bundle', version)
else
gem "bundler", version
load Gem.bin_path("bundler", "bundle", version)
end
rbenv install 2.6.1
で作られた versions/2.6.1/bin/bundle
#!/home/koshigoe/.rbenv/versions/2.6.1/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'bundler' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0.a"
str = ARGV.first
if str
str = str.b[/\A_(.*)_\z/, 1]
if str and Gem::Version.correct?(str)
version = str
ARGV.shift
end
end
if Gem.respond_to?(:activate_bin_path)
load Gem.activate_bin_path('bundler', 'bundle', version)
else
gem "bundler", version
load Gem.bin_path("bundler", "bundle", version)
end