本篇内容主要讲解“怎么在Golang中使用Cobra创建CLI应用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么在Golang中使用Cobra创建CLI应用”吧!
对于开发人员来说平时可能就需要使用到很多 CLI 工具,比如 npm、node、go、python、docker、kubectl 等等,因为这些工具非常小巧、没有依赖性、非常适合系统管理或者一些自动化任务等等。
我们这里选择使用 Golang 里面非常有名的Cobra库来进行 CLI 工具的开发。Cobra 是一个功能强大的现代化 CLI 应用程序库,有很多知名的 Go 项目使用 Cobra 进行构建,比如:Kubernetes、Docker、Hugo 等等
Cobra 是构建在命令、参数和标识符之上的:
Commands
表示执行动作
Args
就是执行参数
Flags
是这些动作的标识符
基本的执行命令如下所示:
$ APPNAME Command Args --Flags # 或者 $ APPNAME Command --Flags Args
比如我们平时使用的一些命令行工具:
git clone URL -bare go get -u URL npm install package –save kubectl get pods -n kube-system -l app=cobra
下面我们来看下 Cobra 的使用,这里我们使用的 go1.13.3 版本,使用 Go Modules 来进行包管理,如果对这部分知识点不熟悉的,可以查看前面我们的文章Go Modules 基本使用(视频)了解。
新建一个名为my-calc
的目录作为项目目录,然后初始化 modules:
$ mkdir my-calc && cd my-calc # 如果 go modules 默认没有开启,需要执行 export GO111MODULE=on 开启 $ go mod init my-calc go: creating new go.mod: module my-calc
初始化完成后可以看到项目根目录下面多了一个go.mod
的文件,现在我们还没有安装cobra
库,执行下面的命令进行安装:
# 强烈推荐配置该环境变量 $ export GOPROXY=https://goproxy.cn $ go get -u github.com/spf13/cobra/cobra
安装成功后,现在我们可以使用cobra init
命令来初始化 CLI 应用的脚手架:
$ cobra init --pkg-name my-calc Your Cobra applicaton is ready at /Users/ych/devs/workspace/youdianzhishi/course/my-calc
需要注意的是新版本的 cobra 库需要提供一个--pkg-name
参数来进行初始化,也就是指定上面我们初始化的模块名称即可。上面的 init 命令就会创建出一个最基本的 CLI 应用项目:
$ tree . . ├── LICENSE ├── cmd │ └── root.go ├── go.mod ├── go.sum └── main.go 1 directory, 5 files
其中main.go
是 CLI 应用的入口,在main.go
里面调用好了cmd/root.go
下面的Execute
函数:
// main.go package main import "my-calc/cmd" func main() { cmd.Execute() }
然后我们再来看下cmd/root.go
文件。
root(根)命令是 CLI 工具的最基本的命令,比如对于我们前面使用的go get URL
,其中go
就是 root 命令,而get
就是go
这个根命令的子命令,而在root.go
中就直接使用了 cobra 命令来初始化rootCmd
结构,CLI 中的其他所有命令都将是rootCmd
这个根命令的子命令了。
这里我们将cmd/root.go
里面的rootCmd
变量内部的注释去掉,并在Run
函数里面加上一句fmt.Println("Hello Cobra CLI")
:
var rootCmd = &cobra.Command{ Use: "my-calc", 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.`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("Hello Cobra CLI") }, }
这个时候我们在项目根目录下面执行如下命令进行构建:
$ go build -o my-calc
该命令会在项目根目录下生成一个名为my-calc
的二进制文件,直接执行这个二进制文件可以看到如下所示的输出信息:
$ ./my-calc
Hello Cobra CLI
我们知道init
函数是 Golang 中初始化包的时候第一个调用的函数。在cmd/root.go
中我们可以看到init
函数中调用了cobra.OnInitialize(initConfig)
,也就是每当执行或者调用命令的时候,它都会先执行init
函数中的所有函数,然后再执行execute
方法。该初始化可用于加载配置文件或用于构造函数等等,这完全依赖于我们应用的实际情况。
在初始化函数里面cobra.OnInitialize(initConfig)
调用了initConfig
这个函数,所有,当rootCmd
的执行方法RUN: func
运行的时候,rootCmd
根命令就会首先运行initConfig
函数,当所有的初始化函数执行完成后,才会执行rootCmd
的RUN: func
执行函数。
我们可以在initConfig
函数里面添加一些 Debug 信息:
func initConfig() { fmt.Println("I'm inside initConfig function in cmd/root.go") ... }
然后同样重新构建一次再执行:
$ go build -o my-calc $ ./my-calc I'm inside initConfig function in cmd/root.go Hello Cobra CLI
可以看到是首先运行的是initConfig
函数里面的信息,然后才是真正的执行函数里面的内容。
为了搞清楚整个 CLI 执行的流程,我们在main.go
里面也添加一些 Debug 信息:
// cmd/root.go func init() { fmt.Println("I'm inside init function in cmd/root.go") cobra.OnInitialize(initConfig) ... } func initConfig() { fmt.Println("I'm inside initConfig function in cmd/root.go") ... } // main.go func main() { fmt.Println("I'm inside main function in main.go") cmd.Execute() }
然后同样重新构建一次再执行:
$ go build -o my-calc $ ./my-calc I'm inside init function in cmd/root.go I'm inside main function in main.go I'm inside initConfig function in cmd/root.go Hello Cobra CLI
根据上面的日志信息我们就可以了解到 CLI 命令的流程了。
init
函数最后处理的就是flags
了,Flags
就类似于命令的标识符,我们可以把他们看成是某种条件操作,在 Cobra 中提供了两种类型的标识符:Persistent Flags
和Local Flags
。
Persistent Flags
: 该标志可用于为其分配的命令以及该命令的所有子命令。
Local Flags
: 该标志只能用于分配给它的命令。
该函数主要用于在 home 目录下面设置一个名为.my-calc
的配置文件,如果该文件存在则会使用这个配置文件。
// cmd/root.go // initConfig 读取配置文件和环境变量 func initConfig() { if cfgFile != "" { // 使用 flag 标志中传递的配置文件 viper.SetConfigFile(cfgFile) } else { // 获取 Home 目录 home, err := homedir.Dir() if err != nil { fmt.Println(err) os.Exit(1) } // 在 Home 目录下面查找名为 ".my-calc" 的配置文件 viper.AddConfigPath(home) viper.SetConfigName(".my-calc") } // 读取匹配的环境变量 viper.AutomaticEnv() // 如果有配置文件,则读取它 if err := viper.ReadInConfig(); err == nil { fmt.Println("Using config file:", viper.ConfigFileUsed()) } }
viper
是一个非常优秀的用于解决配置文件的 Golang 库,它可以从 JSON、TOML、YAML、HCL、envfile 以及 Java properties 配置文件中读取信息,功能非常强大,而且不仅仅是读取配置这么简单,了解更多相关信息可以查看 Git 仓库相关介绍:https://github.com/spf13/viper。
现在我们可以去掉前面我们添加的一些打印语句,我们已经创建了一个my-calc
命令作为rootCmd
命令,执行该根命令会打印Hello Cobra CLI
信息,接下来为我们的 CLI 应用添加一些其他的命令。
在项目根目录下面创建一个名为add
的命令,Cobra
添加一个新的命令的方式为:cobra add <commandName>
,所以我们这里直接这样执行:
$ cobra add add add created at /Users/ych/devs/workspace/youdianzhishi/course/my-calc $ tree . . ├── LICENSE ├── cmd │ ├── add.go │ └── root.go ├── go.mod ├── go.sum ├── main.go └── my-calc 1 directory, 7 files
现在我们可以看到cmd/root.go
文件中新增了一个add.go
的文件,我们仔细观察可以发现该文件和cmd/root.go
比较类似。首先是声明了一个名为addCmd
的结构体变量,类型为*cobra.Command
指针类型,*cobra.Command
有一个RUN
函数,带有*cobra.Command
指针和一个字符串切片参数。
然后在init
函数中进行初始化,初始化后,将其添加到rootCmd
根命令中rootCmd.AddCommand(addCmd)
,所以我们可以把addCmd
看成是rootCmd
的子命令。
同样现在重新构建应用再执行:
$ go build -o my-calc $ ./my-calc Hello Cobra CLI $ ./my-calc add add called
可以看到add
命令可以正常运行了,接下来我们来让改命令支持添加一些数字,我们知道在RUN
函数中是用户字符串 slice 来作为参数的,所以要支持添加数字,我们首先需要将字符串转换为 int 类型,返回返回计算结果。在cmd/add.go
文件中添加一个名为intAdd
的函数,定义如下所示:
// cmd/add.go func intAdd(args []string) { var sum int // 循环 args 参数,循环的第一个值为 args 的索引,这里我们不需要,所以用 _ 忽略掉 for _, ival := range args { // 将 string 转换成 int 类型 temp, err := strconv.Atoi(ival) if err != nil { panic(err) } sum = sum + temp } fmt.Printf("Addition of numbers %s is %d\n", args, sum) }
然后在addCmd
变量中,更新RUN
函数,移除默认的打印信息,调用上面声明的addInt
函数:
// addCmd Run: func(cmd *cobra.Command, args []string) { intAdd(args) },
然后重新构建应用执行如下所示的命令:
$ go build -o my-calc $ ./my-calc Hello Cobra CLI # 注意参数之间的空格 $ ./my-calc add 1 2 3 Addition of numbers [1 2 3] is 6
由于RUN
函数中的args
参数是一个字符串切片,所以我们可以传递任意数量的参数,但是确有一个缺陷,就是只能进行整数计算,不能计算小数,比如我们执行如下的计算就会直接 panic 了:
$ ./my-calc add 1 2 3.5 panic: strconv.Atoi: parsing "3.5": invalid syntax goroutine 1 [running]: my-calc/cmd.intAdd(0xc0000a5890, 0x3, 0x3) ......
因为在intAdd
函数里面,我们只是将字符串转换成了 int,而不是 float32/64 类型,所以我们可以为addCmd
命令添加一个flag
标识符,通过该标识符来帮助 CLI 确定它是 int 计算还是 float 计算。
在cmd/add.go
文件的init
函数内部,我们创建一个 Bool 类型的本地标识符,命名成float
,简写成f
,默认值为 false。这个默认值是非常重要的,意思就是即使没有在命令行中调用 flag 标识符,该标识符的值就将为 false。
// cmd/add.go func init() { rootCmd.AddCommand(addCmd) addCmd.Flags().BoolP("float", "f", false, "Add Floating Numbers") }
然后创建一个floatAdd
的函数:
func floatAdd(args []string) { var sum float64 for _, fval := range args { // 将字符串转换成 float64 类型 temp, err := strconv.ParseFloat(fval, 64) if err != nil { panic(err) } sum = sum + temp } fmt.Printf("Sum of floating numbers %s is %f\n", args, sum) }
该函数和上面的intAdd
函数几乎是相同的,除了是将字符串转换成 float64 类型。然后在addCmd
的RUN
函数中,我们根据传入的标识符来判断到底应该是调用intAdd
还是floatAdd
,如果传递了--float
或者-f
标志,就将会调用floatAdd
函数。
// cmd/add.go // addCmd Run: func(cmd *cobra.Command, args []string) { // 获取 float 标识符的值,默认为 false fstatus, _ := cmd.Flags().GetBool("float") if fstatus { // 如果为 true,则调用 floatAdd 函数 floatAdd(args) } else { intAdd(args) } },
现在重新编译构建 CLI 应用,按照如下方式执行:
$ go build -o my-calc $ ./my-calc add 1 2 3 Addition of numbers [1 2 3] is 6 $ ./my-calc add 1 2 3.5 -f Sum of floating numbers [1 2 3.5] is 6.500000 $./my-calc add 1 2 3.5 --float Sum of floating numbers [1 2 3.5] is 6.500000
然后接下来我们在给addCmd
添加一些子命令来扩展它。
添加偶数
同样在项目根目录下执行如下命令添加一个名为even
的命令:
$ cobra add even even created at /Users/ych/devs/workspace/youdianzhishi/course/my-calc
和上面一样会在root
目录下面新增一个名为even.go
的文件,修改该文件中的init
函数,将rootCmd
修改为addCmd
,因为我们是为addCmd
添加子命令:
// cmd/even.go func init() { addCmd.AddCommand(evenCmd) }
然后更新evenCmd
结构体参数的RUN
函数:
// cmd/even.go Run: func(cmd *cobra.Command, args []string) { var evenSum int for _, ival := range args { temp, _ := strconv.Atoi(ival) if temp%2 == 0 { evenSum = evenSum + temp } } fmt.Printf("The even addition of %s is %d\n", args, evenSum) },
首先将字符串转换成整数,然后判断如果是偶数才进行累加。然后重新编译构建应用:
$ go build -o my-calc $ ./my-calc add even 1 2 3 4 5 6 The even addition of [1 2 3 4 5 6] is 12
my-calc
是我们的根命令,add
是rootCmd
的子命令,even
优势addCmd
的子命令,所以按照上面的方式调用。可以用同样的方式再去添加一个奇数相加的子命令。
到此,相信大家对“怎么在Golang中使用Cobra创建CLI应用”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。