暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

go命令行库:cobra 简易教程

五分钟学SRE 2021-12-05
2887

    我们一直在使用 CLI 工具。您可能熟悉 git、docker、kubectl、awscli 等 CLI 工具。在go 中可以使用cobra来构建我们自己的cli工具。

    Cobra是一个强大的 Golang 库和工具,用于创建 CLI(命令行界面)应用程序。Cobra 通过提供自动化流程的工具和提供提高开发人员生产力的关键抽象来实现这一点。

    Cobra主要包括以下部分:

  • Command:一般表示action,即运行的二进制命令服务。同时可以拥有子命令(children commands)。

  • Args:命令执行相关参数。

  • Flags:二进制命令的配置参数,可对应配置文件。参数可分为全局参数和子命令参数。参考:pflag library。

项目设置

创建一个新文件夹以在其中工作并 cd 进入其中:

mkdir five-m-go && cd five-m-go

创建 go 模块并获取 Cobra 包

# 如果 go modules 默认没有开启,需要执行 export GO111MODULE=on 开启
$ go mod init five-m-go
go: creating new go.mod: module five-m-go
go get -u github.com/spf13/cobra/cobra

在你的项目中初始化 Cobra

cobra init --pkg-name five-m-go

完成后可以看到我们的项目目录

tree .
.
├── LICENSE
├── cmd
│ └── root.go
├── go.mod
├── go.sum
└── main.go

其中 main.go 是 CLI 应用的入口,在 main.go 里面调用好了 cmd/root.go 下面的 Execute 函数:

package main


import "five-m-go/cmd"


func main() {
cmd.Execute()
}

root.go文件

rootCmd

    root 命令是任何 cli 的基本命令。对于前,go get URL—go是这里的根命令,get是go根命令的子命令

    在 root.go 中就直接使用了 cobra 命令来初始化 rootCmd 结构,CLI 中的其他所有命令都将是 rootCmd 这个根命令的子命令。

    这里我们将 cmd/root.go 里面的 rootCmd 变量内部的注释去掉,并在 Run 函数里面加上一句 fmt.Println("Hello five minutes to learn go"):

var rootCmd = &cobra.Command{
Use: "five-m-go",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:


Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello five minutes to learn go")
},
}
tip:

记得不要把最后的,忘记,不然会报语法错误

构建cobra项目

go build -o five-m-go

在项目根目录下生成一个名为five-m-go的二进制文件

./five-m-go 
Hello five minutes to learn go

init函数

    我们知道 init 函数是 Golang 中初始化包的时候第一个调用的函数。在 cmd/root.go 中我们可以看到 init 函数中调用了 cobra.OnInitialize(initConfig),也就是每当执行或者调用命令的时候,它都会先执行 init 函数中的所有函数,然后再执行 execute 方法。该初始化可用于加载配置文件或用于构造函数等等,这完全依赖于我们应用的实际情况。

    在初始化函数里面 cobra.OnInitialize(initConfig) 调用了 initConfig 这个函数,所有,当 rootCmd 的执行方法 RUN: func 运行的时候,rootCmd 根命令就会首先运行 initConfig 函数,当所有的初始化函数执行完成后,才会执行 rootCmd 的 RUN: func 执行函数。

可以在函数加一些调试信息

