Ruby
Python

gem, bundler と pip, venv の比較

More than 1 year has passed since last update.

Ruby や Python でできたツールの README には、よくインストール方法として gem install redcarpet とか pip install pygments どとシンプルなコマンドが書かれています。

ですが、このインストール方法をみたときに、Rubyに慣れてない人は「どうせ gem install してもなんかよくわからないエラーがでて、愚痴ったら bundler 使わないほうが悪いみたいに言われるんだろ」とか、Pythonに慣れてない人は「これどこにインストールするの? bundler みたいなのないの?」と思うかもしれません。

少なくとも私は gem install でインストールするツールを敬遠していました。でも、「これだから gem は…」と愚痴るのは違うだろう、 Rubyist は pip install に同じ思いを持ってるだろうと思ったので、私のような人のためにこの記事を書くことにしました。 Ruby 側のツールに対する理解が間違っているかもしれないので、間違っていたら編集リクエストをください。

gem installpip install

どちらもサードパーティーのパッケージをインストールするために使います。

通常は Ruby だと /usr/local/lib/ruby/gems/2.3.0, Python だと /usr/local/lib/python3.5/site-packages/ のような、ユーザー非依存の場所にインストールしようとします。

gem install --user-install <パッケージ名>pip install --user <パッケージ名> すると、 ~/.gem/ruby/2.3.0~/.local/lib/python3.5 (maxOS で Framework になっている場合 ~/Library/Python/3.5/lib/python/site-packages) のような場所にインストールします。

Note:
Ubuntu で apt install python3-pip でインストールできる pip は、 sudo を付けてない場合は自動で --user でインストールするようにカスタマイズされています。

bundle installpip install -r

どちらも、定義されたパッケージの一覧をインストールするのに使います。

bundler の場合、 bundle install すると (Gemfile.lock が無い場合や Gemfile が更新されていた場合は) Gemfile をもとにパッケージをインストールして、実際にインストールしたパッケージ (Gemfile に含まれない依存パッケージも含む) とバージョンを記述した Gemfile.lock を生成します。 Gemfile.lock が既にある場合はそちらをもとにインストールすることで、違う環境でも全く同じバージョンのライブラリをインストールすることができます。

pip の場合も、 pip install -r requirements.txt すると requirements.txt に書いてあるルールにもとづいてパッケージをインストールします。バージョンをロックしたい場合、 pip freeze > requirements.lock すると現在インストールされている全てのライブラリとバージョンを書き出せるので、それを pip install -r requirements.lock することができます。

bundler が Gemfile.lock を自動で生成しバージョン管理に含めることを推奨しているのに対して、 pip は自動で lock ファイルを作りませんし、特定のやりかたを推奨してもいません。
WebアプリをCIとプロダクション環境で同じようにデプロイしたい場合は bundler と同じ方針を取りますし、ライブラリを開発するプロジェクトで、開発に利用するツールをインストールするだけなら、 requirements.txt だけあれば十分です。OSSのフレームワークやライブラリのリポジトリには Gemfile.lock 相当のものがないのはそのためです。

bundler の --path と venv

インストールするライブラリを Ruby や Python 全体で共有するのではなく、アプリケーション固有で管理したい場合に、 bundle install --path=vendor/bundlepython3 -m venv /path/to/python を使います。
これらは目的は同じなのですが、実現方法が異なるので注意が必要です。

bundle install --path は、指定したディレクトリ配下にパッケージをインストールするだけです。
そのままではそのディレクトリ配下のパッケージが使えませんが、 bundle exec コマンド すると使えるようになります。

一方、 python3 -m venv /path/to/python は、 /path/to/python に新しく Python をインストールしたかのように振る舞う「仮想環境」を作ります。この仮想環境はサードパーティーのパッケージは分離されているものの、標準ライブラリは元になった Python の物を使うので、 bundler の path と同程度に軽量です。

venv は仮想環境を作るだけなので、 bundle install --path の用にインストールまでするには、その環境の pip を使って pip install -r requirements.txt する必要があります。
このように仮想環境内のコマンドを実行する場合、 bundle exec のようなコマンドを使うのではなく、 /path/to/python/bin にあるコマンドを実行することになります。それにはいくつかの方法があります。

  • フルパスでコマンドを実行する: /path/to/python/bin/pip install -r requiremnts.txt
  • PATH の最初に追記する: export PATH=/path/to/python/bin:$PATH; pip install -r requirements.txt
  • activate というヘルパースクリプトを使う: source /path/to/python/bin/activate; pip install -r requirements.txt

activate スクリプトは主に3つのことをします。

  • PATH に仮想環境の bin を追加する
  • VIRTUAL_ENV という環境変数を設定する (vim や emacs などの外部ツールが現在利用中の仮想環境を見つけられる)
  • PATH などを元に戻す deactivate コマンドを定義する

さいごに

この記事ではどちらが優れているかを論じることはしません。

片方に慣れているともう片方で同じやり方ができないために面倒に感じがちなので、慣れてない方を dis りたくなっても我慢しましょう。