Goから外部コマンドの呼び出しではPATHの「~」が展開されない
Goで書かれたプログラムから外部コマンドを呼び出す場合、環境変数PATHに~(チルダ:ホームディレクトリ)は展開されないので、~/bin/のようにPATHを通している場合、実行に失敗します。原因がわからず結構はまりました。
以下のように~を使わず、$HOMEを展開し回避します。
export PATH="$HOME/bin:$PATH"
たまにはまっている人がいる問題のようなので(例)、記事として日本語で共有しておきます。
やりたかったのは
WSL2の環境で、chezmoiから1Password CLIを利用しているのですが、Linux版のCLIはWSL2のホストで動いている1Password GUIと通信してくれません。そのため、1Passwordの長いマスターパスワードを打ち込む必要があります。
一方、Windows版の1Password CLIでは、1Password GUI側でWindows Helloを設定していると、Hello経由で指紋などで認証が行われます。
Windows Helloでの認証をWSL環境からも使いたいと思い、WSL側からWindows版の1Passwordを利用を試みていたのですが、chezmoiからの利用のみ上記の理由でうまく呼び出せずはまっていました(1Password CLIの利用がほぼchezmoiのみなので、とん挫するところでした)。
WSLのフォルダにWindows版1Password CLIへのシンボリックリンクをopという名前で置き、そのフォルダをフルパスでPATHに追加すればchezmoi(go)からWindows版1Password CLIが呼び出され、Windows Helloでの認証で動作しました。
Windows版1Password CLIのフォルダを直接PATHに指定しても動くかもしれませんが、なんとなく気持ち悪いので未検証です。
問題
一応、動いているのですが、たまにエラーが発生するようです(chezmoi applyでエラー)。
同じ文書(op document get)でこけているわけでもないので、単純に呼び出せない、というわけではなさそうです。
原因・対応がわかれば追記します。
対処
エラーの発生状況などから、op document get
の実行間隔の制約らしいことがわかりました。
1Password CLIのLinux版やMac版では、op signin
でTOKENが発行されるのに対し、Windows版ではTOKENの発行などがないため、
リクエストの都度1Passwordのサーバー側かGUIクライアントとの通信を行っているようです。
その関係?でchezmoi apply
の実行中に~/.ssh
フォルダの取得などで1passwordからのファイル取得が繰り返され高頻度での実行となったときにエラーとなるようです。
op.exe
の呼び出しをシンボリックリンク経由ではなく、以下のようなシェルスクリプトを挟みリトライとウェイトを入れることで、エラーの発生頻度がなくなりました(というか、想定しているretryも発生しないように見える)。
#! /bin/bash
if [ "$1" != "document" ]; then
/mnt/c/1password/op.exe $*
else
for i in {1..10}; do
/mnt/c/1password/op.exe $*
RESULT=$?
if [ $? ] ; then
exit 0
fi
echo retry $i : op $* 1>&2
sleep 1
done
exit $RESULT
fi
もとは、もっと単純にエラーコードをチェックし、retryしていたのですが、chezmoi document
のみに対象を絞り、リトライを入れることでうまく動いているようです。しかし、うまくいく原因は不明で、これ以上はchezmoiのソースとかを見ないとわからなさそうです。
とりあえず、目的は達成されたので、これで運用してみます。
これ以上はタイトルとずれすぎるので、続きがあれば別記事で書きます。