Logo
Section 1 / 13

Cobra 入门

在本课程中,你将学习 Cobra,它是 Go 命令行程序的事实标准。

导入

Cobra 入门

在本课程中,你将学习 Cobra,它是 Go 命令行程序的事实标准。

Cobra 既是处理命令行参数和组织命令的库,也是一个可以为你的程序生成结构化骨架的应用程序。它被众多知名的 Go 命令行工具广泛使用,例如 kubectl(Kubernetes CLI)和 docker(Docker CLI)。

Cobra 指挥官

Cobra 的名字来源于漫画反派 Cobra Commander,他是 G.I Joe 漫画宇宙中“Cobra”恐怖组织的最高领导人。这为一个命令行程序工具提供了绝佳的灵感。它还有一个很棒的标志!

cobra commander.png
cobra commander.png

Cobra 的作者 Steve Francia 在 Google 工作,开发了多个其他著名的 Go 库和程序,特别是 Hugo 和 Viper。剧透预警:我们稍后将在 multi-git 中集成 Viper。

好的。让我们来看看 Cobra 到底是什么。

为什么选择 Cobra?

Cobra 成熟、经过实战检验,并提供了大量功能。它很可能已被其他 Go 开发者所熟悉,因此如果你与他人协作,他们使用 Cobra 构建的命令行程序会感觉非常顺手。以下是 Cobra 提供的一些特性:

  • 命令与嵌套子命令
  • 符合 POSIX 标准的标志(包括短名和长名)
  • 全局、局部和级联标志
  • 轻松生成应用程序骨架
  • 智能拼写建议
  • 可选地与 viper 紧密集成以支持 12 因素应用

还有更多功能。你可能不需要全部这些能力,但即使只需要其中少数几项,Cobra 也能开箱即用地提供给你。

让我们看看 Cobra 是如何组织的。

理解 Cobra 的概念

Cobra 基于命令、参数和标志的概念。基本思想是命令行应像一句话一样:

1<Application Name> <verb> <noun> <adjective>

动词对应命令,名词对应参数,标志对应形容词:

1<Application name> <command> <argument> <flag>

安装 Cobra 本身就是一个很好的例子:

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

应用程序名称是 go,动词是 get,参数是 Cobra 包名 github.com/spf13/cobra/cobra,形容词是 -u,表示更新。

然而,当遇到嵌套命令、多个参数或多个标志时,这种映射很快就会失效。例如,基本的 kubectl 命令 kubectl get pods 会获取默认命名空间中的 Pod 列表,并打印一些相关信息。在这个命令中,应用程序名称是 kubectl,命令是嵌套的 get pods,没有参数或标志。如果从英语句子的角度来看,Pod 就是名词。现在,如果你想获取特定的 Pod,就需要向命令传递一个参数:kubectl get pod <pod name>。但从英语语法角度看,名词是 pod <pod name>,这既像嵌套命令又像参数。

总之,这个类比有时会被拉得太远。请以它最初提供的精神来理解——作为构建一致、易于使用和理解的命令行 API 的一般指导原则。

命令

命令是 Cobra 构建的基础概念。命令可以有子命令,每一层级的命令都可以关联一个操作。作为应用程序开发者,我们的任务是设计一组命令和子命令,作为程序的命令行接口。

Cobra 通过提供一个功能丰富的命令类型来帮助我们,该类型包含数十种不同的方法。我们将在下一课中探索其中许多方法。

命令和子命令必须按正确的顺序出现在命令行中,并且在任何参数之前。标志可以随意分布。

1command --flag1 sub-command --flag2 arg1 arg2 --flag3

参数

参数通常是命令操作的对象。它可以是文件名、URL 或其他任何内容。命令可以接受零个或多个参数。有些命令可以接收任意数量的参数,并对所有参数进行操作。例如,cat 命令接受任意数量的文件名,将它们连接起来并输出到标准输出:

1$ cat file-1 file-2 ... file-N

Cobra 区分位置参数(必须出现在特定位置)和自定义参数。Cobra 提供了多种方式来指定和验证传给命令的参数数量正确。你可以要求以下验证:

验证方法说明
NoArgs命令不接受任何参数。
ArbitraryArgs命令接受任意参数,对数量或类型无限制。
OnlyValidArgs命令要求所有位置参数都在 Command 的 ValidArgs 字段中。
MinimumNArgs(int N)命令至少需要 N 个位置参数。
MaximumNArgs(int N)命令最多允许 N 个位置参数。
ExactArgs(int N)命令恰好需要 N 个位置参数。
ExactValidArgs(int N)命令恰好需要 N 个位置参数,且所有位置参数都必须在 Command 的 ValidArgs 字段中。
RangeArgs(min, max)命令允许参数数量在范围 [min..max] 内(包含边界)。

你还可以为参数定义自定义验证器,这些是接受所有参数并可在违反自定义验证规则时返回错误的函数。自定义验证函数的签名如下:

1func(cmd *cobra.Command, args []string) error

标志

标志是一种修改命令行为的方式。有时并不总是清楚某事物应该是一个命令、一个标志还是一个参数。例如,许多命令行程序都有一个 version 命令,而另一些则有一个 --version 标志。最终结果相同,都会显示版本信息,但从 CLI 设计角度来看,保持一致的方法更好,以避免让用户困惑。

Git 采取了高标准的做法,同时定义了版本命令和 --version 标志:

1$ git version 2git version 2.25.0

标志始终是可选的。当标志不存在时,执行默认行为。标志可以是裸标志,即不带额外信息。当标志存在时,命令的行为与不存在时不同。例如,git 的 -p 标志会将输出发送到 less 以实现分页查看。

1commit 636ba8edb8b24c79059f8dbc4fb895a8a7cac013 (HEAD -> master, origin/master, origin/HEAD) 2Author: the-gigi <the.gigi@gmail.com> 3Date: Tue Dec 31 14:09:41 2019 -0800 4 5 Sync 6 7commit 8b672d75480e68f4f5973ad7f2777409b186e833 8Author: the-gigi <the.gigi@gmail.com> 9Date: Tue Dec 31 13:03:43 2019 -0800 10 11 check that repo names are not empty 12 13commit 27f6eaadac01f1aa8a90d29768bd023c400d0602 14Author: the-gigi <the.gigi@gmail.com> 15Date: Tue Dec 31 11:25:51 2019 -0800 16 17 removed unused import 18 19...

标志可以有长名和短名。例如,git 的 -p 标志也称为 --paginate。这是一个可用性功能:长名更易读,适合脚本;而在终端输入命令时,你可能更倾向于使用短名。

为标志同时提供短名和长名是良好实践。

某些标志需要额外的信息。例如,--git-dir=<path> 用于设置 git 命令要操作的仓库路径。默认值是当前工作目录。

现在你已经理解了 Cobra 的基本概念,我们将讨论如何在程序中将其作为库使用。

Testing 1,2,3...

Cobra 与其他替代方案的比较