HDE クラウドプロダクト開発部の小本です。
私のお気に入りツールdirenvを紹介します。
direnvとは・・・
- シェルの
cdをフックし、ディレクトリごとに環境変数を自動設定するツール pyenvなどを置き換えることができるツール- Pythonistaも、Rubyistも、Gopherも、みんな使って損はないツール
direnv以前の世界(pyenvはawesomeだった)
Pythonには、プロジェクトそれぞれに専用の環境を作ってPythonのバージョンやライブラリを切り替えることができるツールがあります。
- 専用環境を作れる virtualenv
- 専用環境をコマンドで簡単に切り替えられる virtualenvwrappper
と進化し、その最終形態がpyenvです。
pyenvはあらかじめディレクトリに環境を紐付けておくと、ディレクトリにcdしたとき、勝手に環境を切り替えてくれます。
$ # ~/foo ディレクトリでは、python 3.4.1を使う $ cd ~/foo $ pyenv local 3.4.1 $ # 移動すると、自動でpythonが切り替わる $ cd ~/foo $ python --version Python 3.4.1
これで「小1時間悩んだ挙句、別のPythonで実行していた事に気づき(ry」ということは無くなります。はっきり言って、革命的です、life-changingです。
乱立する ***env
我々が使う言語はPythonだけではありません。しかし、名前の通り pyenv はPython専用です。
rbenv phpenv nodenv jenv denv luaenvなどがあるのですが *1 、どれもやることはほとんど同じです。
もはや、***env を管理すること事態がコストです。
***envを一元的に管理するためのanyenvというツールもありますが、 エレガントとは言えません。
direnv = エレガントな回答
そこでdirenvです
pyenvが実際に行っているのは主に「環境変数PATHを変更し pythonコマンドの指す先を変える」ということです。
そこで、direnvはディレクトリごとに環境変数を切り替えることで、***env群の機能を1つのツールで提供できるのです。
direnvのインストール
direnvはGoで書かれていて、単一のバイナリファイルとして提供されています。
# Linuxの場合 curl https://github.com/zimbatm/direnv/releases/download/v2.6.0/direnv.linux-amd64 > ~/bin/direnv chmod +x ~/bin/direnv
その後、フックを追加します。
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc echo 'eval (direnv hook fish)' >> ~/.config/fish/config.fish echo 'eval `direnv hook tcsh`' >> ~/.cshrc
基本的な使い方
direnvの基本的な動作は2つです。
- ディレクトリに
cdしたとき、現在の環境変数を保存した上で、.envrcファイルを読み込む - ディレクトリを離れるとき、以前の環境変数を元に戻す
ディレクトリ固有の環境変数を指定するのが、.envrcファイルです。
とりあえず.envrcを編集するeditだけ覚えておけば十分でしょう。
$ cd ~/my-project $ direnv edit . # ~/my-project/.envrc をエディタで開く $ direnv edit # ~/.envrc が存在すれば . は省略可能
direnvは環境変数以外も扱える
実は.envrcには任意のシェルスクリプトを書くことが出来ます。
例えば以下のようにすれば、ディレクトリに入るたびにSLが走り抜けます。
# ~/foo-project/.envrc sudo apt-get update -y && sudo apt-get install -y sl sl
direnvは他にも追加のコマンドを用意しています。
layout program_name:その言語用の開発環境をセットアップするPATH_add path: 環境変数PATHにpathを追加path_add envname path: 環境変数envnameにpathを追加
詳しくはdirenv-stdlib.1.mdをご覧ください。
また、~/.direnvrcに自作コマンドを書くこともできます。
後述のuse pythonなどは~/.direnvrcへの追記が必須です。
direnvの使用例
テスト用環境変数のセット(汎用)
AWSのアクセスキーなどを.envrcで読み込むようにしておくと、
exportする手間が省ける上、
本番環境を誤って破壊したりするのも防げて便利です。
# ~/aws-project/.envrc export AWS_ACCESS_KEY=XXXXXXXXXXXXXXXXX export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY export AWS_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_KEY
bundle exec を省略する(Ruby向け)
layout rubyで bundle exec command を commandで実行できるようになります(bundle execを省略できるようになります)。
# ~/ruby-project/.envrc layout ruby # bundle execを省略可能にする。
pyenvの代わりにする(Python向け)
layout pythonで、virtualenvを使った専用環境を作れます。
# ~/python-project/.envrc use python 2.7.9 # インタープリタのバージョンを指定 layout python # 専用環境を作成
use python でバージョンを指定する機能もあるのですが、
指定バージョンのインタープリタを検索するコードは自分で~/.direnvrcに書かなくてはなりません。・
以下は pytohnzを使う場合のコードです。
# ~/.direnvrc use_python() { local version=$1 local found=0 while read line; do name=$(echo $line | cut -d ' ' -f 1) path=$(echo $line | cut -d ' ' -f 2-) if [ "${name}" = "${version}" \ -o "${name}" = "CPython-${version}" \ -o "${name}" = "CPython-${version}.0" \ ]; then PATH_add "${path}/bin" found=1 break fi done < <(pythonz list -p | sed -e '1d') if [ "$found" -eq 0 ]; then echo "python '${version}' is not installed." >&2 return 1 fi return 0 }
パッケージのインストール先を分ける(外部パッケージを隔離する)(Go向け)
入門記事などでは~/.bashrcや~/.zshrcの中で、
export GOPATH=~/gocode
などとすることが多いようです。
しかし、この方法だと~/gocodeの中に全プロジェクトのパッケージが混ざるので、
- 同じパッケージの異なるバージョンを同時にインストールできない
- 変なことをすると、全プロジェクトが巻き添えになる
- どれが不要なパッケージか分からなくなる
などの問題があります。
layout goで、カレントディレクトリをGOPATHにすることができます。
# ~/go-project/.envrc
layout go
さらに、path_add, PATH_addを使って、GOPATHに複数のディレクトリを追加します。
こうすると、
- プロジェクト本体のソース →
src/ - 依存パッケージのソース →
.direnv/go/src
と、分けて配置できるので、rm -rf .direnv/go/srcで依存パッケージを簡単におじゃんにできます。
unset GOPATH layout go path_add GOPATH .direnv/go PATH_add .direnv/go/bin PATH_add bin
追記:ファイルの使い分けなど
このへんで「~/.bashrcと.envrcをどう使い分ければいいんだっけ?」と、
たまに混乱してくるので、表にまとめます:
| ~/.bashrc, ~/.profile等 | プロジェクトに無関係な、システム全体で共通の環境変数 |
|---|---|
| .envrc | プロジェクト固有の設定 |
| ~/.direnvrc | .envrcから呼び出すコマンド |
システム全体で共通ではないが、
複数プロジェクト間で共有したい環境変数がある場合は、
適当なファイル(~/Document/direnv/common.shとか)を作り、
各プロジェクトの.envrcでsource ~/Document/direnv/common.shすればいいでしょう。
また、.envrcはGitやMarcurial等のVCSの管理対象にはしない方がいいと思います。
使いたい環境変数やインタープリタのパスなどは、開発者ごとに違う可能性があるからです(そもそもdirenvを使いたくない・使えないかもしれないですし)。
まとめ
direnvはGoで書かれた、Python・Ruby・Goでの開発を効率化するツールです。
そしてHDEでは製品開発にPython・Ruby・Goを(も)使っています。
*1:ちなみにrbenvが***envの元祖らしいです