Go cobra 库

cobra

cobra 既是一个用于创建强大现代 CLI 应用程序的库,也是一个生成应用程序和命令文件的程序。cobra 被用在很多 go 语言的项目中,比如 Kubernetes、Docker、Istio、ETCD、Hugo、Github CLI 等等

概念

cobra 中有个重要的概念,分别是 commands、arguments 和 flags。

  • commands 代表行为
  • arguments 就是命令行参数 (或者称为位置参数)
  • flags 代表对行为的改变 (也就是常说的命令行选项)。

执行命令行程序时的一般格式为:

1
APPNAME COMMAND ARG --FLAG

比如下面的例子:

1
2
3
4
5
# server是 commands,port 是 flag
hugo server --port=1313

# clone 是 commands,URL 是 arguments,brae 是 flag
git clone URL --bare

如果是一个简单的程序 (功能单一的程序),使用 commands 的方式可能会很啰嗦,但是像 git、docker 等应用,把这些本就很复杂的功能划分为子命令的形式,会方便使用 (对程序的设计者来说又何尝不是如此)。

创建 cobra 应用

安装 cobra 包:

1
$ go get -u github.com/spf13/cobra/cobra

然后就可以用 cobra 程序生成应用程序框架了:

1
$ cobra init <appname>

此时的程序并没有什么功能,执行它只会输出一些默认的提示信息

cobra 推荐的项目结构如下:

1
2
3
4
5
6
7
+ cmd/
    root.go
    add.go
    your.go
    commands.go
    here.go
  main.go

所有命令放在项目根目录下的 cmd 目录中。其中,默认命令(即不输入任何命令)为 root.go

cobra 应用的 main.go 非常简单,通常如下:

1
2
3
4
5
6
7
8
9
package main

import (
    "{pathToYourApp}/cmd"
)

func main() {
    cmd.Execute()
}

创建 rootCmd

root.go 的内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package cmd

import (
    "fmt"
    "os"

    "github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
    Use:   "demo",
    Short: "A cobra demo",
    Long:  `A cobra demo. xxx...`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("execute root cmd.")
    },
}

func Execute() {
    if err := rootCmd.Execute(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

此时,执行 go run main.go --help,可以看到以下输出:

1
2
3
4
5
6
7
A cobra demo. xxx...

Usage:
  demo [flags]

Flags:
  -h, --help   help for demo

直接执行 go run main.go 会打印 execute root cmd.

创建其他命令

我们再创建一个 print 命令。一般每个命令在 cmd 下都有一个自己的文件。只需要在 cmd 下再新建一个 print.go,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

func init() {
    rootCmd.AddCommand(printCmd)
}

var printCmd = &cobra.Command{
    Use:   "print",
    Short: "print something",
    Long:  "print something, xxx",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("execute print cmd")
    },
}

此时再执行 go run main.go --help 可以看到已经增加了 print 命令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
A cobra demo. xxx...

Usage:
  demo [flags]
  demo [command]

Available Commands:
  help    Help about any command
  print       print something

Flags:
  -h, --help   help for demo

Use "demo [command] --help" for more information about a command.

创建 flag

在执行 print 命令时,我们想传递一些参数,来指定打印的内容,这时我们就需要增加 flags。

flags 分为 persistent flaglocal flagspersistent flag 可以分配给当前命令及其所有子命令,而local flags 只应用于当前命令。

这里给 print 命令增加一个 local flags

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

func init() {
    rootCmd.AddCommand(printCmd)

    printCmd.Flags().StringVarP(&Msg, "message", "m", "default message", "message to be printed")
}

var Msg string
var printCmd = &cobra.Command{
    Use:   "print",
    Short: "print something",
    Long:  "print something, xxx",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println(Msg)
    },
}

这时再使用 go run main.go print 会打印默认内容default message,也可以使用 -m--message 来指定要打印的内容了。