命令行cobra

安装

Cobra:

$ go get -u github.com/spf13/cobra

Cobra代码生成工具:

$ go get -u github.com/spf13/cobra/cobra

项目自动生成

$ mkdir cobra-demo
$ cd cobra-demo/
$ cobra init --pkg-name cobra-demo
$ go mod init cobra-demo
$ go mod tidy
$ tree
.
├── LICENSE
├── cmd
   └── root.go
├── go.mod
├── go.sum
└── main.go

命令行参数绑定

// 生成的 cmd/root.go 中的 init() 有如下2行绑定 config 参数的代码
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra-demo.yaml)")
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

// 添加类似于如下2行代码,可与 viper 来绑定 flags
rootCmd.PersistentFlags().StringVar(&apiVersion, "apiVersion", "", "apiVersion")
viper.BindPFlag("apiVersion", rootCmd.PersistentFlags().Lookup("apiVersion"))

cmd目录创建对应的配置文件sample.yaml

apiVersion: zhhnzw.mock.com/v1
kind: CustomPod

和相应的sample.go

package cmd

type Config struct  {
	ApiVersion string
	Kind string
}

var Conf = new(Config)

cmd/root.go添加解析到结构体变量的代码:

// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
		if err := viper.Unmarshal(Conf); err != nil {
			panic(fmt.Errorf("unmarshal conf failed, err:%s \n", err))
		}
		fmt.Println(Conf,rootCmd.PersistentFlags().Lookup("apiVersion").Value)
	}

打开rootCMD变量的Run函数,项目代码

Run: func(cmd *cobra.Command, args []string) {
		// 通过 cmd 变量从命令行读取参数,通过 viper 读取绑定的变量的参数
		fmt.Println("read from rootCmd Run:", cmd.Flag("config").Value, cmd.Flag("apiVersion").Value, viper.Get("apiVersion"))
	},

功能验证

# 可以看到cmd如期望的读取出了 config 参数
# 也如期望的绑定了 yaml 文件,读取出了 yaml 设置的默认的apiVersion 参数
$ go run main.go --config ./cmd/sample.yaml
Using config file: ./cmd/sample.yaml
bind Conf: &{zhhnzw.mock.com/v1 CustomPod}
read from rootCmd Run: ./cmd/sample.yaml  zhhnzw.mock.com/v1
# 通过 cmd 或者 viper 来读取,都成功取得了相同的参数值
$ go run main.go --config ./cmd/sample.yaml --apiVersion v2
Using config file: ./cmd/sample.yaml
bind Conf: &{v2 CustomPod}
read from rootCmd Run: ./cmd/sample.yaml v2 v2

添加子命令

$ cobra add sub
// 可以看到,生成的 cmd/sub.go 已经将子命令添加到了 rootCmd 主命令
func init() {
	rootCmd.AddCommand(subCmd)
  // 可以为这个子命令添加专属的 Local Flag
}

修改 subCmd 变量:

var subCmd = &cobra.Command{
	Use:   "sub",
	Short: "求和操作",
	Long: `实现输入参数的求和计算`,
	Run: func(cmd *cobra.Command, args []string) {
		sub := 0
		for k, e := range args {
			fmt.Println("第", k, "个变量:", e)
			v, err := strconv.Atoi(e)
			if err != nil {
				return
			}
			sub += v
		}
		fmt.Println("参数的求和为:", sub)
	},
}

功能验证

$ go run main.go sub 1 2 3
第 0 个变量: 1
第 1 个变量: 2
第 2 个变量: 3
参数的求和为: 6

Command & Flag

如上 sub 为 Command,--config 和 --apiVersion 是 Flag

Command 可以按树型结构嵌套

Persistent Flags & Local Flags

通过 PersistentFlags 绑定的参数在全局生效

Local Flags 绑定的参数在指定的 Command 下生效,在其他的 Command 下查询就查不出来了

Last updated

Was this helpful?