cobra既是创建功能强大的现代CLI应用程序的库,也是生成应用程序和命令文件的程序。
许多使用最广泛的Go项目都是使用Cobra构建的:
Cobra是一个库,提供了一个简单的接口来创建功能强大的现代CLI工具,类似于git&go工具。
Cobra也是一个应用程序,将生成您的应用程序骨架,以迅速开发基于Cobra的应用程序。
Cobra 提供的内容:
* 易用的基于子命令的CLI命令: app server
, app fetch
等
* 完全兼容POSIX的命令参数 (包含show & long 两个版本)
* 嵌套的子命令
* 全局, 局部以及级联的命令参数
* 使用 cobra init appname
& cobra add cmdname
很容易产生程序和增加命令
* 智能的提示 (app srver
… did you mean app server
?)
* 自动为命令和参数创建帮组说明
* 自动识别help参数
* 自动为应用生成bash autocomplete
* 自动为应用生成man文档
* 支持命令别名
* 灵活定义你自己的help,usage等信息
* 可选择为12-factor应用紧密集成viper
Cobra 建立在commands, arguments & flags的基础之上.
Commands 表示操作, Args 是对象 and Flags 是对操作的修饰.
最好的应用程序将在使用时阅读像句子。 用户将知道如何使用该应用程序,因为他们将原生地理解如何使用它。
就像下面的模式一下
APPNAME VERB NOUN --ADJECTIVE.
or
APPNAME COMMAND ARG --FLAG
一些很好的现实世界的例子可能会更好地说明这一点。
在下面的例子中, ‘server’ 是命令, ‘port’ 是参数:
hugo server --port=1313
在这个命令中,我们告诉Git克隆URL.
git clone URL --bare
命令是应用程序的中心点。 应用程序支持的每个交互都将包含在Command中。 一个命令可以有子命令并可以选择运行一个动作。
如下面的例子, ‘server’ 是一个command.
参数是修改命令行为的一种方法。 Cobra支持完全符合POSIX的参数以及Go[flag包](https://golang.org/pkg/flag/)。 Cobra命令可以定义持续到子命令的标志,以及只对该命令可用的标志。
在下面的例子中, ‘port’ 是一个参数.
参数功能由[pflag库](https://github.com/spf13/pflag)提供,标志标准库的一个分支,在添加POSIX合规性的同时保持相同的接口。
使用cobra很容易。 首先,使用go get
安装最新版本的库。 这个命令将安装cobra
生成器可执行文件以及库和它的依赖关系:
go get -u github.com/spf13/cobra/cobra
再者, 在你们应用里面包含Cobra:
import "github.com/spf13/cobra"
虽然欢迎您提供自己的组织,但通常基于Cobra的应用程序将遵循以下组织结构:
▾ appName/
▾ cmd/
add.go
your.go
commands.go
here.go
main.go
在Cobra应用程序中,通常main.go文件非常空白。 它有一个目的:初始化Cobra。
package main
import (
"fmt"
"os"
"{pathToYourApp}/cmd"
)
func main() {
if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
Cobra提供自己的程序,将创建您的应用程序,并添加任何你想要的命令。 将Cobra整合到您的应用程序中是最简单的方法。
Here 你可以访问到详细的内容.
要手动实现Cobra,您需要创建一个纯粹的main.go文件和一个RootCmd文件。 您可以根据需要提供其他命令。
Cobra doesn’t require any special constructors. Simply create your commands.
Cobra并不需要任何指定的constructors, 仅仅创建你的命令
你可以将他们放在这个 app/cmd/root.go:
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 http://hugo.spf13.com`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
}
您将另外定义Cobra并处理init()函数中的配置。
例如 cmd/root.go:
import (
"fmt"
"os"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func init() {
cobra.OnInitialize(initConfig)
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/")
RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)")
RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase"))
viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper"))
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("license", "apache")
}
func initConfig() {
// Don't forget to read config either from cfgFile or from home directory!
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".cobra")
}
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can't read config:", err)
os.Exit(1)
}
}
In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra.
使用root命令,你需要让主函数执行它。
尽管可以在任何命令上调用Execute,但为了清晰起见,应该在根上运行Execute。
在Cobra应用程序中,通常main.go文件非常空白。 它有一个目的,来初始化Cobra。
package main
import (
"fmt"
"os"
"{pathToYourApp}/cmd"
)
func main() {
if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
额外的命令可以定义,通常每个命令都有自己的文件
在cmd /目录里面。
如果你想创建一个版本命令,你可以创建cmd / version.go和
用下面的代码填充它:
package cmd
import (
"github.com/spf13/cobra"
"fmt"
)
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")
},
}
参数提供修饰符来控制动作命令的操作
由于参数是在不同的位置定义和使用的,我们需要在正确的范围外定义一个变量来分配参数。
var Verbose bool
var Source string
有两种不同的方法来分配一个参数。
一个参数可以是“持久的”,这意味着这个参数将被分配的命令以及该命令下的每个命令都可用。 对于全局参数,在根上分配一个参数作为持久参数。
RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
一个参数也可以在本地分配,只适用于该特定的命令。
RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
默认情况下,Cobra只解析目标命令上的本地参数,任何
父命令的本地参数被忽略。 通过启用Command.TraverseChildren
croba将
在执行目标命令之前解析每个命令的本地参数。
command := cobra.Command{
Use: "print [OPTIONS] [COMMANDS]",
TraverseChildren: true,
}
你可以通过viper来绑定你的参数:
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
不会被设置为config的值。
更多内容参考viper documentation.
位置参数的验证可以使用Command
的Args
字段指定。
内置有如下验证器:
NoArgs
- the command will report an error if there are any positional args.ArbitraryArgs
- the command will accept any args.OnlyValidArgs
- the command will report an error if there are any positional args that are not in the ValidArgs
field of Command
.MinimumNArgs(int)
- the command will report an error if there are not at least N positional args.MaximumNArgs(int)
- the command will report an error if there are more than N positional args.ExactArgs(int)
- the command will report an error if there are not exactly N positional args.RangeArgs(min, max)
- the command will report an error if the number of args is not between the minimum and maximum number of expected args.设置自定义验证器的示例:
var cmd = &cobra.Command{
Short: "hello",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("requires at least one arg")
}
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!")
},
}
在下面的例子中,我们定义了三个命令。 两个在顶层
而一个(cmdTimes)是最高命令之一的孩子。 在这种情况下,根
不可执行,这意味着一个子命令是必需的。 这是完成的
通过不为“rootCmd”提供“运行”。
我们只为一个命令定义了一个参数。
有关标志的更多文档可在https://github.com/spf13/pflag中找到
package main
import (
"fmt"
"strings"
"github.com/spf13/cobra"
)
func main() {
var echoTimes int
var cmdPrint = &cobra.Command{
Use: "print [string to print]",
Short: "Print anything to the screen",
Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdEcho = &cobra.Command{
Use: "echo [string to echo]",
Short: "Echo anything to the screen",
Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdTimes = &cobra.Command{
Use: "times [# times] [string to echo]",
Short: "Echo anything to the screen more times",
Long: `echo things multiple times back to the user by providing
a count and a string.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
for i := 0; i < echoTimes; i++ {
fmt.Println("Echo: " + strings.Join(args, " "))
}
},
}
cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
var rootCmd = &cobra.Command{Use: "app"}
rootCmd.AddCommand(cmdPrint, cmdEcho)
cmdEcho.AddCommand(cmdTimes)
rootCmd.Execute()
}
有关更大型应用程序的更完整示例,请查看[Hugo](http://gohugo.io/)。
当您有子命令时,Cobra会自动向您的应用程序添加一个帮助命令。 这将在用户运行“app help”时被调用。 此外,帮助也将支持所有其他命令作为输入。 比如说,你有一个叫做“create”的命令,没有任何额外的配置; 当“app help create”被调用时,Cobra将工作。 每个命令都会自动添加“–help”标志。
以下输出是由cobra自动生成的。 除了命令和标志定义之外,什么都不需要。
$ 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, --author string author name for copyright attribution (default "YOUR NAME")
--config string config file (default is $HOME/.cobra.yaml)
-h, --help help for cobra
-l, --license string name of license for the project
--viper use Viper for configuration (default true)
Use "cobra [command] --help" for more information about a command.
帮助就像任何其他的命令一样。 周围没有特殊的逻辑或行为
您可以提供自己的帮助命令或您自己的模板,以使用缺省命令与followind函数一起使用:
cmd.SetHelpCommand(cmd *Command)
cmd.SetHelpFunc(f func(*Command, []string))
cmd.SetHelpTemplate(s string)
后两者也将适用于任何子命令。
When the user provides an invalid flag or invalid command, Cobra responds by
showing the user the ‘usage’.
当用户提供无效参数或无效命令时,Cobra通过向用户显示“usage”做出响应。
You may recognize this from the help above. That’s because the default help
embeds the usage as part of its output.
你可以从上面的帮助中认识到这一点。 这是因为默认帮助嵌入使用作为其输出的一部分。
$ 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 copyright attribution (default "YOUR NAME")
--config string config file (default is $HOME/.cobra.yaml)
-h, --help help for cobra
-l, --license string name of license for the project
--viper use Viper for configuration (default true)
Use "cobra [command] --help" for more information about a command.
您可以提供您自己的使用功能或模板供Cobra使用。 像帮助一样,函数和模板可以通过公共方法重写:
cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string)
可以在命令的主“Run”功能之前或之后运行功能。 PersistentPreRun和PreRun函数将在Run之前执行。 PersistentPostRun和PostRun将在Run之后执行。 如果Persistent * Run函数没有声明自己,那么Persistent * Run
函数将被子代继承。 这些功能按以下顺序运行:
PersistentPreRun
PreRun
Run
PostRun
PersistentPostRun
以下是使用所有这些功能的两个命令的示例。当子命令被执行时,它将运行root命令的PersistentPreRun
而不是根命令的PersistentPostRun
:
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()
}
Output:
Inside rootCmd PersistentPreRun with args: []
Inside rootCmd PreRun with args: []
Inside rootCmd Run with args: []
Inside rootCmd PostRun with args: []
Inside rootCmd PersistentPostRun with args: []
Inside rootCmd PersistentPreRun with args: [arg1 arg2]
Inside subCmd PreRun with args: [arg1 arg2]
Inside subCmd Run with args: [arg1 arg2]
Inside subCmd PostRun with args: [arg1 arg2]
Inside subCmd PersistentPostRun with args: [arg1 arg2]
Cobra will print automatic suggestions when “unknown command” errors happen. This allows Cobra to behave similarly to the git
command when a typo happens. For example:
当“未知命令”错误发生时,Cobra将打印自动建议。 当发生错字时,这允许Cobra的行为类似于git
命令。 例如:
$ hugo srever
Error: unknown command "srever" for "hugo"
Did you mean this?
server
Run 'hugo --help' for usage.
建议是基于每个子命令注册的自动化,并使用[Levenshtein distance](http://en.wikipedia.org wiki / Levenshtein_distance)的实现。 每个注册的命令匹配的最小距离为2(忽略大小写)将显示为一个建议。
如果您需要禁用建议或在命令中调整字符串距离,请使用:
command.DisableSuggestions = true
or
command.SuggestionsMinimumDistance = 1
您还可以使用SuggestFor属性显式设置给定命令的名称。这允许对字符串距离不接近的字符串提出建议,但是对于您的一组命令以及对于某些您不需要别名的字符串来说是有意义的。 例:
$ kubectl remove
Error: unknown command "remove" for "kubectl"
Did you mean this?
delete
Run 'kubectl help' for usage.
Cobra可以使用以下格式生成基于子命令,标志等的文档:
Cobra可以生成一个bash补全文件。 如果你添加更多的信息到你的命令,这些完成可以非常强大和灵活。 在[Bash Completions](bash_completions.md)中阅读更多关于它的信息。