0
0

自前サーバーで提供する gem がある場合の Bundler の不可解な動作

Posted at

Bundler の動作が不可解な点について。

再現条件がよく分からないが,一つはっきりしている条件は,Gemfile で指定する gem の中に「rubygems.org 以外のサーバーで提供するもの」が含まれる,という点だ。

以下の例では,my_awesome_gem という自作 gem が https://example.net/gemsource という URL で提供されている,と想定する。

この場合,Gemfile に

source "https://example.net/gemsource" do
  gem "my_awesome_gem"
end

と書けばよい。

なお,Ruby バージョン

ruby 3.3.1 (2024-04-23 revision c56cd86388) [arm64-darwin23]

で動作を確認した。

再現実験

まず Gemfile を以下のように書く。

Gemfile
source "https://rubygems.org"

source "https://example.net/gemsource" do
  gem "my_awesome_gem"
end

gem "debug"

そして,my_awesome_gem は

gem install my_awesome_gem --source https://example.net/gemsource

でインストールしておき,逆に debug はインストールされていない状態にする1

この状態で,

bundle check

とすると,debug がインストールされていないので,当然チェックは通らない。
ただ,

Bundler can't satisfy your Gemfile's dependencies.
Install missing gems with `bundle install`.

のようなメッセージになっていて,何の gem が足りないのかが分からない。
Gemfile.lock が存在する場合は,それに照らして

The following gems are missing
 * debug (1.9.2)
Install missing gems with `bundle install`

などと教えてくれるが,まだ Gemfile.lock が作られていないので不足 gem についての情報は得られないのだ2

そこで,この状態で Bundler.require を強行してみることにする。これで不足 gem が判明するはずだ。

この実験のためにスクリプトを書いてもいいが,以下のようなワンライナーで確認できる。

ruby -r bundler -e "Bundler.require"

これを実行すると「Could not find gem 云々」というエラーメッセージが出るはずだ。
やってみると,

最初の 2 行を抜粋
/Users/XXXXX/.rbenv/versions/3.3.1/lib/ruby/site_ruby/3.3.0/bundler/resolver.rb:336:in `raise_not_found!': Could not find gem 'my_awesome_gem' in locally installed gems. (Bundler::GemNotFound)
        from /Users/XXXXX/.rbenv/versions/3.3.1/lib/ruby/site_ruby/3.3.0/bundler/resolver.rb:414:in `block in prepare_dependencies'

のようになった。
たいへん奇妙なことに「my_awesome_gem が見つからない」と言っている。
実際には my_awesome_gem はインストールされていて,足りないのは debug なのに!

試しに Gemfile の

source "https://example.net/gemsource" do
  gem "my_awesome_gem"
end

の部分をコメントアウトして bundler check すると,ちゃんと「debug が見つからない」と言ってくる。

つまり,この部分が何か悪さをしているのだ。

それ以上のことは分からなかった。

メモ:自前サーバーで gem を提供する方法

自作 gem を rubygems.org 以外で提供するのはとても簡単。
rubygems-generate_index という gem を使うので,これをあらかじめインストールしておく。

ウェブサーバーを用意し,公開するディレクトリーの下に gems というディレクトリーを置き,そこに自分で build してできた *.gem ファイルをためる。
そして,

gem generate_index

とやるだけ3
これで必要なファイル一式が作られる。gems ディレクトリーの中身を加除するたびにこのコマンドを実行すればいい。

自前サーバーを使えば,IP アドレス制限を付けて,公開範囲を「自社内」などに制限することができる。

  1. この実験で,「当て馬」に使う gem は debug である必然性が無い。デフォルト gem でなく,かつ rubygems.org で提供されている gem なら何を使っても同じ結果になると思う。

  2. この仕様もどうかと思う。なぜ教えてくれないのだろう。

  3. このコマンドは,gems ディレクトリーではなくそれを収めた(つまり一階層上の)ディレクトリーで実行する。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0