2013年5月7日火曜日

bundlerの環境変数でハマった話


capistranoでrailsアプリをbundle packageを使ってデプロイしようとしてハマった話。
ちょっとまとめるのが億劫だったので、つらつらと。

困った

あるプロジェクトで、capistranoのcopyストラテジーを使って
デプロイしているのですが、その際に、外部へgemを取りに行かないように、
bundle package を使っています。

で、その bundle package をする部分は自前で定義していて、
下記のように単純にやっていました。

system("cd #{destination} && bundle package --all")

しかしこれだと予期したように動かなかった。

想定としては、

/tmp/hogehoge/vendor/cache

の下に、gem達が入るはずなのに、なぜか

capコマンド実行ディレクトリ/vendor/cache

に入ってしまった。


原因

ググると、こんな記事が見つかりました。
どうやらbundlerが定義している環境変数が原因だったよう。
確認してみる。

$ bundle exec env | grep -i bundle
 :
 :
BUNDLE_BIN_PATH=/hoge/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/bundler-1.3.1/bin/bundle
BUNDLE_GEMFILE=/hoge/hoge/Gemfile
RUBYOPT=-I/hoge/.rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/bundler-1.3.1/lib -rbundler/setup

確かに環境変数がセットされていました。

具体的には、BUNDLE_BIN_PATH と RUBYOPT の bundler/setup がいけなかったようです。


対応

参照した記事と同様に、bundle package を実行する際に、
bundler関連の環境変数をリセットする処理を入れると。想定通りに動きました。

def bundle_package
  execute "bundle packaging" do
    with_clean_env do
      system("cd #{destination} && bundle package --all")
    end
  end
end

def with_clean_env
  bundled_env = ENV.to_hash
  %w(BUNDLE_GEMFILE RUBYOPT BUNDLE_BIN_PATH).each{ |var| ENV.delete(var) }
  yield
ensure
  ENV.replace(bundled_env.to_hash)
end

結局のところ

色々頑張ってみたけど、実は bundler には、

with_clean_env

なるメソッドが実装されていて、さらにその状態でコマンドを実行する

with_clean_system

まで用意されていました。
なので、自前で書かずとも、

def bundle_package
  execute "bundle packaging" do
    Bundler.clean_system("cd #{destination} && bundle package --all")
  end
end

とかやればOKでした。


それはそうと、とりあえずcopyストラテジーで bundle package が使いたいだけなんだけど?

という方は、自分のリポジトリではないですが、

https://github.com/rainux/capistrano-strategy-copy-with-bundle-package

とかを参照したら良い感じになるのではないでしょうか。

勉強になりました。


おしまい。

0 件のコメント:

コメントを投稿