共计 6287 个字符,预计需要花费 16 分钟才能阅读完成。
打工还是要打工的。。我最初也没收回去。
紧急解决当前,当初写复盘,大家随我看看我到底是在学习哪些内容。
(以上内容纯属虚构,如有雷同纯属巧合)
简介
之前咱们讲过 pflag 和 os.Args,当初说说 cobra
这个命令行框架。
Kubernetes
、Hugo
、etcd
这些出名我的项目都用 cobra
来做命令行程序。学起来!
对于作者spf13
,这里多说两句。spf13
开源不少我的项目,而且他的开源我的项目品质都比拟高。置信应用过 vim
的都晓得spf13-vim
,号称 vim 终极配置。能够一键配置,对于我这样的懒人来说相对是福音。
还有他的 viper
是一个残缺的配置解决方案。完满反对 JSON/TOML/YAML/HCL/envfile/Java properties
配置文件等格局,还有一些比拟实用的个性,如配置热更新、多查找目录、配置保留等。还有十分火的动态网站生成器 hugo
也是他的作品牛人就是牛人。
这个牛人 https://github.com/spf13
疾速应用
第三方库都须要先装置,后应用。上面命令装置了 cobra
生成器程序和 cobra 库:
$ go get github.com/spf13/cobra/cobra
PS: 如果呈现了 golang.org/x/text
库找不到之类的谬误,须要手动从 GitHub 上下载该库,再执行下面的装置命令。
当初要举的例子是让咱们的程序调子命令时会透传到 git
上,用 git version
举例。目录构造如下(手动建的):
get-started/
cmd/
root.go
version.go
utils/
helper.go
main.go
cmd
指标是子命令列表,这里有一个version
命令。root.go
先卖个关子,大家不要理他。main.go
是主程序。helper
是这里应用到的工具类。go.mod
文件我省略了。
上面的代码文件我就省略 import "github.com/spf13/cobra"
了,大家晓得就行,version.go
文件:
var versionCmd = &cobra.Command{
Use: "version",
Short: "version subcommand show git version info.",
Run: func(cmd *cobra.Command, args []string) {output, err := utils.ExecuteCommand("git", "version", args...)
if err != nil {utils.Error(cmd, args, err)
}
fmt.Fprint(os.Stdout, output)
},
}
func init() {rootCmd.AddCommand(versionCmd)
}
- 几个参数含意是子命令名称、子命令短提醒、子命令调用的办法
init()
里把子命令加到主命令中去。
你会有纳闷 rootCmd
是哪来的吗?实际上咱们须要一个根节点,把其余命令加进来。如下是 root.go
文件。
var rootCmd = &cobra.Command {
Use: "git",
Short: "Git is a distributed version control system.",
Long: `Git is a free ... 省略 `,
Run: func(cmd *cobra.Command, args []string) {utils.Error(cmd, args, errors.New("unrecognized command"))
},
}
func Execute() {rootCmd.Execute()
}
有没有发现这里不是 init()
而是 Execute()
?这里此包惟一裸露的公开函数内容,专门供命令初始化应用。如下main.go
文件中的调用命令入口:
import "cmd"
func main() {cmd.Execute()
}
最初为了编码不便,在 helpers.go
中封装了调用内部程序和谬误处理函数,我就不开展写了,有趣味去看我的源码。
https://github.com/golang-min…
cobra
主动生成的帮忙信息,very cool
:
$ go run . -h
Git is a free and open source distributed version control system
designed to handle everything from small to very large projects
with speed and efficiency.
Usage:
git [flags]
git [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
version version subcommand show git version info.
Flags:
-h, --help help for git
Use "git [command] --help" for more information about a command.
单个子命令的帮忙信息:
$ go run . version -h
version subcommand show git version info.
Usage:
git version [flags]
Flags:
-h, --help help for version
调用子命令:
$ go run . version
git version 2.33.0
未辨认的子命令:
$ go run . xxx
Error: unknown command "xxx" for "git"
Run 'git --help' for usage.
应用 cobra
构建命令行时,程序的目录构造个别比较简单,举荐应用上面这种构造:
appName/
cmd/
cmd1.go
cmd2.go
cmd3.go
root.go
main.go
每个命令实现一个文件,所有命令文件寄存在 cmd
目录下。外层的 main.go
仅初始化 cobra。
个性
cobra 提供十分丰盛的性能:
- 轻松反对子命令,如
app server
,app fetch
等; - 齐全兼容 POSIX 选项(包含短、长选项);
- 嵌套子命令;
- 全局、本地层级选项。能够在多处设置选项,依照肯定的程序取用;
- 应用脚手架轻松生成程序框架和命令。
首先须要明确 3 个基本概念:
- 命令(Command):就是须要执行的操作;
- 参数(Arg):命令的参数,即要操作的对象;
- 选项(Flag):命令选项能够调整命令的行为。
比方
git clone URL --bare
clone
是一个(子)命令,URL
是参数,--bare
是选项。子命令咱们曾经讲过了,当初讲讲参数。
参数
比方定义命令的中央。
var cloneCmd = &cobra.Command{Use: "clone url [destination]",
...
Run: func(cmd *cobra.Command, args []string) {...
会扭转帮忙函数输入的内容。实际上还是传入字符串数组。
go run . clone -h
Clone a repository into a new directory
Usage:
git clone url [destination] [flags]
Flags:
-h, --help help for clone
选项
cobra
中选项分为两种.
- 一种是永恒选项(
PersistentFlags
翻译不太规范,临时就说永恒选项),定义它的命令和其子命令都能够应用。办法是给根命令增加一个选项定义全局选项。 - 另一种是本地选项,只能在定义它的命令中应用。
cobra
应用 pflag
解析命令行选项,上次讲过,实际上用法都是一样的。
设置永恒选项,在 root.go
根命令文件中的 init()
函数:
var(Verbose bool)
func init() {rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
}
设置本地选项,在子命令的 init()
函数:
var(Source bool)
func init() {localCmd.Flags().StringVarP(&Source, "source", "s", "","Source directory to read from")
rootCmd.AddCommand(divideCmd)
}
两种参数都是雷同的,长选项 / 短选项名、默认值和帮忙信息。
脚手架
通过后面的介绍,咱们也看到了其实 cobra
命令的框架还是比拟固定的。这就有了工具的用武之地了,可极大地提高咱们的开发效率。
在你的 go root
下装置 cobra-cli
,确保bin
目录曾经放到零碎的 path
里,之前写的文章 - 运行那一节有提到过怎么操作,不记得的回去看看哈。
go install github.com/spf13/cobra-cli@latest
上面咱们介绍如何应用这个生成器,先看命令帮忙:
Usage:
cobra-cli init [path] [flags]
Aliases:
init, initialize, initialise, create
Flags:
-h, --help help for init
Global Flags:
-a, --author string author name for copyright attribution (default "YOUR NAME")
--config string config file (default is $HOME/.cobra.yaml)
-l, --license string name of license for the project
--viper use Viper for configuration
- 依据提醒子命令
init
,可选参数为path
。 - 选项为
-a
指定作者,--config string
指定cobra-cli
本人的配置文件 -l
指定license
,--viper
应用viper
来读取配置文件。
应用 cobra init
命令创立一个 cobra 应用程序:
$ mkdir appname
$ cd appname
$ cobra-cli init
Error: Please run `go mod init <MODNAME>` before `cobra-cli init`
$ go mod init
go: creating new go.mod: module github.com/golang-minibear2333/cmd_utils/git/appname
$ cobra-cli init
Your Cobra application is ready at
/Users/xxxx/Documents/code/go/src/github.com/golang-minibear2333/cmd_utils/git/appname
- 先初始化
mod
再初始化我的项目 - 其中
appname
为应用程序名。生成的程序目录构造如下:
.
├── LICENSE
├── cmd
│ └── root.go
├── go.mod
├── go.sum
└── main.go
这个我的项目构造与之前介绍的完全相同,也是 cobra
举荐应用的构造。同样地,main.go
也仅仅是入口。外面的英文正文十分的清晰,我一下子就看懂了用法,你也试试。
配置读取
除了命令行以外,这个库还能够用来配置读取,咱们先创立我的项目和配置文件:
mkdir cfg_load && cd_cg_load
mkdir config && touch config/cfg.yaml
cat >config/cfg.yaml <<-EOF
people:
name: minibear2333
age: 18
EOF
PS: linux
命令不熟的能够在 Go
群里问我。
当初咱们尝试读取这个配置文件,间接应用命令来创立读取配置文件的代码。
$ cobra-cli init --viper
Your Cobra application is ready at
/Users/xxx/Documents/code/go/src/github.com/golang-minibear2333/cmd_utils/git/cfg_load
当初就创立了一个默认配置文件为 $HOME/.cfg_load.yaml
的命令行程序,而咱们之前放在了另一个地位,所以启动的时候须要指定一下。
$ go run . --config==config/cfg.yaml
配置文件就胜利载入了,当初你就能够用 viper
在须要的中央读取配置了。
为了展现一下配置是否胜利读取,持续用 cobra-cli
来创立一个子命令。
$ cobra-cli add viperall
批改此子命令 Run
函数的内容为
var viperallCmd = &cobra.Command{
Use: "viperall",
Short: "Show cfg all",
Long: `Show the contents of the entire configuration file`,
Run: func(cmd *cobra.Command, args []string) {fmt.Println(viper.AllSettings())
},
}
运行,妥了。
$ go run . viperall --config=config/cfg.yaml
Using config file: config/cfg.yaml
map[people:map[age:18 name:minibear2333]]
每次都要指定必定很麻烦,你相熟 viper
的话能够本人改一下默认文件,把我的我的项目下下来给我提交一个 pr
吧~!
子命令也能够嵌套,只须要在 init()
的时候,加到父命令里,当然也能够主动生成。
$ cobra-cli add tt -p viperallCmd
tt created at /Users/xxx/Documents/code/go/src/github.com/golang-minibear2333/cmd_utils/git/cfg_load
$ go run . viperall tt --config=config/cfg.yaml
Using config file: config/cfg.yaml
tt called
- 留神父命令是
viperall
,然而-p
指定的时候要改为viperallCmd
,因为如下(我感觉这个是个很好的奉献 pr,你能够倡议作者改一下):
var viperallCmd = &cobra.Command{
小结
- 每个 cobra 程序都有一个根命令,能够给它增加任意多个子命令。比方咱们在
version.go
的init
函数中将子命令增加到根命令中。 - 创立子命令时指定子命令名称、子命令短提醒、子命令调用的办法。
- 三个重要概念,子命令、参数、选项。
- 全局选项和子命令本人应用的选项。
cobra-cli
主动创立我的项目,主动创立配置文件读取我的项目,主动减少子命令,主动减少嵌套子命令。
举荐目录构造
.
├── LICENSE
├── cmd
│ ├── root.go
| ├── cmd1.go
├── go.mod
├── go.sum
└── main.go
还有更多!cobra
提供了十分丰盛的个性和定制化接口,例如:
- 设置钩子函数,在命令执行前、后执行某些操作。
- 生成 Markdown/ReStructed Text/Man Page 格局的文档。
- 等。本人下来学咯。
cobra
库的应用十分宽泛,很多出名我的项目都有用到,后面也提到过这些我的项目。学习这些我的项目是如何应用 cobra
的,能够从中学习 cobra
的个性和最佳实际。这也是学习开源我的项目的一个很好的路径。
本文由 mdnice 多平台公布