godoc
github 官网
github 官网用户指南
目录组织结构
1
2
3
4
5
6
7
|
▾ appName/
▾ cmd/
add.go
your.go
commands.go
here.go
main.go
|
main.go
1
2
3
4
5
6
7
8
9
|
package main
import (
"{pathToYourApp}/cmd"
)
func main() {
cmd.Execute()
}
|
使用 Cobra 库
创建一个裸 main.go 文件和一个 rootCmd 文件
创建rootCmd
app/cmd/root.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var rootCmd = &cobra.Command{
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
Complete documentation is available at https://gohugo.io/documentation/`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
|
init() 函数中另外定义标志和句柄配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
// Used for flags.
cfgFile string
userLicense string
rootCmd = &cobra.Command{
Use: "cobra-cli",
Short: "A generator for Cobra based Applications",
Long: `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.`,
}
)
// Execute executes the root command.
func Execute() error {
return rootCmd.Execute()
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("license", "apache")
rootCmd.AddCommand(addCmd)
rootCmd.AddCommand(initCmd)
}
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := os.UserHomeDir()
cobra.CheckErr(err)
// Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".cobra")
}
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
|
创建main.go
通常 main.go 文件非常简单。它的目的只有一个:初始化 Cobra。
1
2
3
4
5
6
7
8
9
|
package main
import (
"{pathToYourApp}/cmd"
)
func main() {
cmd.Execute()
}
|
创建子命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(versionCmd)
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of Hugo",
Long: `All software has versions. This is Hugo's`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hugo Static Site Generator v0.9 -- HEAD")
},
}
|
组织子命令
通过使用 AddCommand 来实现
推荐结构
1
2
3
4
5
6
7
8
9
|
├── cmd
│ ├── root.go
│ └── sub1
│ ├── sub1.go
│ └── sub2
│ ├── leafA.go
│ ├── leafB.go
│ └── sub2.go
└── main.go
|
返回和处理错误
使用RunE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(tryCmd)
}
var tryCmd = &cobra.Command{
Use: "try",
Short: "Try and possibly fail at something",
RunE: func(cmd *cobra.Command, args []string) error {
if err := someFunc(); err != nil {
return err
}
return nil
},
}
|
使用标志flag
为命令分配标志
1
2
|
var Verbose bool
var Source string
|
两种不同的方法来分配标志
持久标志
标志可以是“持久的”,这意味着该标志将可用于分配给它的命令以及该命令下的每个命令
对于全局标志,将标志分配为根上的持久标志
1
|
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
|
本地标志
在本地分配标志,该标志仅适用于该特定命令
1
|
localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
|
通过配置Command.TraverseChildren为true可以将标志传递给孩子
1
2
3
4
|
command := cobra.Command{
Use: "print [OPTIONS] [COMMANDS]",
TraverseChildren: true,
}
|
配置绑定标志
可以使用viper绑定标志
1
2
3
4
5
6
|
var author string
func init() {
rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
}
|
持久标志 author 与 viper 绑定。 注意:当用户提供标志–author时,该变量将不会设置为配置中author的值
必需的标志
默认情况下,标志是可选的,通过MarkFlagRequired和MarkPersistentFlagRequired方法将flag设为必须的
1
2
3
4
5
|
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
rootCmd.MarkFlagRequired("region")
rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
rootCmd.MarkPersistentFlagRequired("region")
|
标志组
必须一起提供的不同标志,用MarkFlagsRequiredTogether方法
1
2
3
|
rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
rootCmd.MarkFlagsRequiredTogether("username", "password")
|
防止一起提供不同的标志,用MarkFlagsMutuallyExclusive方法
1
2
3
|
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
|
至少存在一个标志,用MarkFlagsOneRequired方法,可以和MarkFlagsMutuallyExclusive组合实现只能使用一个标志
1
2
3
|
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
rootCmd.MarkFlagsOneRequired("json", "yaml")
|
注意:
- 本地和持久标志都可以使用
- 一个标志可能出现在多个组中
- 一个组可以包含任意数量的标志
位置和自定义参数
位置参数的验证可以使用Command的Args字段来指定。内置以下验证器:
对于参数数量
- NoArgs- 如果有任何位置参数,则报告错误
- ArbitraryArgs- 接受任意数量的参数
- MinimumNArgs(int)- 如果提供的位置参数少于 N 个,则报告错误
- MaximumNArgs(int)- 如果提供了超过 N 个位置参数,则报告错误
- ExactArgs(int)- 如果不存在恰好 N 个位置参数,则报告错误。
- RangeArgs(min, max)- 如果参数数量不在min和max之间,则报告错误
对于参数内容
- OnlyValidArgs- 如果位置参数不是Command的ValidArgs字段对应的字符串切片里的值则报错
1
2
3
4
5
6
7
8
9
10
|
var cmd = &cobra.Command{
Use: "fruit",
Short: "Choose a fruit",
Long: "You can choose an apple, a banana, or a cherry",
Args: cobra.OnlyValidArgs,
ValidArgs: []string{"apple", "banana", "cherry"},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Your fruit:", args[0])
},
}
|
Args未定义 或 nil,则默认为ArbitraryArgs
MatchAll(pargs …PositionalArgs)还可以将现有检查与任意其他检查相结合
1
2
3
4
5
6
7
|
var cmd = &cobra.Command{
Short: "hello",
Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, World!")
},
}
|
可以设置任何满足 func(cmd *cobra.Command, args []string) error 的自定义验证器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var cmd = &cobra.Command{
Short: "hello",
Args: func(cmd *cobra.Command, args []string) error {
// Optionally run one of the validators provided by cobra
if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
return err
}
// Run the custom validation logic
if myapp.IsValidColor(args[0]) {
return nil
}
return fmt.Errorf("invalid color specified: %s", args[0])
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, World!")
},
}
|
帮助命令
自动添加,–help
帮助中的分组命令
见原文
定义您自己的帮助
可以为默认命令提供您自己的帮助命令或您自己的模板
1
2
3
|
cmd.SetHelpCommand(cmd *Command)
cmd.SetHelpFunc(f func(*Command, []string))
cmd.SetHelpTemplate(s string)
|
使用信息
用户提供无效标志或无效命令时,Cobra 会通过向用户显示“用法”进行响应
定义您自己的用法
可以提供自己的使用函数或模板供Cobra使用。与帮助一样,函数和模板可以通过公共方法重写:
1
2
|
cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string)
|
版本标志
如果在 root 命令上设置了 Version 字段,Cobra 会添加一个顶级“–version”标志
使用“–version”标志运行应用程序将使用版本模板将版本打印到标准输出
可以使用 cmd.SetVersionTemplate(s string) 方法自定义模板
PreRun 和 PostRun 钩子
可以在Command的Run主函数之前或之后运行函数
如果子级不声明自己的函数,则Persistent*Run函数将由子级继承
这些函数按以下顺序运行
- PersistentPreRun
- PreRun
- Run
- PostRun
- PersistentPostRun
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package main
import (
"fmt"
"github.com/spf13/cobra"
)
func main() {
var rootCmd = &cobra.Command{
Use: "root [sub]",
Short: "My root command",
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("Inside rootCmd 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)
},
}
var subCmd = &cobra.Command{
Use: "sub [no options!]",
Short: "My subcommand",
PreRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside subCmd PreRun with args: %v\n", args)
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside subCmd Run with args: %v\n", args)
},
PostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside subCmd PostRun with args: %v\n", args)
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)
},
}
rootCmd.AddCommand(subCmd)
rootCmd.SetArgs([]string{""})
rootCmd.Execute()
fmt.Println()
rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
rootCmd.Execute()
}
|
出现“未知命令”时的建议
见原文
为您的命令生成文档
见原文
生成 shell 文件
见原文