Overview
Cobra 是一个用于创建功能强大的现代 CLI 应用程序的库。
Cobra 用于许多Go项目,如 Kubernetes,Hugo 和 GitHub CLI 等。
Cobra 是一个库,它提供了一个简单的界面来创建类似于 git&go 工具的强大现代 CLI 界面。
Installing
- 终端输入以下命令,请确保你已安装了 Go
1 | go get -u github.com/spf13/cobra@latest |
- 在你的程序中导入
1 | import "github.com/spf13/cobra" |
Usage
- Cobra-cli 是一个命令行程序,用于生成 cobra 应用程序和命令文件。它将引导您的应用程序脚手架以快速开发基于 Cobra 的应用程序。这是将 Cobra 合并到应用程序中的最简单方法。
1 | go install github.com/spf13/cobra-cli@latest |
Cobra Generator
Cobra 提供了自己的程序,可以创建您的应用程序并添加您想要的任何命令。这是将 Cobra 合并到应用程序中的最简单方法。
Cobra Generator 目前只支持两种操作
cobra-cli init
Initalizing a module
Cobra-cli init [ app ]
命令将为您创建初始应用程序代码。
1 | cd $PATH/src |
Initalizing a Cobra CLI application
- 在 Go 模块中运行
cobra-cli init
。这将创建一个新的框架项目供您编辑。 - 此时目录结构为
- 运行 main.go
- 查看 main.go 中的内容。第二段 Copyright 后面的内容是可以通过参数进行统一修改的,下面马上会讲
Optional flags
- 使用
cobra-cli init
初始化时,可以提供你的名字和邮箱,以及许可证
1 | cobra-cli init --author "谷安 123456@qq.com" --license apache |
- 再次查看 main.go 中的内容,可以发现 Copyright 后面的内容已经被修改成你提供的名字跟邮箱了
Add commands to a project
- 你可以使用
cobra-cli add
为你的应用添加其他命令
1 | cobra-cli add serve |
- 这会在 cmd 目录下增加三个 go 文件
- 其中 -p 表示将 create 命令分配给 config 命令(也就是 config 命令是 create 的父命令)。如果未指定父命令,则 rootCmd 默认为所有命令的父命令。
- 现在你可以通过如下命令来运行你的程序
1 | go run main.go |
- 也可以使用
go build
编译生成二进制文件,通过二进制文件加参数来运行程序
1 | go build |
- 也可以在代码中对命令进行添加、修改等。比如使用命令
cobra-cli add myCli
之后,会在 cmd 目录下自动生成 myCli.go 文件 - 查看 myCli.go 的内容
1 | var myCliCmd = &cobra.Command{ |
先来看看结构体 myCliCmd。其中 Use 后面的值是指你在使用时应该添加什么样的参数,比如这里是 myCli,那么就应该使用
./myApp myCli
或者go run main.go myCli
来使用。Short 和 Long 是两个对该命令参数的描述,提供给用户看的,你可以在这里提供命令的使用方法再看看最后一行代码,表示将 rootCmd 父命令赋给 myCliCmd。还记得我们在前面说过,通过
cobra-cli add
添加命令时,如果没有 -p 参数,那就默认其父命令时 rootCmd,原因就是自动生成的代码中的这段代码。我们也可以通过修改这段代码,将其他父命令赋给 myCliCmd。比如将 serve 父命令赋给 myCliCmd,将代码修改为serveCmd.AddCommand(myCliCmd)
即可,在使用时应该是./myApp serve myCli
或者go run main.go serve myCli
。
Working with Flags
flag 就是符号 “-” 加一个字母,或者符号 “–” 加一串字母。比如前面提到的命令
cobra-cli add create -p configCmd
中的 -p 就是一个 flag。cobra 同样支持我们给程序定义 flag。
由于 flag 是在不同的位置定义和使用的,因此我们需要在外部定义一个具有正确范围的变量,以分配要使用的 flag。
1 | var Verbose bool |
- 有两种不同的方法来分配 flag
Persistent Flags
- flag 可以是“持久的”,这意味着此 flag 将可用于它所分配到的命令以及该命令下的每个命令。对于全局 flage,将 flag 指定为根上的永久标志。
1 | rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") |
Local Flags
- 也可以在本地分配 flag,该 flag 仅适用于该特定命令。
1 | localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") |
- 下面这样也行,意味着给 version 命令增加了一个可选的 flag
1 | versionCmd.Flags().StringP("heroes", "r", "IronMan", "./app version -r yourHeroes") |
父命令上的本地标志
- 默认情况下,Cobra 仅解析目标命令上的本地标志,父命令上的任何本地标志都将被忽略。通过开启
Command.TraverseChildren
,Cobra 将在执行目标命令之前解析每个命令上的本地标志。
1 | command := cobra.Command{ |
必须的标志
- 默认情况下,标志是可选的。相反,如果您希望命令在未设置标志时报告错误,请根据需要将其标记为:
1 | rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)") |
- 或者,对于持久标志:
1 | rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)") |
标记组
- 如果必须同时提供不同的标志(比如,提供—— username 标志的同时也要提供—— password 标志) ,那么 Cobra 可以强制执行这一要求
1 | rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)") |
- 如果要求两个标志不能同时出现
1 | rootCmd.Flags().BoolVar(&u, "json", false, "Output in JSON") |
- 可以使用 Command 的 Args 字段指定位置参数的验证。如果 Args 未定义或为 nil,则默认为 Args。
- 内置了以下验证程序:
NoArgs
-如果有任何位置参数,命令将报告错误。ArbitraryArgs
-命令将接受任何参数。OnlyValidArgs
-如果有任何位置参数不在 Command 的 ValidArgs 字段中,命令将报告错误。MinimumNArgs (int)
-如果没有至少 N 个位置参数,命令将报告一个错误。MaximumNArgs (int)
-如果位置参数超过 N,命令将报告错误。ExactArgs (int)
-如果没有确切的 N 个位置参数,命令将报告错误。ExactValidArgs (int)
-如果没有确切的 N 个位置参数,或者如果有任何位置参数不在 Command 的 ValidArgs 字段中,命令将报告一个错误RangeArgs (min,max)
-如果参数的数量不在预期参数的最小和最大数量之间,命令将报告错误。MatchAll (pargs... position tionalArgs)
-支持将现有检查与任意其他检查相结合(例如,您想检查 ExactArgs 长度以及其他属性)。- Example:
1 | package main |
内置函数
PersistentPreRun
PreRun
Run
PostRun
PersistentPostRun
- 执行顺序从上至下
- 注意:
Persistent*Run
函数将会被子命令继承。当运行子命令时,会运行父命令的PersistentPreRun
函数,但父命令的PersistentPostRun
函数不会被运行。如下
1 | package main |
- Output
1 | Inside rootCmd PersistentPreRun with args: [] |
发生未知命令时的提示
- 当“未知命令”错误发生时,Cobra 将打印自动建议。这使得 Cobra 在发生输入错误时的行为类似于 git 命令
- 根据注册的每个子命令自动提出建议,并使用莱文斯坦距离的实现。匹配最小距离为2(忽略大小写)的每个已注册命令将显示为一个建议。
- 如果需要禁用建议或调整命令中的字符串距离,请使用:
1 | command.DisableSuggestions = true |
未完待续…
- 本文作者: 谷安
- 本文链接: http://example.com/2022/07/21/Cobra/
- 版权声明: 转载请注明出处