AWS とかを頻繁に弄るようになってきた今、direnv 無しでは生きられない体になってきました。
が、いままで漠然と使ってきていたので direnv について改めて調べました。
インストール
下記から適当なバイナリをダウンロードし、パスの通ったところに保存して実行属性を付けます。
またはソースからビルドします。
git clone https://github.com/direnv/direnv
cd direnv
make install
あるいは go get でも大丈夫だと思います(ビルドできる環境があるなら)。
go get github.com/direnv/direnv
インストールできたら Bash のシェルのフックを設定します。
vim ~/.bashrc
次のように追記します。
# ~/.bashrc
eval "$(direnv hook bash)"
反映します。
exec bash --login
使ってみる
適当なディレクトリで direnv edit . するとエディタが起動します。
direnv edit .
以下のように環境変数のエクスポートを記述します。
export AWS_DEFAULT_PROFILE=oreore
export AWS_PROFILE=$AWS_DEFAULT_PROFILE
エディタを終了すると次のように表示されます。
direnv: loading .envrc
direnv: export +AWS_DEFAULT_PROFILE +AWS_PROFILE
env で環境変数を確認してみると、設定されていることがわかります。
env | grep ^AWS
# => AWS_PROFILE=oreore
# => AWS_DEFAULT_PROFILE=oreore
別のディレクトリに移動します。
cd ../other
すると次のように表示されます。
direnv: unloading
環境変数がクリアされています。
env | grep ^AWS
# =>
direnv: error .envrc is blocked. Run direnv allow to approve its content.
direnv edit で編集されるファイルはカレントディレクトリの .envrc なので直接編集することも可能です。
vim .envrc
編集すると次の警告が表示されます。
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
安全のために、.envrc が変更された後は direnv allow するまで無効になっています。
例えば、誰かが /tmp/.envrc を rm -fr / みたいな内容で作成した状況を想像してみてください。
direnv allow すると有効になります。
direnv allow
direnv edit で編集した場合は自動的に direnv allow されるので、direnv allow する必要はありません。
direnv allow の情報は ~/.config/direnv/allow/ に保存されています。
ll ~/.config/direnv/allow/
# => -rw-r--r-- 1 ngyuki staff 0 10 22 01:22 221e5718...
# => -rw-r--r-- 1 ngyuki staff 0 10 22 01:15 6d84e3c8...
# => -rw-r--r-- 1 ngyuki staff 0 10 22 01:23 dc9609ff...
sha256 っぽいファイルが沢山作成されています。ファイル名+内容を sha256 したもののようです。
{ realpath .envrc; cat .envrc; } | sha256sum
詳細は以下のとおりです。
stdlib
.envrc ファイルの中ではいくつか便利なユーティリティ関数が使えます。特に使いそうなやつを説明します。
expand_path
expand_path <rel_path> [relative_to]
- 指定された相対パスを絶対パスに変換して出力します
- 2番目の引数が基準となるディレクトリです
- 省略するとカレントディレクトリが基準になります
cd /path/to/ore
expand_path ../are
# => /path/to/are
find_up
find_up [filename]
- ディレクトリを遡って、直近のファイル名が
filenameであるファイルのパスを出力します - ファイル名を省略すると
.envrcが検索されます
cd /path/to/ore
touch dore
cd are/sore
pwd
# => /path/to/ore/are/sore
find_up dore
# => /path/to/ore/dore
PATH_add
PATH_add <path>
- 環境変数
PATHに指定したパスを追加します - 相対パスを指定した場合でも絶対パスに変換されてから追加されます
echo $PATH
# => /usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
cd /path/to/ore
PATH_add bin
echo $PATH
# => /path/to/ore/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin
path_add
path_add <varname> <path>
- 環境変数の名前を指定できる意外は
PATH_addと同じです
export GOPATH=/path/to/golang
echo $GOPATH
# => /path/to/golang
cd /path/to/ore
path_add GOPATH go
echo $GOPATH
# => /path/to/ore/go:/path/to/golang
プログラミング言語に特有の設定とかもあったりします。詳細はマニュアルを参照してください。
.direnvrc
~/.direnvrc が存在する場合、.envrc のロード前にロードされます。
例えば、独自のユーティリティ関数を作ったりできます。
# ~/.direnvrc
aws_profile(){
export AWS_PROFILE=$1
export AWS_DEFAULT_PROFILE=$AWS_PROFILE
}
この関数は .envrc で使用することができます。
# .envrc
aws_profile oreore
また、stdlib で use という関数が定義されており、use foo bar の形式で呼び出すと use_foo bar という関数が呼ばれるようになっています。なので、~/.direnvrc で次のような関数を作成しておくと、
# ~/.direnvrc
use_aws(){
export AWS_PROFILE=$1
export AWS_DEFAULT_PROFILE=$AWS_PROFILE
}
.envrc で次のように使用することができます。
# .envrc
use aws oreore
Loading layered .envrc
次のように複数の階層に .envrc が存在していた場合。
/a/.envrc/a/b/.envrc
/a/b/ に cd したときは /a/b/.envrc が有効になります。
/a/b/.envrc で source_env を使うと、上の階層の .envrc もロードすることができます。
# /a/b/.envrc
source_env ..
もしくは source_up を使えば、階層を遡って直近の .envrc が自動でロードされます。
# /a/b/.envrc
source_up
dotenv とのコンパチ
次のように書いておくと、dotenv の .env を direnv の .envrc からロードすることができます。
# .envrc
dotenv .env
dotenv の .env は次のような形式です。
# .env
AWS_ACCESS_KEY_ID="ore-no-key"
AWS_SECRET_ACCESS_KEY="ore-no-secret"
これは RHEL の /etc/sysconfig/ とかに置かれるファイルの形式(=systemd の EnvironmentFile)と同じです。
例えば、次のようなケースで使えます。
- ローカルでなにかデーモンを開発している
- デーモンに必要な環境変数は
.envに書いて.envrcからロード - 開発にしか必要ない環境変数は
.envrcにそのまま書く - systemd の
EnvironmentFileで.envを指定する
direnv exec
exec サブコマンドを使えば、指定したディレクトリの .envrc が反映された状態でコマンドを実行できます。
direnv exec [DIR] COMMAND [...ARGS]
DIR を省略すると COMMAND で指定したファイルのあるディレクトリから .envrc がロードされます。
例えば、インタプリタとスクリプトを指定する場合は次のように呼び出します。
direnv exec /path/to/project php /path/to/project/hoge.php
スクリプトがそのまま実行可能なら次のように呼び出します。
direnv exec /path/to/project/vendor/bin/hoge
(そういう使い方はしたことありませんが)デーモンとかバッチとかで起動するときにはこのサブコマンドを使うと良いと思います。