R/O

go:embed で CLI ツールのシェル補完スクリプトをバイナリに埋め込む

Posted on 2021-03-01

Go 1.16 で入った go:embed を使って、自作の CLI ツール sidenote1 のシェル補完用スクリプトをバイナリに埋め込んでみた。

テキストファイルの内容を文字列として埋め込むだけなら非常に簡単で、以下のようにするだけ。

  1. embed パッケージを import する

    import _ "embed"
    
  2. string 変数の宣言の前に //go:embed <ファイル> で埋め込みたいファイルを指定する

    //go:embed path/to/file.txt
    var embeddedFileContent string
    

sidenote では埋め込んだスクリプトを出力するだけの completion サブコマンドを追加2して、Bash であれば ~/.bashrc

source <(sidenote completion bash)

と書いておけばシェル補完を有効化できるようにした。

Go で CLI ツールを作る利点の一つにツールがシングルバイナリで動作することがあるが、シェル補完用スクリプトのようにツール本体とは別の付属物がある場合、バイナリに埋め込んでしまうことでユーザに別途インストールしてもらう手間を省くことができる。3 特に (アーカイブ形式での配布ではなく) go install でインストールすることを想定しているようなものの場合はうれしいと思う。

バイナリにファイルを埋め込むためのパッケージは以前から色々と存在していたものの、sidenote はなるべく依存関係を小さく保っておきたい意図で Go の標準ライブラリ以外は使わないようにしていて、自前でファイル埋め込みを実現するのも大変そうなので対応していなかった。 そういう意味で標準のツールチェインでサポートされるようになったことはありがたい。

  1. sidenote については以前の記事を参照 

  2. サブコマンド名は kubectl にならった 

  3. これは付属物だけをアップデートしたい場合でもバイナリ全体を更新する必要がある、ということでもあるので、何でもかんでも埋め込めば良いということではない