概要
同じコマンド名でもディレクトリ毎に異なる挙動をさせたかった。具体的な使用例は本記事後半を参照のこと。
おおざっぱに言うと、ディレクトリ毎にエイリアスを変更するイメージ。
最終的にはdirenvを使用して実現できた。
direnvの準備
direnvは、所定のディレクトリ以下に固有の環境変数を設定してくれるツール。
インストール
Macであれば、以下でインストール可能。
1
brew install direnv
インストール後、使用しているシェルの設定ファイルにdirenvの設定を追加する
zshなら ~/.zshrc
に以下を追加。
1
eval "$(direnv hook zsh)"
bashなら ~/.bashrc
に以下を追加。
1
eval "$(direnv hook bash)"
direnvの簡単な使い方
インストール後は、固有の環境変数を設定したいディレクトリで以下のコマンドを実行して、環境変数を設定すれば良い。
1
direnv edit .
例えば、以下のように記載するとそのディレクトリ配下では HELLO
という環境変数に World
という値が設定されている。
1
export HELLO='World'
設定ファイルはそのディレクトリに、 .envrc
というファイルが作成される。
.envrc
は直接編集するのではなく direnv edit .
を用いて編集する。直接編集した場合は、 direnv allow
を実行しろというエラーが表示されるので、その通りに実行すること。
direnvでディレクトリ固有のコマンドを定義する設定
まずは、 ~/.direnvrc
に以下を設定する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ALIASES_DIR=".direnv/aliases"
export_function() {
local name=$1
local alias_dir=$PWD/${ALIASES_DIR}
mkdir -p "$alias_dir"
PATH_add "$alias_dir"
local target="$alias_dir/$name"
if declare -f "$name" >/dev/null; then
echo "#!/usr/bin/env bash" > "$target"
declare -f "$name" >> "$target" 2>/dev/null
echo "$name" '"$@"' >> "$target"
chmod +x "$target"
fi
}
clear_direnv_aliases() {
local alias_dir=$PWD/${ALIASES_DIR}
rm -rf $alias_dir/*
}
export_function
は第1引数に作成したいコマンド名を渡すと、そのコマンド名のファイルが実行権限付きで ALIASES_DIR
のパス以下に作成される。
.envrc
内で export_function
が呼び出されれば、このディレクトリ配下にいる間 ALIASES_DIR
が環境変数PATHに追加された状態になる。
定義したいコマンドファイルの中身を以下のように .envrc
内に定義する。
1
2
3
4
5
6
7
clear_direnv_aliases
sample-cmd () {
echo "Hello $1"
echo "This command is sample command"
}
export_function sample-cmd
これにより、 .direnv/aliases/sample-cmd
という実行権限付きのファイルが以下の内容で作成されている。
1
2
3
4
5
6
7
#!/usr/bin/env bash
sample-cmd ()
{
echo "Hello $1";
echo "This command is sample command"
}
sample-cmd "$@"
このコマンドを実行すれば以下のようになる。引数を受け取ることも出来る。
1
2
3
4
5
6
7
$ sample-cmd
Hello
This command is sample command
$ sample-cmd Mike
Hello Mike
This command is sample command
clear_direnv_aliases
は export_function
で作成されたコマンドを全て削除する関数であり、これを .envrc
で呼び出せば、direnv対象のディレクトリに入る度にコマンドファイルが削除される。
これを入れておかないと、 .envrc
で一度作成したコマンドを削除(又は変更)した場合でも前のコマンドがそのまま残り続けてしまう。
clear_direnv_aliases
は 最初の export_function
よりも前に記載しておくこと。
使用例
例えば、色々なプロジェクトにおいて相違するdockerの起動、終了などのコマンドを同じコマンド名に統一するために使用している。
下記プロジェクトAのようにシンプルな感じであれば良いのだが、プロジェクトBのようにdocker-composeファイルのファイル名を指定するよう場合には、いちいち面倒くさい。プロジェクトによってはこのような面倒くさいコマンドが必要なものはプロジェクトCのようにMakefileが用意され、面倒なコマンドを隠蔽してくれている場合もある。
やりたい事 | プロジェクトAの例 | プロジェクトBの例 | プロジェクトCの例 |
---|---|---|---|
起動 | docker-compose up -d | docker-compose -f docker-compose.local.yaml up -d | make up |
コンテナをkillして終了 | docker-compose down | docker-compose -f docker-compose.local.yaml down | make down |
volumeなども一緒に削除して終了 | docker-compose down -v –remove-orphans | docker-compose -f docker-compose.local.yaml down -v –remove-orphans | make clean |
プロジェクトBのような場合には、自分がMakefileを追加してPRを投げれば良いが、それでも、全プロジェクトでMakefileのターゲット名を統一できるわけではない。 各プロジェクトでやりたい事に対して同じコマンドを利用するにはaliasでの対応は難しい。 このようなケースでは今回のような対応が有効だ。
今は以下のような共通コマンドを設定して利用している。
やりたい事 | 共通コマンド |
---|---|
コンテナのログを表示 | dc-logs |
コンテナをkillして終了 | dc-down |
Volumeなども一緒に削除して終了 | dc-hard-down |
コンテナをkillして再起動 & ログを表示 | dc-restart |
Volumeなどを削除して再起動 & ログを表示 | dc-hard-restart |
.envrc
設定の一例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
clear_direnv_aliases
dc-logs () {
docker-compose logs -f "$@"
}
export_function dc-logs
dc-down () {
docker-compose down
}
export_function dc-down
dc-hard-down () {
docker-compose down -v --remove-orphans
}
export_function dc-hard-down
dc-restart () {
dc-down && make up && dc-logs
}
export_function dc-restart
dc-hard-restart () {
dc-hard-down && make up && make init && dc-logs
}
export_function dc-hard-restart
コンテナを起動していないときも dc-restart
や dc-hard-restart
を実行すれば良い。
同じことをやるときのインターフェイスを統一しておくと無駄に頭を使わなくて済み開発に集中できるようになる。
なお、dc-logs
は外部から引数を受け付けられるようにコマンドを定義しているため、以下のようにログを確認する対象のコンテナをコマンド実行時に切り替えられる。
dc-logs
→ 全てのコンテナのログを確認できる。dc-logs container1 container2
→ container1及びcontainer2の2つのコンテナのログのみを確認できる。