本文是上一文章《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
源码 源码在此 。