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の元祖らしいです