使用
安装cobra
使用Cobra很简单。首先,使用go get安装最新版本
go get github.com/spf13/cobra/cobra
由于各种问题,国内使用 go get 安装 golang 官方包可能会失败。如果出现:
hidden@hidden:~$ go get github.com/spf13/cobra/cobra
package golang.org/x/sys/unix: unrecognized import path "golang.org/x/sys/unix" (https fetch: Get https:
package golang.org/x/text/transform: unrecognized import path "golang.org/x/text/transform" (https fetch: Get https:
package golang.org/x/text/unicode/norm: unrecognized import path "golang.org/x/text/unicode/norm" (https fetch: Get https:
即使使用代理也不行,怎么解决这个问题?
其实 golang 在 github 上建立了一个镜像库,如 https://github.com/golang/sys/, 即是 https://golang.org/x/sys/ 的镜像库。要避免以上报错,其实只需要执行以下步骤:
mkdir -p $GOPATH/src/golang.org/x
cd $GOPATH/src/golang.org/x
git clone https:
git clone https:
然后再执行go get github.com/spf13/cobra/cobra即可。
安装成功之后会生成一个名为cobra的可执行文件:
hidden@hidden:~
$ ls -al $GOPATH/bin | grep cobra
-rwxr-xr-x 1 zhuzhonghua zhuzhonghua 11411056 Aug 12 15:48 cobra
使用Cobra生成应用程序
假设现在我们要开发一个基于CLI的命令程序,名字为demo。执行如下命令:
hidden@hidden:~$ cd $GOPATH/src/github.com/spf13/
hidden@hidden:~/go/src/github.com/spf13$ cobra init demo --pkg-name=github.com/spf13/demo
Your Cobra applicaton is ready at
/home/zhuzhonghua/go/src/github.com/spf13/demo
hidden@hidden:~/go/src/github.com/spf13$ cd demo/
在$GOPATH/src/github.com/spf13目录下会生成一个demo的文件夹,结构如下:
hidden@hidden:~/go/src/github.com/spf13/demo$ tree
.
├── cmd
│ └── root.go
├── LICENSE
└── main.go
1 directory, 3 files
在demo目录下会有如下的内容:
hidden@hidden:~/cobra/demo$ tree
.
├── cmd
│ └── root.go
├── LICENSE
└── main.go
1 directory, 3 files
测试cobra效果:
hidden@hidden:~/cobra/demo$ go run main.go
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.
subcommand is required
exit status 1
在Cobra应用程序中,通常main.go文件非常空洞。它主要只干一件事:初始化Cobra。
package main
import "github.com/spf13/demo/cmd"
func main() {
cmd.Execute()
}
添加子命令
可以定义其他命令,并且通常在cmd/目录中为每个命令提供自己的文件。
如果要创建版本(version)命令,可以创建cmd/version.go并使用以下内容填充它:
hidden@hidden:~/go/src/github.com/spf13/demo$ cobra add version
version created at /home/zhuzhonghua/go/src/github.com/spf13/demo
此目录结构变更为:
hidden@hidden:~/go/src/github.com/spf13/demo$ tree
.
├── cmd
│ ├── root.go
│ └── version.go
├── LICENSE
└── main.go
1 directory, 4 files
现在我们来执行以下这个子命令:
hidden@hidden:~/go/src/github.com/spf13/demo$ go run main.go version
version called
生成的version代码如下(cmd/version.go):
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var versionCmd = &cobra.Command{
Use: "version",
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("version called")
},
}
func init() {
rootCmd.AddCommand(versionCmd)
}
注:命令的名称使用驼峰式命名(camelCase),而不能使用蛇形命名(snake_case)。读者可以自行创建一个蛇形命名的命令来查看一下实际的效果(hint: camelCase to snake_case)。
完善子命令功能
修改上面代码中的函数Run:
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("version called")
},
修改为:
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Version 1.0.0 for demo")
},
再次执行go run main.go version,结果如下:
Version 1.0.0 for demo
另一个示例
在上面的cmd/version.go中我们发现在init函数有这么一行代码:rootCmd.AddCommand(versionCmd),这个rootCmd是什么呢?
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
)
var cfgFile string
var rootCmd = &cobra.Command{
Use: "demo",
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.`,
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.demo.yaml)")
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
viper.AddConfigPath(home)
viper.SetConfigName(".demo")
}
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
打开cmd/root.go(上面的示例代码),你会发现rootCmd其实就是我们的根命令。我相信机智的同学已经猜出来我们添加子命令的子命令的方法了。现在让我们在cmd目录下新建help.go文件,项目文件结构为:
hidden@hidden:~/go/src/github.com/spf13/demo$ tree
.
├── cmd
│ ├── help.go
│ ├── root.go
│ └── version.go
├── LICENSE
└── main.go
1 directory, 5 files
其中cmd/help.go的内容为(help为version的子命令):
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var helpCmd = &cobra.Command{
Use: "help",
Short: "show command info",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Here is the help information")
},
}
func init() {
versionCmd.AddCommand(helpCmd)
}
执行go run main.go version help命令之后,结果为:
hidden:demo hidden$ go run main.go version help
Here is the help information
使用Flags
Flags提供了修饰符来控制动作命令的操作。
Persistent Flags:全局性flag, 可用于它所分配的命令以及该命令下的每个命令。在根上分配标志作为全局flag。
Local Flags:局部性flag,在本args分配一个标志,该标志仅适用于该特定命令。
Required flags:必选flag,flag默认是可选的。如果希望命令在未设置flag时报告错误,请将其标记为required。
添加Flags
如果仔细看过上面cmd/version.go中init函数中的注释的话,你应该已经得到了足够多的信息来自己操作添加flag。
不过这里我再解释一下,首先是persistent参数,当你的参数作为persistent flag存在时,如注释所言,在其所有的子命令之下该参数都是可见的。而local flag则只能在该命令调用时执行。
可以做一个简单的测试,在cmd/version.go的init函数中,添加如下内容(添加在rootCmd.AddCommand(versionCmd)这一行之上):
versionCmd.PersistentFlags().String("global_foo", "global_val", "A help for global_foo")
versionCmd.Flags().String("local_foo","local_val", "A help for local_foo")
现在运行go run main.go version -h得到如下结果:
hidden:demo hidden$ go run main.go version -h
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.
Usage:
demo version [flags]
demo version [command]
Available Commands:
help show command info
Flags:
--global_foo string A help for global_foo (default "global_val")
-h, --help help for version
--local_foo string A help for local_foo (default "local_val")
Global Flags:
--config string config file (default is
$HOME/.demo.yaml)
Use "demo version [command] --help" for more information about a command.
接着我们对比着再运行go run main.go help -h试试:
hidden:demo hidden$ go run main.go version help -h
Usage:
demo version help [flags]
Flags:
-h, --help help for help
Global Flags:
--config string config file (default is $HOME/.demo.yaml)
--global_foo string A help for global_foo (default "global_val")
可以发现在Gloabal Flags的变化。version作为root的子命令,仍然可以使用root的persistent flag-> config(可以查看root.go),而help作为test的子命令,不仅可以使用test的persistent flag-> fool, 也可以使用test父命令的persistent flag。从而我们可以直观的看出persistent的作用范围是该命令之后的所有子命令。
flag支持的参数类型可以参考文档:https://godoc.org/github.com/spf13/cobra
注意:cmd.Flags().String()与 cmd.Flags().StringP()是不一样的。假如我们在version.go的init下增加如下两行:
versionCmd.Flags().String("flag1","", "flag1 usage")
versionCmd.Flags().StringP("flga2","f","", "flag2 usage")
前者调用需要如下形式:
go run main.go version --flag1
后者有如下两种形式调用:
go run main.go version --flag2
go run main.go version -f
其它示例:
persistent flag:
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
local flag:
rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
rootCmd.MarkFlagRequired("source") // Flags默认是可选的。如果您希望命令在未设置Flags时报告错误,请将其标记为必需
获取Flags值
在知道了如何设置参数后,我们的下一步当然是需要在运行时获取改参数的值。现在我们把注意力放到version.go的这个部分:
var versionCmd = &cobra.Command{
Use: "version",
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("Version 1.0.0 for demo")
},
}
让我们把注意力重新放到上面的代码上。我们也很容易可以猜测到Use,Short,Long三个参数的作用,这里便不做阐述。
显而易见,我们应该在Run这里来获取参数并执行我们的命令功能。获取参数其实也并不复杂。以versionCmd.Flags().StringP("flag2", "f", "", "flag2 usage")此为例,我们可以在Run函数里添加:
str,_ := cmd.Flags().GetString("flag2")
fmt.Printf("The param vale is %s\n", str)
运行命令go run main.go version -f vvvv,获得结果如下:
The param vale is vvvv
Version 1.0.0 for demo
使用Args
可以使用Args字段来指定位置参数的验证Command。
以下验证器内置:
-
NoArgs - 如果存在任何位置参数,该命令将报告错误。
-
ArbitraryArgs - 该命令将接受任何args。
-
OnlyValidArgs- 如果存在任何不在ValidArgs字段中的位置参数,该命令将报告错误Command。
-
MinimumNArgs(int) - 如果没有至少N个位置参数,该命令将报告错误。
-
MaximumNArgs(int) - 如果有多于N个位置参数,该命令将报告错误。
-
ExactArgs(int) - 如果没有确切的N位置参数,该命令将报告错误。
-
RangeArgs(min, max) - 如果args的数量不在预期args的最小和最大数量之间,则该命令将报告错误。
为了演示Args的用法,我们在cmd目录下再创建一个args.go文件,其内容如下(注意多了一个Args函数):
mport (
"fmt"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
var argsCmd = &cobra.Command{
Use: "args",
Short: "args demo",
Long: ``,
Args: func(cmd *cobra.Command, args []string) error {
if len(args)<1{
return errors.New("requires at least one arg")
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("args called, args: ", args)
},
}
func init() {
rootCmd.AddCommand(argsCmd)
}
示例中限定参数的格式至少为一个否则会报错。我们来运行一下看一看结果如何,首先是不添加参数(go run main.go args):
hidden:demo hidden$ go run main.go args
Error: requires at least one arg
Usage:
demo args [flags]
Flags:
-h, --help help for args
Global Flags:
--config string config file (default is $HOME/.demo.yaml)
requires at least one arg
exit status 1
可以看到报错:Error: requires at least one arg。
我们再来试一下添加参数的结果:
hidden:demo hidden$ go run main.go args 1
args called, args: [1]
hidden:demo hidden$ go run main.go args 1 2 3 4
args called, args: [1 2 3 4]
示例中的Args函数可以替换为
Args: cobra.MinimumNArgs(1),
读者可以自行验证一下效果。
Help命令
前面的示例中出现了cmd/help.go,为了不产生迷惑,我们把这个文件先删除掉。
当您有子命令时,Cobra会自动为您的应用程序添加一个帮助命令。当用户运行“app help”时会调用此方法。此外,帮助还将支持所有其他命令作为输入。比如说,你有一个名为'create'的命令,没有任何额外的配置; 当'app help create'被调用时,Cobra会工作。每个命令都会自动添加' - help'标志。
可以在终端输入cobra或者cobra help命令看一下实际的效果:
hidden@hidden:~$ cobra help
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.
Usage:
cobra [command]
Available Commands:
add Add a command to a Cobra Application
help Help about any command
init Initialize a Cobra Application
Flags:
-a,
-h,
-l,
Use "cobra [command] --help" for more information about a command.
自定义Help命令
可以提供自定义的help命令或自定义的模板,通过以下函数实现:
cmd.SetHelpCommand(cmd *Command)
cmd.SetHelpFunc(f func(*Command, []string))
cmd.SetHelpTemplate(s string)
后两者也适用于子命令。
Usage
当用户提供无效标志或无效命令时,Cobra会通过向用户显示“usage”来做出响应。
示例:
hidden@hidden:~$ cobra --invalid
Error: unknown flag: --invalid
Usage:
cobra [command]
Available Commands:
add Add a command to a Cobra Application
help Help about any command
init Initialize a Cobra Application
Flags:
-a, --author string author name for