本文上一文章《Golang实践录:命令行cobra库实例》 的优化,主要的子命令的业务实现的整理。
起因
旧版本中,每个子命令的入口函数,均需一一判断传入参数,并调用对应的业务实现函数,编码扩展稍有繁琐,而且也不美观。
思考再三,决定使用结构体数组的形式来优化。
思路
此思路来源于 busybox 。
首先定义结构体:
// 命令列表,包括名称,帮助信息
type UserCmdFunc struct {
Name string
ShortHelp string
// LongHelp string
Func func(args []string)
}
再实现遍历命令列表函数:
func PrintHelpInfo(theCmd []conf.UserCmdFunc) {
fmt.Println("valid command: ");
for _, item:=range theCmd {
fmt.Println(item.Name, "\t:", item.ShortHelp)
}
}
在使用时,只需要定义结构体数组,并填写对应的命令名称,帮助信息,及对应的函数指针即可。示例:
var theCmd = []conf.UserCmdFunc{
conf.UserCmdFunc {
Name: "foo",
ShortHelp: "just a foo help info",
Func: foo,
},
conf.UserCmdFunc {"watch", "watch config file", testWatch,},
}
当命令不合法——亦即无法在结构体数组中找到时,提示合法的命令,提高体验。
由于各子命令位于不同的包中,实际上 theCmd 及子命令入口函数绝大部分代码是相同的,容易扩展。
实现
以子命令 test 为例,旧版本入口源码如下:
func NewCmdTest() *cobra.Command{
var cmd = &cobra.Command{
Use: name,
Short: shortDescription,
Long: longDescription,
Example: example,
RunE: func(cmd *cobra.Command, args []string) error {
if (len(args) == 0) {
klog.Warning("no args found")
return nil
}
// !! 以下要一一判断并调用
if (args[0] == "foo"){
foo(args)
} else if (args[0] == "watch"){
testWatch(args)
} else {
klog.Printf("cmd '%v' not support", args[0])
return nil
}
return nil
},
}
return cmd
}
新版本变化如下:
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
}
测试
默认输出帮助信息:
$ ./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:
--config string config file (config.yaml)
-h, --help help for cmdtool.exe
--print will print sth
--version version for cmdtool.exe
Use "cmdtool.exe [command] --help" for more information about a command.
执行子命令,默认将合法的命令输出:
$ ./cmdtool.exe test
[2020-12-02 17:43:40.771 rootCmd.go:112] helloooooo 100s firstblood
[2020-12-02 17:43:40.772 cmd.go:43] no args found
valid command:
foo : just a foo help info
watch : watch config file
$ ./cmdtool.exe test nocmd
[2020-12-02 17:43:47.953 rootCmd.go:112] helloooooo 100s firstblood
[2020-12-02 17:43:47.954 cmd.go:53] cmd 'nocmd' not support
valid command:
foo : just a foo help info
watch : watch config file
源码
源码在此。 本次也修改了 cobra 帮助信息不对齐的小问题。