いまさら direnv の解説

  • 59
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

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/.envrcrm -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/.envrcsource_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

(そういう使い方はしたことありませんが)デーモンとかバッチとかで起動するときにはこのサブコマンドを使うと良いと思います。