関連記事
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。
Goを使っていると、CLIで動作するちょっとしたツールをよく作ります。
その際にコマンドラインから引数を貰うのに、通常は flag
パッケージを使ってちょちょいとフラグ制御したりもしますね。
んで、たまにもう少しちゃんとしたコマンドを作るときは、サブコマンドを使えるようにしたいときがあります。
サブコマンドというのは、git pull
とか git switch
みたいに、2つ目のコマンドを用意するということです。
spf13/cobra のような素晴らしいライブラリも沢山ありますが、私個人は標準パッケージでなんとかするのが結構好きです。
flag
パッケージには、FlagSet
という構造体が存在するので、それを使うとサブコマンドも作れます。
使い方もとてもシンプルなのでよく利用する構造体です。FlagSet
を使うとユニットテストもし易いです。
サンプル
package main import ( "flag" "log" "os" "runtime/debug" ) type subcommand string const ( subcmd1 subcommand = "cmd1" subcmd2 subcommand = "cmd2" subver subcommand = "version" subhelp subcommand = "help" ) // cmd1 subcommand var ( cmd1 = flag.NewFlagSet("cmd1", flag.ExitOnError) cmd1OptC = cmd1.Int("c", 0, "option c") ) // cmd2 subcommand var ( cmd2 = flag.NewFlagSet("cmd2", flag.ExitOnError) cmd2OptF = cmd2.String("f", "", "option f") ) func init() { log.SetFlags(0) } func main() { if len(os.Args) < 2 { help() os.Exit(1) } var ( subcmd = subcommand(os.Args[1]) args = os.Args[2:] ) switch subcmd { case subcmd1: cmd1.Parse(args) runCmd1() case subcmd2: cmd2.Parse(args) runCmd2() case subver: version() return case subhelp: help() return default: help() os.Exit(1) } } func runCmd1() { log.Printf("option c is %v", *cmd1OptC) } func runCmd2() { log.Printf("option f is %v", *cmd2OptF) } func version() { info, ok := debug.ReadBuildInfo() if !ok { log.Println("error: call debug.ReadBuildInfo()") os.Exit(1) } for _, s := range info.Settings { if s.Key == "vcs.revision" { log.Printf("version: vX.Y.Z (%s)", s.Value) return } } } func help() { log.Println("Usage: app <cmd1|cmd2|version|help>") cmd1.Usage() cmd2.Usage() }
以下のようなタスクファイルを用意。
# https://taskfile.dev version: '3' tasks: default: cmds: - go build -o app - ./app - ./app help - ./app version - ./app cmd1 -c 100 - ./app cmd2 -f helloworld - ./app cmd1 -f helloworld ignore_error: true
実行すると以下のようになります。
$ task task: [default] go build -o app task: [default] ./app Usage: app <cmd1|cmd2|version|help> Usage of cmd1: -c int option c Usage of cmd2: -f string option f task: [default] ./app help Usage: app <cmd1|cmd2|version|help> Usage of cmd1: -c int option c Usage of cmd2: -f string option f task: [default] ./app version version: vX.Y.Z (fe9c8eb719af1f17bcd9e2e7174c791e7ecd74c0) task: [default] ./app cmd1 -c 100 option c is 100 task: [default] ./app cmd2 -f helloworld option f is helloworld task: [default] ./app cmd1 -f helloworld flag provided but not defined: -f Usage of cmd1: -c int option c
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。