本文在上一文章《Golang实践录:命令行cobra库实例》 的基础上继续进行优化,主要优化的部分是子命令的业务实现。
起因
旧版本中,每个子命令的入口函数,均需一一判断传入参数,并调用对应的业务实现函数,编码扩展稍有繁琐,而且也不美观。 思考再三,决定使用结构体数组的形式来优化。
思路
此思路来源于 busybox 。
首先定义结构体:
//命令列表,包括名称,帮助信息typeUserCmdFuncstruct{NamestringShortHelpstring//LongHelpstringFuncfunc(args[]string)}
再实现遍历命令列表函数:
funcPrintHelpInfo(theCmd[]conf.UserCmdFunc){fmt.Println("validcommand:");for_,item:=rangetheCmd{fmt.Println(item.Name,"\t:",item.ShortHelp)}}
在使用时,只需要定义结构体数组,并填写对应的命令名称,帮助信息,及对应的函数指针即可。示例:
vartheCmd=[]conf.UserCmdFunc{conf.UserCmdFunc{Name:"foo",ShortHelp:"justafoohelpinfo",Func:foo,},conf.UserCmdFunc{"watch","watchconfigfile",testWatch,},}
当命令不合法——亦即无法在结构体数组中找到时,提示合法的命令,提高体验。 由于各子命令位于不同的包中,实际上 theCmd 及子命令入口函数绝大部分代码是相同的,容易扩展。
实现
以子命令 test 为例,旧版本入口源码如下:
funcNewCmdTest()*cobra.Command{varcmd=&cobra.Command{Use:name,Short:shortDescription,Long:longDescription,Example:example,RunE:func(cmd*cobra.Command,args[]string)error{if(len(args)==0){klog.Warning("noargsfound")returnnil}//!!以下要一一判断并调用if(args[0]=="foo"){foo(args)}elseif(args[0]=="watch"){testWatch(args)}else{klog.Printf("cmd'%v'notsupport",args[0])returnnil}returnnil},}returncmd}
新版本变化如下:
vartheCmd=[]conf.UserCmdFunc{conf.UserCmdFunc{Name:"foo",ShortHelp:"justafoohelpinfo",Func:foo,},conf.UserCmdFunc{"watch","watchconfigfile",testWatch,},}funcNewCmdTest()*cobra.Command{varcmd=&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("noargsfound")common.PrintHelpInfo(theCmd)returnnil}//!!遍历并调用即可for_,item:=rangetheCmd{if(args[0]==item.Name){item.Func(args)returnnil}}klog.Printf("cmd'%v'notsupport",args[0])common.PrintHelpInfo(theCmd)returnnil},}//note:使用子命令形式,下列可在help中展开//命令参数,保存的值,参数名,默认参数,说明//cmd.Flags().StringVar(&mode,"db","-","setthedatabasename")returncmd}
测试
默认输出帮助信息:
$./cmdtool.execmdtesttool.命令终端测试示例工具。Usage:cmdtool.exe[command]Examples:commingsoon...AvailableCommands:dbdbcommandhelpHelpaboutanycommandmiscmisccommandtesttestcommandFlags:--configstringconfigfile(config.yaml)-h,--helphelpforcmdtool.exe--printwillprintsth--versionversionforcmdtool.exeUse"cmdtool.exe[command]--help"formoreinformationaboutacommand.
执行子命令,默认将合法的命令输出:
$./cmdtool.exetest[2020-12-0217:43:40.771rootCmd.go:112]helloooooo100sfirstblood[2020-12-0217:43:40.772cmd.go:43]noargsfoundvalidcommand:foo:justafoohelpinfowatch:watchconfigfile$./cmdtool.exetestnocmd[2020-12-0217:43:47.953rootCmd.go:112]helloooooo100sfirstblood[2020-12-0217:43:47.954cmd.go:53]cmd'nocmd'notsupportvalidcommand:foo:justafoohelpinfowatch:watchconfigfile
源码
源码在此。 本次也修改了 cobra 帮助信息不对齐的小问题。