Go语言中,我们可以使用cobra很方便的进行命令行工具的开发,kubelet命令就是使用这个库开发的。在这片博客中,我将会总结一下我学习cobra库的笔记,希望对你有帮助。点击这里可以进入cobra官方说明。
go get github.com/spf13/cobra/cobra
将cobra下载完成后,GOPATH/bin目录会生成一个cobra可执行程序,通过这个程序我们可以初始化一个cobra代码框架。
我们可以通过下面的命令初始化项目:
mkdir -p newApp && cd newApp
cobra init --pkg-name github.com/spf13/newApp
或者
cobra init --pkg-name github.com/spf13/newApp path/to/newApp
上面是官方的示例,需要注意的是–pkg-name后面接的是你要编写的命令的名称,不一定是你新建目录的名称。
这里我举个例子,初始化一个time命令:
$ cobra init --pkg-name time
Your Cobra applicaton is ready at
D:\GOCODE\cobraStudy
初始化之后可以看到,cobra命令在项目目录底下创建了开发框架:
root.go代码中有一个rootCmd变量:
函数initConfig(): 用来初始化viper配置文件位置,监听变化。
函数init(): 定义flag和配置处理。
我们可以编译一下:
$ go build -o time main.go
然后执行time命令:
$ ./time
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.
因为我们开没有进行开发,因此我们可以看到当前time命令只有一些帮助信息。
添加命令之前我们需要理解cobra的三个概念:
其中commands代表行为,arguments代表数值,flags代表对行为的改变。
执行命令行程序时的一般格式为:
[appName] [command] [arguments] --[flag]
这里我们在上面创建的项目基础上添加命令:
$ cobra add show
show created at D:\GOCODE\cobraStudy
此时,cmd目录会多一个show.go的文件,我们可以在这个文件中定义show具体执行的操作,这里的show就是上面说的command。
我们现在编译一下代码:
$ go build -o time main.go
执行命令,我们可以看到time命令的帮助信息,在usage中我们可以看到,当前有两个command一个是默认的help另一个就是我们刚才创建的show,Flags也有两个,这是初始化的时候自带的,后面我们可以自己进行修改。
$ ./time
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:
time [command]
Available Commands:
help Help about any command
show A brief description of your command
Flags:
--config string config file (default is $HOME/.time.yaml)
-h, --help help for time
-t, --toggle Help message for toggle
Use "time [command] --help" for more information about a command.
选项(flags)用来控制 Command 的具体行为。根据选项的作用范围,可以把选项分为两类:
1)对于 persistent 类型的选项,既可以设置给该 Command,又可以设置给该 Command 的子 Command。对于一些全局性的选项,比较适合设置为 persistent 类型,比如控制输出的 verbose 选项:
我们创建一个test命令:
$ cobra add test
test created at D:\GOCODE\cobraStudy
在test.go文件的init()函数中我们可以通过下面的方式给test命令添加flags:
// 下面定义了一个Flag foo, foo后面接的值会被赋值给Foo
Foo = testCmd.PersistentFlags().String("foo", "", "A help for foo")
// 下面定义了一个Flag print ,print后面的值会被赋值给Print变量
testCmd.PersistentFlags().StringVar(&Print, "print", "", "print")
// 下面定义了一个Flag show,show默认为false, 有两种调用方式--show\-s,命令后面接了show则上面定义的show变量就会变成true
testCmd.PersistentFlags().BoolVarP(&show, "show", "s", false, "show")
需要注意的是,上例中我创建的Foo、Print、show都是全局变量,如果没有创建,代码会执行不成功。
上面是常见的定义方式,更多定义方式请参考原码。
我们修改一下Run后面的函数:
Run: func(cmd *cobra.Command, args []string) {
if show {
fmt.Println("Show")
}
fmt.Println("Print:", Print)
fmt.Println("Foo:", *Foo)
},
编译后执行命令:
$ ./time test --foo hello -s --print world
Show
Print: world
Foo: hello
2)local 类型的选项只能设置给指定的 Command:
// 下面定义了一个Flag show,show默认为false, 有两种调用方式--show\-s,命令后面接了show则上面定义的show变量就会变成true
showL = *testCmd.Flags().BoolP("showL", "S", false, "show")
// 下面定义了一个Flag print ,print后面的值会被赋值给Print变量
testCmd.Flags().StringVar(&PrintL, "printL", "", "print")
// 下面定义了一个Flag foo, foo后面接的值会被赋值给Foo
FooL = testCmd.Flags().String("fooL", "", "A help for foo")
默认情况下的选项都是可选的,但一些用例要求用户必须设置某些选项,这种情况 cobra 也是支持的,通过 Command 的 MarkFlagRequired 方法标记该选项即可:
show = *testCmd.Flags().BoolP("show", "s", false, "show")
// 设置使用test的时候后面必须接show
_ = testCmd.MarkFlagRequired("show")
首先我们来搞清楚命令行参数(arguments)与命令行选项(flags/options)的区别。以常见的 ls 命令来说,其命令行的格式为:
$ ls --help
Usage: ls [OPTION]... [FILE]...
其中的 OPTION 对应本文中介绍的 flags,以 - 或 – 开头;而 FILE 则被称为参数(arguments)或位置参数。一般的规则是参数在所有选项的后面,上面的 … 表示可以指定多个选项和多个参数。
cobra 默认提供了一些验证方法:
比如要让 Command cmdTimes 至少有一个位置参数,可以这样初始化它:
// testCmd represents the test command
var testCmd = &cobra.Command{
Use: "test",
// 定义arguments数量最少为1个
Args: cobra.MinimumNArgs(1),
Short: "short usage",
Long: `Long usage`,
Run: func(cmd *cobra.Command, args []string) {
if show {
fmt.Println("Show")
fmt.Println("Print:", Print)
fmt.Println("Foo:", *Foo)
}
},
}
功能功能说明:
(1)show
查看当前时间
(2)parse
指定时间格式 --format,parse为show的子命令。
在第一部分我们已经添加了show命令,现在我们修改show.go文件。
1)首先我们实现输出当前时间的功能。
下面是初始化的内容:
// showCmd represents the show command
var showCmd = &cobra.Command{
Use: "show",
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("show called")
},
}
命令实现的功能由Command.Run控制,我们定义一个函数,输出当前时间:
// ShowTime 显示当前时间
func ShowTime(cmd *cobra.Command, args []string) {
fmt.Println(time.Now())
}
然后将函数给Command.Run赋值:
// showCmd represents the show command
var showCmd = &cobra.Command{
Use: "show",
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: ShowTime, // 这里改为函数名称
}
2)修改help命令。
help命令有两个,一个是short一个是lang,很明显short命令用来定义简短的说明,lang命令用来定义详细说明,下面我们修改show命令的help:
// showCmd represents the show command
var showCmd = &cobra.Command{
Use: "show",
Short: "Displays the current time",
Long: `You can use the time show command to view the current time. For example:
$ ./time show
2020-07-03 15:01:59.6035666 +0800 CST m=+0.013998501`,
Run: ShowTime,
}
修改完成,我们编译代码:
$ go build -o time main.go
执行time命令,我们可以看到show命令后面的说明变成了我们定义的简短说明:
$ ./time
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:
time [command]
Available Commands:
help Help about any command
show Displays the current time
Flags:
--config string config file (default is $HOME/.time.yaml)
-h, --help help for time
-t, --toggle Help message for toggle
Use "time [command] --help" for more information about a command.
我们再执行time show --help命令,可以看到现在展示了show命令的详细说明:
$ ./time show --help
You can use the time show command to view the current time. For example:
$ ./time show
2020-07-03 15:01:59.6035666 +0800 CST m=+0.013998501
Usage:
time show [flags]
Flags:
-h, --help help for show
Global Flags:
--config string config file (default is $HOME/.time.yaml)
1)添加parse命令
下面的命令通过-p指定parse为show的子命令,注意命令后面接Cmd
。
$ cobra add parse -p showCmd
parse created at D:\GOCODE\cobraStudy
2)编辑parse命令
// parseCmd represents the parse command
var parseCmd = &cobra.Command{
Use: "parse",
Short: "Format current time",
Long: `Format current time. For example:
time show parse --format "2006:01:02 15:04:05".`,
Run: func(cmd *cobra.Command, args []string) {
// 输出格式化之后的时间
fmt.Println(time.Now().Format(format))
},
}
var format string
func init() {
showCmd.AddCommand(parseCmd)
parseCmd.Flags().StringVarP(&format, "format", "f", "", "Help message for toggle")
// 这里指定format flag为必须
_ = parseCmd.MarkFlagRequired("format")
}
编译命令并执行:
$ ./time show parse --format="2006:01:02 15:04:05"
2020:07:03 17:04:05
修改root.go文件,删除没有用的代码:
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "time",
Short: "Show Current Time",
Long: `Show Current Time. For example:
With this command, you can view the current time or customize the time format.`,
}
func init() {
cobra.OnInitialize(initConfig)
}
测试一下命令:
random@random-wz MINGW64 /d/GOCODE/cobraStudy
$ ./time --help
Show Current Time. For example:
With this command, you can view the current time or customize the time format.
Usage:
time [command]
Available Commands:
help Help about any command
show Displays the current time
Flags:
-h, --help help for time
Use "time [command] --help" for more information about a command.
random@random-wz MINGW64 /d/GOCODE/cobraStudy
$ ./time show
2020-07-03 17:10:04.8230742 +0800 CST m=+0.014971101
random@random-wz MINGW64 /d/GOCODE/cobraStudy
$ ./time show parse
Error: required flag(s) "format" not set
Usage:
time show parse [flags]
Flags:
-f, --format string Help message for toggle
-h, --help help for parse
required flag(s) "format" not set
random@random-wz MINGW64 /d/GOCODE/cobraStudy
$ ./time show parse -f "15:04:05"
17:10:25