cli - 构建强大命令行程序的工具箱 (3)

获取 cli

cli 开源在 github 上,欢迎大家前去 star :-)

使用go get获取

go get github.com/mkideal/cli

上一篇以一个示例讲解了cli库的Command对象和Context对象。本篇将以实例分析讲解cli构建复杂多命令的应用程序。
本实例代码使用goplus生成

goplus new -t tree tree

实例代码

 1    package main
 2    
 3    import (
 4        "fmt"
 5        "os"
 6    
 7        "github.com/mkideal/cli"
 8    )
 9    
10    func main() {
11        if err := cli.Root(root,
12            cli.Tree(help),
13            cli.Tree(version),
14        ).Run(os.Args[1:]); err != nil {
15            fmt.Fprintln(os.Stderr, err)
16            os.Exit(1)
17        }
18    }
19    
20    //--------------
21    // root command
22    //--------------
23    
24    type rootT struct {
25        cli.Helper
26    }
27    
28    var root = &cli.Command{
29        Name: os.Args[0],
30        //Desc: "describe the app",
31        Argv: func() interface{} { return new(rootT) },
32    
33        Fn: func(ctx *cli.Context) error {
34            argv := ctx.Argv().(*rootT)
35            if argv.Help || len(ctx.Args()) == 0 {
36                ctx.WriteUsage()
37                return nil
38            }
39    
40            //TODO: do something
41            return nil
42        },
43    }
44    
45    //--------------
46    // help command
47    //--------------
48    
49    var help = cli.HelpCommand("display help")
50    
51    //-----------------
52    // version command
53    //-----------------
54    
55    const appVersion = "v0.0.1"
56    
57    var version = &cli.Command{
58        Name: "version",
59        Desc: "display version",
60    
61        Fn: func(ctx *cli.Context) error {
62            ctx.String(appVersion + "\n")
63            return nil
64        },
65    }

Root 函数

11行使用cli.Root函数构建了一颗命令树并返回根命令。Root函数接受一个*cli.Command作为第一个参数,它也是Root函数的返回值:根命令, 然后是一个可变数量的子命令树...*CommandTree。Root函数和CommandTree的声明如下:

// Root registers forest for root and return root
func Root(root *Command, forest ...*CommandTree) *Command

CommandTree struct {
    command *Command
    forest  []*CommandTree
}

示例中的

cli.Root(root,
    cli.Tree(help),
    cli.Tree(version),
)

为root命令注册了两颗子树cli.Tree(help)cli.Tree(version)

Tree函数

cli.Tree函数接受和cli.Root一样的参数,不过返回的是一个*cli.CommandTree

func Tree(cmd *Command, forest ...*CommandTree) *CommandTree {
    return &CommandTree{
        command: cmd,
        forest:  forest,
    }
}

help命令的实现

var help = cli.HelpCommand("display help")

使用了cli包提供的实用函数cli.HelpCommand

func HelpCommand(desc string) *Command {
    return &Command{
        Name:        "help",
        Desc:        desc,
        CanSubRoute: true,
        Fn:          HelpCommandFn,
    }
}

HelpCommand使用了内置的HelpCommandFn函数

func HelpCommandFn(ctx *Context) error {
    var (
        args   = ctx.Args()
        parent = ctx.Command().Parent()
    )
    if len(args) == 0 {
        ctx.String(parent.Usage(ctx))
        return nil
    }
    var (
        child = parent.Route(args)
        clr   = ctx.Color()
    )
    if child == nil {
        return fmt.Errorf("command %s not found", clr.Yellow(strings.Join(args, " ")))
    }
    ctx.String(child.Usage(ctx))
    return nil
}

运行

编译程序

$> go build -o tree

终端中运行

$> ./tree
Usage:
  -h, --help     display help

Commands:
  help      display help
  version   display version
$> ./tree help
Usage:
  -h, --help     display help

Commands:
  help      display help
  version   display version
$> ./tree help version
display version

$> ./tree vresion
v0.0.1

更复杂的树可以长这样

cli.Root(
    root,
    cli.Tree(cmd1,
        cli.Tree(cmd11),
        cli.Tree(cmd12),
    ),
    cli.Tree(cmd2,
        cli.Tree(cmd21),
        cli.Tree(cmd22,
            cli.Tree(cmd221),
            cli.Tree(cmd222),
            cli.Tree(cmd223),
        ),
    ),
)

结语

本篇主要介绍了RootTree的用法和两个实用的函数
HelpCommandHelpCommandFn。在 github查看更多示例:

共 0 个回复