$ go mod init sample
go: creating new go.mod: module sample
init
コマンドを実行。
$ go run -mod=mod github.com/spf13/cobra-cli@latest init
$ tree
tree
.
├── LICENSE
├── cmd
│ └── root.go
├── go.mod
├── go.sum
└── main.go
main.go
は cmd.Execute()
を呼び出しているだけ。
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
*/
package main
import "sample/cmd"
func main() {
cmd.Execute()
}
cmd/root.go
を編集。実行したら Hello
を出力する。
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "sample",
Short: "挨拶をします",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println("Hello")
return nil
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
}
実行。
$ go run main.go
Hello
help を見る。
$ go run main.go -h
挨拶をします
Usage:
sample [flags]
Flags:
-h, --help help for sample
--night
をつければ Good night
を出力する。
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var night bool
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "sample",
Short: "挨拶をします",
RunE: func(cmd *cobra.Command, args []string) error {
if night {
fmt.Println("Good night")
return nil
}
fmt.Println("Hello")
return nil
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
rootCmd.PersistentFlags().BoolVar(&night, "night", false, "night フラグの説明文です")
}
実行。
$ go run main.go -h
挨拶をします
Usage:
sample [flags]
Flags:
-h, --help help for sample
--night night フラグの説明文です
$ go run main.go
Hello
$ go run main.go --night
Good night
func init() {
// rootCmd.PersistentFlags().BoolVar(&night, "night", false, "night フラグの説明文です")
rootCmd.PersistentFlags().BoolVarP(&night, "night", "n", false, "night フラグの説明文です")
}
実行。
$ go run main.go -h
挨拶をします
Usage:
sample [flags]
Flags:
-h, --help help for sample
-n, --night night フラグの説明文です
$ go run main.go -n
Good night
--name
をつければ挨拶の後に名前を出力する。
今度は変数を設定しないでフラグの値を取得してみる。
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var night bool
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "sample",
Short: "挨拶をします",
RunE: func(cmd *cobra.Command, args []string) error {
name, _ := cmd.Flags().GetString("name")
if night {
fmt.Println("Good night " + name)
return nil
}
fmt.Println("Hello " + name)
return nil
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
rootCmd.PersistentFlags().BoolVarP(&night, "night", "n", false, "night フラグの説明文です")
rootCmd.Flags().StringP("name", "a", "", "name フラグの説明文です")
}
実行。
$ go run main.go -h
挨拶をします
Usage:
sample [flags]
Flags:
-h, --help help for sample
-a, --name string name フラグの説明文です
-n, --night night フラグの説明文です
$ go run main.go
Hello
$ go run main.go -a aaa
Hello aaa
$ go run main.go -a aaa --night
Good night aaa
~P
がついている方は shorthand
を設定できる。
~Var
がついている方は直接値を設定できる。
rootCmd.Flags().String("name", "", "name フラグの説明文です")
rootCmd.Flags().StringP("name", "a", "", "name フラグの説明文です")
rootCmd.Flags().StringVar(&name, "name", "", "name フラグの説明文です")
rootCmd.Flags().StringVarP(&name, "name", "a", "", "name フラグの説明文です")
func init() {
rootCmd.PersistentFlags().BoolVarP(&night, "night", "n", false, "night フラグの説明文です")
rootCmd.Flags().StringP("name", "a", "", "name フラグの説明文です (required)")
rootCmd.MarkFlagRequired("name")
}
実行。
$ go run main.go
Error: required flag(s) "name" not set
Usage:
sample [flags]
Flags:
-h, --help help for sample
-a, --name string name フラグの説明文です (required)
-n, --night night フラグの説明文です
$ go run main.go -a aaa
Hello aaa
引数に数字を 2 つ与えるとその合計を出力する。
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "sample",
Short: "挨拶をします",
RunE: func(cmd *cobra.Command, args []string) error {
name, _ := cmd.Flags().GetString("name")
if night {
fmt.Println("Good night " + name)
if len(args) > 0 {
firstNum, _ := strconv.Atoi(args[0])
secondNum, _ := strconv.Atoi(args[1])
fmt.Printf("SUM: %v\n", firstNum+secondNum)
}
return nil
}
fmt.Println("Hello " + name)
if len(args) > 0 {
firstNum, _ := strconv.Atoi(args[0])
secondNum, _ := strconv.Atoi(args[1])
fmt.Printf("SUM: %v\n", firstNum+secondNum)
}
return nil
},
}
実行。
$ go run main.go -a aaa
Hello aaa
$ go run main.go -a aaa 1 99
Hello aaa
SUM: 100
これらのメソッドが用意されている。
メソッド | 機能 |
---|---|
NoArgs | 引数が存在したらエラーを返す |
OnlyValidArgs | ValidArgs に含まれていないとエラーを返す |
ArbitraryArgs | エラーを返さない |
MinimumNArgs(n) | 少なくとも n 個の引数がないとエラーを返す |
MaximumNArgs(n) | n 個以上の引数があるとエラーを返す |
ExactArgs(n) | n 個の引数以外だとエラーを返す |
ExactValidArgs(int) | n 個の引数以外 or ValidArgs フィールドにない位置引数がある場合はエラーを返す |
RangeArgs(min, max) | 範囲内の値でないとエラーを返す |
こんな感じで設定できる。
Args: cobra.ExactArgs(1),
複数のバリデーションをチェックする場合は MatchAll
を使えば良さそう。
// MatchAll allows combining several PositionalArgs to work in concert.
func MatchAll(pargs ...PositionalArgs) PositionalArgs {
return func(cmd *Command, args []string) error {
for _, parg := range pargs {
if err := parg(cmd, args); err != nil {
return err
}
}
return nil
}
}
今回は 2 個の引数のみ受け付ける。かつ、値が数値であることのみ許可する。
var rootCmd = &cobra.Command{
Use: "sample",
Short: "挨拶をします。2 つの int を渡すと計算もします",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return nil
} else {
if len(args) != 2 {
return errors.New("引数の数が不正です")
}
_, err1 := strconv.Atoi(args[0])
_, err2 := strconv.Atoi(args[1])
if err1 != nil || err2 != nil {
return errors.New("引数の型が不正です")
}
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
name, _ := cmd.Flags().GetString("name")
if night {
fmt.Println("Good night " + name)
if len(args) > 0 {
firstNum, _ := strconv.Atoi(args[0])
secondNum, _ := strconv.Atoi(args[1])
fmt.Printf("SUM: %v\n", firstNum+secondNum)
}
return nil
}
fmt.Println("Hello " + name)
if len(args) > 0 {
firstNum, _ := strconv.Atoi(args[0])
secondNum, _ := strconv.Atoi(args[1])
fmt.Printf("SUM: %v\n", firstNum+secondNum)
}
return nil
},
}
実行。
$ go run main.go -a aaa
Hello aaa
$ go run main.go -a aaa 1 99
Hello aaa
SUM: 100
$ go run main.go -a aaa 1 abc
Error: 引数の型が不正です
Usage:
sample [flags]
Flags:
-h, --help help for sample
-a, --name string name フラグの説明文です (required)
-n, --night night フラグの説明文です
実行前と実行後の処理を設定できる。
var rootCmd = &cobra.Command{
Use: "sample",
Short: "挨拶をします。2 つの int を渡すと計算もします",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return nil
} else {
if len(args) != 2 {
return errors.New("引数の数が不正です")
}
_, err1 := strconv.Atoi(args[0])
_, err2 := strconv.Atoi(args[1])
if err1 != nil || err2 != nil {
return errors.New("引数の型が不正です")
}
}
return nil
},
PreRun: func(cmd *cobra.Command, args []string) {
fmt.Println("=== PreRun ===")
},
RunE: func(cmd *cobra.Command, args []string) error {
name, _ := cmd.Flags().GetString("name")
if night {
fmt.Println("Good night " + name)
if len(args) > 0 {
firstNum, _ := strconv.Atoi(args[0])
secondNum, _ := strconv.Atoi(args[1])
fmt.Printf("SUM: %v\n", firstNum+secondNum)
}
return nil
}
fmt.Println("Hello " + name)
if len(args) > 0 {
firstNum, _ := strconv.Atoi(args[0])
secondNum, _ := strconv.Atoi(args[1])
fmt.Printf("SUM: %v\n", firstNum+secondNum)
}
return nil
},
PostRun: func(cmd *cobra.Command, args []string) {
fmt.Println("=== PostRun ===")
},
}
実行。
$ go run main.go -a aaa
=== PreRun ===
Hello aaa
=== PostRun ===
$ go run -mod=mod github.com/spf13/cobra-cli@latest add server
$ tree
.
├── LICENSE
├── cmd
│ ├── root.go
│ └── server.go
├── go.mod
├── go.sum
└── main.go
cmd
配下にファイルが生成されている。
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// serverCmd represents the server command
var serverCmd = &cobra.Command{
Use: "server",
Short: "server を起動します",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("server called")
},
}
func init() {
rootCmd.AddCommand(serverCmd)
}
実行。
$ go run main.go -h
挨拶をします。2 つの int を渡すと計算もします
Usage:
sample [flags]
sample [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
server A brief description of your command
Flags:
-h, --help help for sample
-a, --name string name フラグの説明文です (required)
-n, --night night フラグの説明文です
Use "sample [command] --help" for more information about a command.
server
のヘルプをみる。
$ go run main.go server -h
server を起動します
Usage:
sample server [flags]
Flags:
-h, --help help for server
Global Flags:
-n, --night night フラグの説明文です
$ go run main.go server
server called
subcommand も簡単に実装できそう。