Github:https://github.com/spf13/cobra
Cobra 是一个第三方 Golang 包,是一个应用程序生成框架,用于创建自己的应用程序或命令行(Command)程序,从而开发以 Cobra 为基础的应用。目前 Docker、Kubernetes、Hugo 等著名项目都使用了 Cobra。
Cobra 提供的功能:
执行命令行程序时的一般格式为:
APPNAME COMMAND ARG --FLAG
# e.g.
git clone --bare
通过 cobra init 指令来初始化一个应用程序的项目框架,同时还会自动生成 RootCmd(根命令)的代码。
GO111MODULE="off"
$ go get -u github.com/spf13/cobra/cobra
$ mkdir $GOPATH/src/cobrademo
$ cd $GOPATH/src/cobrademo
$ cobra init --pkg-name cobrademo
$ go build
GO111MODULE="on"
$ go get -u github.com/spf13/cobra/cobra
$ mkdir cobrademo
$ cd cobrademo
$ cobra init --pkg-name cobrademo
$ go mod init cobrademo
$ go build
项目的目录树:
$ tree -T 1
.
├── cmd
│ └── root.go
├── cobrademo
├── go.mod
├── go.sum
├── LICENSE
└── main.go
main.go 非常简约,只做一件事:初始化 Cobra Application 的 RootCmd。
// file: /root/cobrademo/main.go
package main
import "cobrademo/cmd"
func main() {
cmd.Execute()
}
import cmd package 之后就完成了 cmd 包内所有局部变量的初始化,最主要的就是 rootCmd 变量:
// file: /root/cobrademo/cmd/root.go
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "cobrademo",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}
可见,初始的,Cobra Application 的 RootCmd 不具备任何逻辑功能,仅仅是输出一些描述信息。
$ ./cobrademo
A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.
我们可以通过 cobra add 指令来为 RootCmd 生成 SubCmd。
$ cobra add image
image created at /root/cobrademo
$ cobra add container
container created at /root/cobrademo
当前的目录树:
$ tree -T 1
.
├── cmd
│ ├── container.go
│ ├── image.go
│ └── root.go
├── cobrademo
├── go.mod
├── go.sum
├── LICENSE
└── main.go
上述两条指令,分别生成了 cobrademo 程序中 image 和 container 子命令的代码文件,通常存放在 /cmd 目录下。父命令和子命令之间的关系通过 AddCommand 方法来确定,通常被实现在子命令的 init() 函数中。
// file: /root/cobrademo/cmd/container.go
// containerCmd represents the container command
var containerCmd = &cobra.Command{
Use: "container",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("container called")
},
}
func init() {
rootCmd.AddCommand(containerCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// containerCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// containerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
同样的,子命令具体的功能逻辑也需要开发者自己来实现,初始的只是输出一些描述信息。但父子命令的关系以及相关的说明文档,Cobra 已经自动的完成了。
./cobrademo
A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.
Usage:
cobrademo [command]
Available Commands:
container A brief description of your command
help Help about any command
image A brief description of your command
Flags:
--config string config file (default is $HOME/.cobrademo.yaml)
-h, --help help for cobrademo
-t, --toggle Help message for toggle
Use "cobrademo [command] --help" for more information about a command.
目前为止我们为 cobrademo 应用程序添加了三个 Command:
当我们需要为 RootCmd 实现逻辑功能时,只需要编辑 cmd/root.go,找到变量 rootCmd 的初始化过程并为之实现 Run 方法:
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "cobrademo",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
// rootCmd 的逻辑实现
fmt.Println("cobra demo program")
},
}
再次编译并运行:
$ ./cobrademo
cobra demo program
其他的 SubCmd(image、container)以此类推,即可实现其各自的逻辑,通常是在别的 Package 中完成了具体的逻辑实现了,然后再收敛到 Run 方法中进行调用。可见基于 Cobra 框架,开发者可以非常简易的实现一个基于指令行的应用程序。
Command 执行的操作是通过 Command.Run 方法实现的。Cobra 还支持我们在 Run 方法执行的前后执行一些其它的操作,以下是各类 Run 方法的执行顺序:
其中的 PersistentPreRun 方法和 PersistentPostRun 方法可以伴随着任何子命令的执行。
在 Cobra 中,Flags 是用来控制 Command 具体行为的。
Flags 具有 2 种类型:
var Verbose bool
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
var Source string
rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
另外的,Cobra 提供了 MarkFlagRequired() 方法,用于标记一个选项是 “可选的” 还是 “必选的”:
var Name string
rootCmd.Flags().StringVarP(&Name, "name", "n", "", "user name (required)")
rootCmd.MarkFlagRequired("name")
通常的,会在 Command 文件的 init() 函数中完成 Command 相应的 Flags 的定义,例如:
// file: /root/cobrademo/cmd/root.go
var cfgFile string
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobrademo.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
需要注意的是,当 Flag 定义好了,并且 Flag 需要接受 Args 时,我们还需要定义一个变量来关联这些标志,继而完成 Args 参数的接收。例如,当我们执行指令 ./cobrademo --config=test.yaml
时,上述代码中的 cfgFile 变量值就会被赋予 test.yaml
。
常见的,有两种 Arguments 的使用方式:
./cobrademo test
,参数值会传入 Command 的 Run: func(cmd *cobra.Command, args []string)
args 参数中。./cobrademo --config=test.yaml
,参数值会传递到 Flag 对应的变量。Cobra 对 Arguments 的处理,主要是两件事情:
Cobra Build-in 提供了一系列的验证方法:
例如:要让 cmdTimes 至少有一个 Arg,则可以这样初始化它:
var cmdTimes = &cobra.Command{
Use: …
Short: …
Long: …
Args: cobra.MinimumNArgs(1),
Run: …
}
Cobra 也支持自定义验证,示例:直接编写 Args func。
var cmd = &cobra.Command{
Short: "hello",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("requires at least one arg")
}
if myapp.IsValidColor(args[0]) {
return nil
}
return fmt.Errorf("invalid color specified: %s", args[0])
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, World!")
},
}
Cobra 会自动为应用程序添加 help 子命令和 --help 选项,两种的效果是一样的。区别在于 help 子命令还可以接受其他子命令的名称作为 Args 参数,继而返回其他子命令的帮助手册。
例如:
$ cobrademo help image
$ cobrademo help image times
此外,开发者还可以通过下面的方式进行自定义:
cmd.SetHelpCommand(cmd *Command)
cmd.SetHelpFunc(f func(*Command, []string))
cmd.SetHelpTemplate(s string)
提示信息和帮助信息是类型的,Cobra 会自动添加,只不过提示信息是你输入了非法参数、选项或命令时才出现的。
$ ./cobrademo --test
Error: unknown flag: --test
Usage:
cobrademo [flags]
cobrademo [command]
Available Commands:
container A brief description of your command
help Help about any command
image Print images information
Flags:
--config string config file (default is $HOME/.cobrademo.yaml)
-h, --help help for cobrademo
-t, --toggle Help message for toggle
Use "cobrademo [command] --help" for more information about a command.
unknown flag: --test
同样可以自定义提示信息:
cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string)
此外,如果我们输入了不正确的命令或者是选项,Cobra 还会给出模糊提示:
$ ./cobrademo im
Error: unknown command "im" for "cobrademo"
Did you mean this?
image
Run 'cobrademo --help' for usage.
unknown command "im" for "cobrademo"
Did you mean this?
image
Cobra 可以基于子命令,标记,等生成文档。支持以下格式:
init() 函数除了定义 Flags 和父子命令关系之外,还会完成 initConfig:从环境变量或配置文件加载配置选项,以此来覆盖或填充没有通过指令行参数进行配置的 Flags 值。
// file: /root/cobrademo/cmd/root.go
3
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".cobrademo" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".cobrademo")
}
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
请浏览《Go 语言编程 — viper 配置管理工具》。
为 image 子命令添加一个 cmdTimes 子命令,用于根据 times(次数)打印输入的单词。
package cmd
import (
"fmt"
"strings"
"github.com/spf13/cobra"
)
// imageCmd represents the image command
var imageCmd = &cobra.Command{
Use: "image",
Short: "Print images information",
Long: "Print all images information",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("image args are : " + strings.Join(args, " "))
},
}
var echoTimes int
var cmdTimes = &cobra.Command{
Use: "times [string to echo]",
Short: "Echo anything to the screen more times",
Long: `echo things multiple times back to the user by providing a count and a string.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
for i := 0; i < echoTimes; i++ {
fmt.Println("Echo: " + strings.Join(args, " "))
}
},
}
func init() {
cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
imageCmd.AddCommand(cmdTimes)
rootCmd.AddCommand(imageCmd)
}
重新编译并执行:
$ ./cobrademo image hello
image args are : hello
$ ./cobrademo image times -t=3 world
Echo: world
Echo: world
Echo: world
$ ./cobrademo image times -t=3
Error: requires at least 1 arg(s), only received 0
Usage:
cobrademo image times [string to echo] [flags]
Flags:
-h, --help help for times
-t, --times int times to echo the input (default 1)
Global Flags:
--config string config file (default is $HOME/.cobrademo.yaml)
requires at least 1 arg(s), only received 0
注:因为我们在代码中为 cmdTimes 子命令设置了 Args 检查:cobra.MinimumNArgs(1) ,所以必须为 times 子命令传入一个参数。
https://www.cnblogs.com/sparkdev/p/10856077.html
https://www.cnblogs.com/borey/p/5715641.html
https://www.jianshu.com/p/7abe7cff5384