Golang实践录:命令行cobra库实例再三优化

本文是上一文章《Golang实践录:命令行cobra库实例优化》 的优化,主要的子命令的业务实现的整理。

起因

上一版本实现的方式,还是有点不满意,格式也不对齐,重要的是,似乎不是正规的方式。

思路

cobra官方支持多级子命令,经研究测试发现,在实现三级子命令时,稍有麻烦。故舍弃官方的做法。同时参考了部分示例代码,结合得到本文的案例。

实现

旧版本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var theCmd = []conf.UserCmdFunc{
conf.UserCmdFunc {
Name: "foo",
ShortHelp: "just a foo help info",
Func: foo,
},
conf.UserCmdFunc {"watch", "watch config file", testWatch,},
}

func NewCmdTest() *cobra.Command{

var cmd = &cobra.Command{
Use: name,
Short: shortDescription,
Long: longDescription,
Example: example,
RunE: func(cmd *cobra.Command, args []string) error {
truetruetrue//klog.Println(common.DBName)
truetruetrueif (len(args) == 0) {
truetruetruetrueklog.Warning("no args found")
truetruetruetruecommon.PrintHelpInfo(theCmd)
truetruetruetruereturn nil
truetruetrue}
// !! 遍历并调用即可
truetruetruefor _, item:=range theCmd {
truetruetruetrueif (args[0] == item.Name) {
truetruetruetruetrueitem.Func(args)
truetruetruetruetruereturn nil
truetruetruetrue}
truetruetrue}
truetruetrueklog.Printf("cmd '%v' not support", args[0])
truetruetruecommon.PrintHelpInfo(theCmd)
return nil
},
}
// note:使用子命令形式,下列可在help中展开
// 命令参数,保存的值,参数名,默认参数,说明
//cmd.Flags().StringVar(&mode, "db", "-", "set the database name")

return cmd
}

新版本修改如下:

根据命令参数长度补齐:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// rpad adds padding to the right of a string.
func rpad(s string, padding int) string {
truetemplate := fmt.Sprintf("%%-%ds", padding)
truereturn fmt.Sprintf(template, s)
}

func GetHelpInfo(theCmd []conf.UserCmdFunc) (ret string) {
trueret = fmt.Sprintf("Available Commands:\n");

truefor _, item := range theCmd {
truetruenameLen := len(item.Name)
truetrueif nameLen > cmdMaxLen {
truetruetruecmdMaxLen = nameLen
truetrue}
true}
true
truefor _, item := range theCmd {
truetrueret += fmt.Sprintf(" %v %v\n", rpad(item.Name, cmdMaxLen), item.ShortHelp)
true}
true
truereturn
}

子命令实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

var mode int

func NewCmdTest() *cobra.Command{

var cmd = &cobra.Command{
Use: name,
Short: shortDescription,
Long: longDescription + "\n" + common.GetHelpInfo(theCmd),
Example: example,
RunE: func(cmd *cobra.Command, args []string) error {
truetruetrue// 1 没有参数
truetruetrueif (len(args) == 0) {
truetruetruetrue//klog.Warning("no args found")
truetruetruetrue//common.PrintHelpInfo(theCmd)
truetruetruetruecmd.Help()
truetruetruetruereturn nil
truetruetrue}

truetruetrue// 2 遍历是否有合法的参数,如无则提示
truetruetrueidx := -1
truetruetruefor idx1, item := range theCmd {
truetruetruetrueif (args[0] == item.Name) {
truetruetruetruetrueidx = idx1 // why ???
truetruetruetruetruebreak
truetruetruetrue}
truetruetrue}
truetruetrueif idx == -1 {
truetruetruetrueklog.Printf("arg '%v' not support", args[0])
truetruetruetruecmd.Help()
truetruetruetruereturn nil
truetruetrue}
truetruetrue
truetruetrue// 3 执行公共的初始化
truetruetrueklog.Printf("bussiness init, mode: %v\n", mode) // just test

truetruetrue// 4 执行命令
truetruetruetheCmd[idx].Func(args)

truetruetruereturn nil
},
}
// note:使用子命令形式,下列可在help中展开
// 命令参数,保存的值,参数名,默认参数,说明
truecmd.Flags().IntVarP(&mode, "mode", "m", 0, "set the test mode")

return cmd
}

修改1:将自定义的帮助信息纳入到Long字段,利用默认的cmd.Help()输出信息(要添加自定义的部分信息)。
修改2:先遍历自定义的命令列表,没有时提示帮助信息,有则执行。

测试

默认输出帮助信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ ./cmdtool.exe
cmd test tool.
【中文样例】命令终端测试示例工具。

Usage:
cmdtool.exe [command]

Examples:
comming soon...


Available Commands:
db db command
help Help about any command
misc misc command
test test command

Flags:
-c, --config string config file (config.yaml)
-h, --help help for cmdtool.exe
-o, --output string specify the output file name
-p, --print verbose output
--version version for cmdtool.exe

Use "cmdtool.exe [command] --help" for more information about a command.

执行子命令,默认将合法的命令输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
$ ./cmdtool.exe test
[2020-12-11 14:51:24.009 rootCmd.go:115] helloooooo 100s firstblood
test...

Available Commands:
foo just a foo help info
watch watch config file

Usage:
cmdtool.exe test [flags]

Examples:
example comming up...


Flags:
-h, --help help for test
-m, --mode int set the test mode

Global Flags:
-c, --config string config file (config.yaml)
-o, --output string specify the output file name
-p, --print verbose output


$ ./cmdtool.exe test nocmd
[2020-12-11 14:53:13.301 rootCmd.go:115] helloooooo 100s firstblood
[2020-12-11 14:53:13.303 cmd.go:60] arg 'nocmd' not support
test...

Available Commands:
foo just a foo help info
watch watch config file

Usage:
cmdtool.exe test [flags]

Examples:
example comming up...


Flags:
-h, --help help for test
-m, --mode int set the test mode

Global Flags:
-c, --config string config file (config.yaml)
-o, --output string specify the output file name
-p, --print verbose output

源码

源码在此