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

本文上一文章《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 帮助信息不对齐的小问题。

相关推荐
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页