Cobra是一个强大的用来构建命令行程序的库,许多流行的Go项目都是用它来构建的,好比Kubernetes、Docker、etcd、Istio、Github CLI等等。git
接下来,演示开发一个咱们本身的命令行程序chenqionghe,模仿一下docker命令行,预期功能以下github
# 查看帮助 chenqiong -h # 查看版本,相似docker version chenqionghe version # 查看hello命令帮助,相似docker ps -h chenqionghe hello -h # 使用hello命令,相似docker run --name app --volume /app/data chenqionghe hello --name light-weight-baby --author gym
Cobra基于三个基本概念docker
使用基本模式是APPNAME VERB NOUN --ADJECTIVE或APPNAME COMMAND ARG --FLAG,例如bash
# server是一个command,--port=1313是一个命令行选项 hugo server --port=1313 # clone 是 commands,URL 是 arguments,brae是命令行选项 git clone URL --bare
go get -u github.com/spf13/cobra/cobra go install github.com/spf13/cobra/cobra
这里个人应用名叫chenqiongheapp
go mod init chenqionghe
建立文件夹cmd,并建立文件cmd/root.go,这是用来放全部的命令的基本文件ide
package cmd import ( "fmt" "github.com/spf13/cobra" "os" ) var rootCmd = &cobra.Command{ Use: "chenqionghe", Short: "getting muscle is not easy", Long: `let's do it, yeah buddy light weight baby!`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("hello chenqionghe") }, } func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } }
package main import "chenqionghe/cmd" func main() { cmd.Execute() }
运行一下main.go能够看到生效了
函数
cobra add hello
会在cmd下生成一个hello.cmd的命令,生成的命令是长下面这样的,核心是调用了AddCommand方法
ui
咱们把没用的信息干掉,精简后以下命令行
package cmd import ( "fmt" "github.com/spf13/cobra" ) var helloCmd = &cobra.Command{ Use: "hello", Short: "hello命令简介", Long: `hello命令详细介绍`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("hello called") }, TraverseChildren: true, } func init() { rootCmd.AddCommand(helloCmd) }
直接运行看看3d
go run main.go hello
同理,咱们再建立一个version命令
cobra add version
修改一下Run方法
Run: func(cmd *cobra.Command, args []string) { fmt.Println("chenqionghe version v0.0.1") },
运行以下
flag选项按做用范围分为persistent和local两类
persistent是全局选项,对应的方法为PersistentFlags,能够分配给命令和命令下的全部子命令,上面的rootCmd和helloCmd都是能够调用flag
例如,添加一个-v选项
func init() { var Verbose bool rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "全局版本") }
运行,能够看到生效了
local为本地选项,对应方法为Flags,只对指定的Command生效,咱们往hello命令的init里边添加一个本地flag
func init() { rootCmd.AddCommand(helloCmd) //本地flag var Source string helloCmd.Flags().StringVarP(&Source, "source", "s", "", "读取文件路径") }
运行以下
咱们在init函数添加如下代码
rootCmd.Flags().StringVarP(&Name, "name", "n", "", "你的名字") rootCmd.MarkFlagRequired("name")
运行以下,必须填写name参数才能够运行
添加一个initConfig方法
func initConfig() { viper.AddConfigPath("./") viper.AddConfigPath("./conf") viper.SetConfigName("config") viper.SetConfigType("yaml") viper.AutomaticEnv() if err := viper.ReadInConfig(); err != nil { fmt.Println("Error:", err) os.Exit(1) } }
在init中调用
cobra.OnInitialize(initConfig) //这会运行每一个子命令以前运行 rootCmd.PersistentFlags().StringVar(&Author, "author", "defaultAuthor", "做者名") viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
这将把viper配置和flag绑定,若是用户不设置-author选项,将从配置中查找
cobra默认提供了一些验证方法
往Command中添加参数Args,咱们规定参数不能少于5个,以下
var rootCmd = &cobra.Command{ Use: "chenqionghe", Short: "getting muscle is not easy", Long: `let's do it, yeah buddy light weight baby!`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("hello chenqionghe") }, Args: cobra.MinimumNArgs(5), }
运行输出
咱们能够看到核心的方法,其实就是cobra.Command中的Run参数,指定了func(cmd *cobra.Command, args []string)类型的回调
表明咱们能够直接使用cmd和args来编写咱们的程序
咱们能够直接使用cmd的flag方法获取传递的flag
var helloCmd = &cobra.Command{ Use: "hello", Short: "hello命令简介", Long: `hello命令详细介绍`, Run: func(cmd *cobra.Command, args []string) { fmt.Println(cmd.Flag("author").Value) fmt.Println(cmd.Flag("name").Value) }, }
运行以下
var helloCmd = &cobra.Command{ Use: "hello", Short: "hello命令简介", Long: `hello命令详细介绍`, Run: func(cmd *cobra.Command, args []string) { fmt.Println(args) }, TraverseChildren: true, }
调用以下,能够看到已经取出了全部的args参数
cobra提供了不少钩子方法,可按运行顺序排列以下
var helloCmd = &cobra.Command{ Use: "hello", Short: "hello命令简介", Long: `hello命令详细介绍`, //Args: cobra.MinimumNArgs(1), PersistentPreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) }, PreRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) }, Run: func(cmd *cobra.Command, args []string) { fmt.Printf("Run with args: %v\n", args) }, PostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) }, PersistentPostRun: func(cmd *cobra.Command, args []string) { fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) }, }
运行以下
到这里,咱们就已经学会了若是设置子命令、flag参数、arguments参数以及编写方法使用这些参数,
还有最后一步,就是编译出咱们的二进制程序,验证一下咱们以前的需求
go build -o chenqionghe
以下,已经生成二进制文件chenqionghe
./chenqionghe -h # 查看帮助 ./chenqionghe version # 查看版本,相似docker version ./chenqionghe hello -h # 查看hello命令帮助,相似docker ps -h ./chenqionghe hello --name light-weight-baby --author gym # 使用hello命令,相似docker run --name app --volume /app/data
能够看到,完美的实现了预期需求,就是这么简单,light weight baby!