本番環境にデプロイしたビルド済のバイナリのバージョンを確認したいことがあります。 また、開発環境で使うちょっとしたツールを作る場合、ほとんどの場合いくつかのコマンドラインオプションを受け取れるようにしたいです。
これらのバージョン表示、コマンドラインオプションは共に
- Go言語標準 flag パッケージ
- サードパーティー製ライブラリ
で実現できます。
しかし、サードパーティ製ライブラリを含めると種類が多いため、どれを使って良いか分かりづらいです。それぞれの特徴を見て、どのような時にどの方法で実現したら良いか紹介してみようと思います。
結論 (どのような時にどの方法で実現したら良いか)
結論としては
- バージョン情報のみを表示したい場合
- 標準の
flag
パッケージ
- 標準の
- 社内でのみ利用するツールやコマンドラインオプションが少ない場合
- 標準の
flag
パッケージ
- 標準の
- 一般に公開するツールやコマンドラインオプションが多い場合
- サードパーティ製ライブラリ
- おすすめは spf13/pflag (2021年2月現在)
- サードパーティ製ライブラリ
になるかと思います。
それぞれ特徴を見ていきます。
標準の flag
パッケージ
特徴
特徴としては
また、標準の flag
パッケージを使う場合
- バージョン情報の表示
- コマンドラインオプションの追加
の間に実装方法に差異はありません。
コード
コードを書いて確認していきたいと思います。ショートオプションとロングオプションの両方を追加したい場合、2行に分けて書く必要があります。
package main import ( "flag" "fmt" ) var version = "1.0" func main() { var withVersion bool // ショートオプション `-v` を追加(デフォルトはflase) flag.BoolVar(&withVersion, "v", false, "version: short option") // ロングオプション `-version` を追加(デフォルトはflase) flag.BoolVar(&withVersion, "version", false, "version: long option") // 指定されたオプションを読み込む flag.Parse() // versionオプションが指定されていれば標準出力して戻る if withVersion { fmt.Println("Version ", version) return } // オプションversionが指定されていない場合の処理 // 〜〜〜 }
追加オプションをつけて、go run
で実行すると、バージョン情報が表示されることを確認できます。
$ go run main.go -v Version 1.0 $ go run main.go -version Version 1.0
ちなみに、flag.Parse()
を実行することで、-h
と -help
も使えるようになります。
$ go run main.go -h Usage of /tmp/go-build277262992/b001/exe/main: -v version: short option -version version: long option
用途
- ロングオプションが一般的なGNU/POSIXのコマンドラインツールのシンタックスと異なる
- ロングオプションとショートオプションの両方を追加するのが煩雑
という特徴から
- バージョン情報のみを表示したい
- 社内でのみ利用するツールやコマンドラインオプションが少ない
といったケースでは、標準の flag
パッケージを使うのが良いと言えそうです。
サードパーティー製のパッケージ
flag
パッケージの代替となるサードパーティー製のパッケージには様々なものがありますが、2021年2月現在 spf13/pflag がよく使われてます。
よく使われる理由として考えられるのは、 spf13/cobra というコマンドラインツールのフレームワークで使われているライブラリだからです。
github cli
docker cli
kubectl
等の様々なコマンドラインツールを実装するのに使われている人気のライブラリなので、長期的にメンテナンスされることが見込まれている、という点が大きいかと思います。
参考までに、よく使われている他のサードパーティ製パッケージと併せて
- go.modで requireされている数
- Githubのスターの数
を記載しておきます。
- サードパーティ製パッケージ
- spf13/pflag
- requireされている数: 12,137件
- スターの数: 約1,400
- alecthomas/kingpin
- requireされている数: 2,332件
- スターの数: 約3,000
- jessevdk/go-flags
- requireされている数: 1,738件
- スターの数: 約19,000
- spf13/pflag
spf13/pflag (サードパーティ製パッケージ)
特徴
特徴としては
- オプションの形式が、GNU/POSIXのコマンドラインツールと同じになる
- 例えば、ロングオプション
version
、ショートオプションv
を追加する場合- ロングオプションの形式は
--version
になる。 - ショートプションの形式は
-v
になる。
- ロングオプションの形式は
- 例えば、ロングオプション
- ロングオプションとショートオプションの両方を追加するのが容易
- サードパーティのパッケージのためライブラリ単体でバージョンの更新が必要
になるかと思います。
コード
こちらもコードを書いて確認してみます。ショートオプションとロングオプションの両方を追加したい場合、1行で表現できるのが確認できます。複数のオプションが必要な場合はこちらの方法が便利です。
package main import ( "fmt" "github.com/spf13/pflag" ) var version = "1.0" func main() { var withVersion bool // ロングオプション `--version`、ショートオプション `-v`を追加 // デフォルトはflase pflag.BoolVarP(&withVersion, "version", "v", false, "version") // 指定されたオプションを読み込む pflag.Parse() // versionオプションが指定されていれば標準出力して戻る if withVersion { fmt.Println("Version ", version) return } // オプションversionが指定されていない場合の処理 // 〜〜〜 }
オプションをつけて、go run
で実行すると、バージョン情報が表示されることを確認できます。
$ go run main.go -v Version 1.0 $ go run main.go --version Version 1.0
なお、spf13/pflag
で何らかのオプションを追加する方法を紹介するために version
オプションを追加するコードを載せていますが、コマンドラインフレームワークであるcobra
と一緒に使う場合は、version
オプションは追加不要です。(参照)
こちらのサードパーティーのパッケージも、pflag.Parse()
を実行することで、-h
と -help
も使えるようになります。ヘルプの表示フォーマットに少し違いがあり、ショートオプションとロングオプションは1行で表示されます。
$ go run main.go -h Usage of /tmp/go-build962608044/b001/exe/main: -v, --version version
用途
という特徴から
- 一般に公開するツールやコマンドラインオプションが多い
といったケースでは、spf13/pflag
のようなサードパーティのパッケージを使うのが良いと言えそうです。
便利機能
他にも spf13/pflag
には便利な機能があります。長期的に運用していく時に必要な機能になりそうです。
- フラグを非推奨にする または 短縮形のみ非推奨にする
- 隠しフラグ
- 機能としては他のフラグと同様に使用可能だが、ヘルプやUsageに表示されなくなる。
- Go標準パッケージ flagのサポート
- 例えば、
golang/glog
など内部でGo標準のflagパッケージを使っている等、統合的にフラグを使いたいケースもサポートしている。
- 例えば、
関連記事
今回はspf13/pflag
に関する記事でしたが、コマンドラインフレームワークのspf13/cobra
にも興味持たれた方は、もしよろしければ以下の記事も参照してみてください。
simple-minds-think-alike.hatenablog.com
simple-minds-think-alike.hatenablog.com