本文是上一文章《Golang实践录:命令行cobra库实例优化》 的优化,主要的子命令的业务实现的整理。
起因
上一版本实现的方式,还是有点不满意,格式也不对齐,重要的是,似乎不是正规的方式。
思路
cobra官方支持多级子命令,经研究测试发现,在实现三级子命令时,稍有麻烦。故舍弃官方的做法。同时参考了部分示例代码,结合得到本文的案例。
实现
旧版本如下:
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 {//klog.Println(common.DBName)if (len(args) == 0) {klog.Warning("no args found")common.PrintHelpInfo(theCmd)return nil}// !! 遍历并调用即可for _, item:=range theCmd {if (args[0] == item.Name) {item.Func(args)return nil}}klog.Printf("cmd '%v' not support", args[0])common.PrintHelpInfo(theCmd)return nil},}// note:使用子命令形式,下列可在help中展开// 命令参数,保存的值,参数名,默认参数,说明//cmd.Flags().StringVar(&mode, "db", "-", "set the database name")return cmd
}
新版本修改如下:
根据命令参数长度补齐:
// rpad adds padding to the right of a string.
func rpad(s string, padding int) string {template := fmt.Sprintf("%%-%ds", padding)return fmt.Sprintf(template, s)
}func GetHelpInfo(theCmd []conf.UserCmdFunc) (ret string) {ret = fmt.Sprintf("Available Commands:\n");for _, item := range theCmd {nameLen := len(item.Name)if nameLen > cmdMaxLen {cmdMaxLen = nameLen}}for _, item := range theCmd {ret += fmt.Sprintf(" %v %v\n", rpad(item.Name, cmdMaxLen), item.ShortHelp)}return
}
子命令实现:
var mode intfunc 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 {// 1 没有参数if (len(args) == 0) {//klog.Warning("no args found")//common.PrintHelpInfo(theCmd)cmd.Help()return nil}// 2 遍历是否有合法的参数,如无则提示idx := -1for idx1, item := range theCmd {if (args[0] == item.Name) {idx = idx1 // why ???break}}if idx == -1 {klog.Printf("arg '%v' not support", args[0])cmd.Help()return nil}// 3 执行公共的初始化klog.Printf("bussiness init, mode: %v\n", mode) // just test// 4 执行命令theCmd[idx].Func(args)return nil},}// note:使用子命令形式,下列可在help中展开// 命令参数,保存的值,参数名,默认参数,说明cmd.Flags().IntVarP(&mode, "mode", "m", 0, "set the test mode")return cmd
}
Longcmd.Help()
测试
默认输出帮助信息:
$ ./cmdtool.execmd test tool.【中文样例】命令终端测试示例工具。Usage:cmdtool.exe [command]Examples:comming soon...Available Commands:db db commandhelp Help about any commandmisc misc commandtest test commandFlags:-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.exeUse "cmdtool.exe [command] --help" for more information about a command.
执行子命令,默认将合法的命令输出:
$ ./cmdtool.exe test
[2020-12-11 14:51:24.009 rootCmd.go:115] helloooooo 100s firstblood
test...Available Commands:foo just a foo help infowatch watch config fileUsage:cmdtool.exe test [flags]Examples:example comming up...Flags:-h, --help help for test-m, --mode int set the test modeGlobal 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 infowatch watch config fileUsage:cmdtool.exe test [flags]Examples:example comming up...Flags:-h, --help help for test-m, --mode int set the test modeGlobal Flags:-c, --config string config file (config.yaml)-o, --output string specify the output file name-p, --print verbose output
源码
源码在此。