func initConfig() {
fmt.Println("inside initConfig")

重新构建执行

可以看到执行的顺序是先运行initConfig函数然后才运行执行函数

go build -o five-m-go
./five-m-go
inside initConfig
Hello five minutes to learn go

为了解cli的完整流程,我们加上一些信息在 main.go里面

//cmd/root.go
func init() {
fmt.Println("hi five-m-go,inside init function")
...
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
fmt.Println("hi five-m-go,inside initConfig function")
....
}


//main.go
func main() {
fmt.Println("hi five-m-go,inside main function")
cmd.Execute()
}

重新构建运行可以看到执行顺序

go build -o five-m-go
./five-m-go
hi five-m-go,inside init function
hi five-m-go,inside main function
hi five-m-go,inside initConfig function
Hello five nimutes to learn gos
func init() {
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

可以看到init函数最后处理的是flags,Flags 就类似于命令的标识符,我们可以把他们看成是某种条件操作,在 Cobra 中提供了两种类型的标识符:Persistent Flags 和 Local Flags。

  • Persistent Flags: 该标志可用于为其分配的命令以及该命令的所有子命令。

  • Local Flags: 该标志只能用于分配给它的命令。

initConfig函数

    此功能是在主目录中设置配置路径,配置文件名为.five-m-go
. 如果存在,它将使用配置文件。

// initConfig 函数用于读取配置文件与环境变量
func initConfig() {
fmt.Println("hi five-m-go,inside initConfig function")
if cfgFile != "" {
// Use config file from the flag.
//使用flag 标志中传递的配置文件
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
//获取home 目录
home, err := os.UserHomeDir()
cobra.CheckErr(err)


// Search config in home directory with name ".five-m-go" (without extension).
//在home目录下查看 ".five-m-go"配置文件
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".five-m-go")
}
// read in environment variables that match
//读取匹配的环境变量
viper.AutomaticEnv()


// If a config file is found, read it in.
//如果配置文件存在,则读取
if err := viper.ReadInConfig(); err == nil {
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
}
}

    在这个函数里面使用了go的另外一个第三方库,viper 是一个配置解决方案,拥有丰富的特性:

  • 支持 JSON/TOML/YAML/HCL/envfile/Java properties 等多种格式的配置文件;

  • 可以设置监听配置文件的修改,修改时自动加载新的配置;

  • 从环境变量、命令行选项和io.Reader中读取配置;

  • 从远程配置系统中读取和监听修改,如 etcd/Consul;

  • 代码逻辑中显示设置键值。

这个第三方库,会在后面的博文继续介绍,可以等待公众号的更新

    我们已经创建了一个 five-m-go 命令作为 rootCmd 命令,执行该根命令会打印 Hello five nimutes to learn go cobra 信息,接下来为我们的 CLI 应用添加一些其他的命令。


cobra实例演示

使用add新增一个子命令

cobra add show
show created at /Users/zhencai.cai/Downloads/shopee/ops/five-m-go
项目目录下会创建一个 show.go
文件,在该文件中可完成命令的具体操作逻辑。

Show.go的初始代码

// showCmd represents the show command
var showCmd = &cobra.Command{
Use: "show",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:


Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("show called")
},
}


func init() {
rootCmd.AddCommand(showCmd)


// Here you will define your flags and configuration settings.


// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// showCmd.PersistentFlags().String("foo", "", "A help for foo")


// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// showCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

&cobra.Command 作为命令的定义,其中有如下变量:

  • Use:用于指定具体的命令,如:show。

  • Short:命令的简短描述。

  • Long:命令的详细描述。

  • Run:命令执行入口,用于实现命令的具体处理逻辑。


    rootCmd.AddCommand(showCmd) 命令的添加,将命令添加到根命令。(Cobra 支持命令的子命令)

实现显示当前时间逻辑

在 &cobra.Command.Run 中,注释默认的 fmt.Println("show called"),添加获取当前时间逻辑 time.Now():

Run: func(cmd *cobra.Command, args []string) {
// fmt.Println("show called")
fmt.Println(time.Now())
},

可以自定义命令描述

// showCmd represents the show command
var showCmd = &cobra.Command{
Use: "show",
Short: "Hi five-m-go ,this is display the current time",
Long: `You can use the command to view the current time:
./five-m-go show`,
Run: func(cmd *cobra.Command, args []string) {
// fmt.Println("show called")
fmt.Println(time.Now())
},
}

重新构建运行项目

go build -o five-m-go
./five-m-go
Hello five nimutes to learn go cobra
./five-m-go show
2021-12-05 18:51:21.715117 +0800 CST m=+0.001131906

使用 --help查看命令描述

(base) C02G20FCMD6M:five-m-go zhencai.cai$ ./five-m-go show --help
You can use the command to view the current time:
./five-m-go show


Usage:
five-m-go show [flags]


Flags:
-h, --help help for show


Global Flags:
--config string config file (default is $HOME/.five-m-go.yaml)


推荐博文:(How to create a CLI in golang with cobra

)https://towardsdatascience.com/how-to-create-a-cli-in-golang-with-cobra-d729641c7177

推荐博文:(Go 每日一库之 cobra)https://darjun.github.io/2020/01/17/godailylib/cobra/

文章转载自五分钟学SRE,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论