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-practice 的目录作为项目目录,然后初始化 modules:

$ mkdir cobra-practice && cd cobra-practice
# 如果 go modules 默认没有开启,需要执行 export GO111MODULE=on 开启
$ go mod init cobra-practice
go: creating new go.mod: module cobra-practice

初始化完成后可以看到项目根目录下面多了一个 go.mod 的文件,现在我们还没有安装 cobra 库,执行下面的命令进行安装:

# 强烈推荐配置该环境变量
$ export GOPROXY=https://goproxy.cn
$ go get -u github.com/spf13/cobra/cobra

安装成功后,现在我们可以使用 cobra init 命令来初始化 CLI 应用的脚手架:

注意:此处如果没有将GOPATH加入到PATH的话,cobra会提示找不到命令,解决方案就是:export PATH=$PATH:$GOPATH/bin

$ cobra init --pkg-name cobra-practice
Your Cobra applicaton is ready at
/Users/apple/zl/code/cobra-practice

上面的 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 "cobra-practice/cmd"

func main() {
	cmd.Execute()
}
//cmd/root.go
package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/viper"
)

var cfgFile string

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:   "cobra-practice",
	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 Cobra CLI")
	},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	cobra.CheckErr(rootCmd.Execute())
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports persistent flags, which, if defined here,
	// will be global for your application.

	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra-practice.yaml)")

	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		cobra.CheckErr(err)

		// Search config in home directory with name ".cobra-practice" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigName(".cobra-practice")
	}

	viper.AutomaticEnv() // read in environment variables that match

	// 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 build编译,运行cobra-practice可执行文件即执行了命令

增加命令

在项目根目录下面创建一个名为 add 的命令,Cobra 添加一个新的命令的方式为:cobra add <commandName>,所以我们这里直接这样执行:

$ cobra add add
add created at /Users/apple/zl/code/cobra-practice

现在我们可以看到 cmd/root.go 文件中新增了一个 add.go 的文件,我们仔细观察可以发现该文件和 cmd/root.go 比较类似。首先是声明了一个名为 addCmd 的结构体变量,类型为 *cobra.Command 指针类型,*cobra.Command 有一个 RUN 函数,带有 *cobra.Command 指针和一个字符串切片参数

//cmd/add.go
package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// addCmd represents the add command
var addCmd = &cobra.Command{
	Use:   "add",
	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("add called")
	},
}

func init() {
	rootCmd.AddCommand(addCmd)

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

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

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

重新编译,go build,执行cobra-practice add即执行该命令

源码:https://github.com/linjinbao666/cobra-practice.git