Cobra既是用于創(chuàng)建強(qiáng)大的現(xiàn)代CLI應(yīng)用程序的庫,也是用于生成應(yīng)用程序和命令文件的程序。
許多使用最廣泛的Go項(xiàng)目都是使用Cobra構(gòu)建的,其中包括:
Cobra是一個(gè)庫,提供了一個(gè)簡單的接口來創(chuàng)建功能強(qiáng)大的類似于git和go的現(xiàn)代CLI程序。
Cobra也是一個(gè)應(yīng)用程序,幫助你生成應(yīng)用程序腳手架,以快速開發(fā)基于Cobra的應(yīng)用程序。
Cobra提供了:
CobraCobra建立在命令,參數(shù)和標(biāo)志的結(jié)構(gòu)上。
命令表示動(dòng)作,參數(shù)是事物,標(biāo)志是這些動(dòng)作的修飾符。
最好的應(yīng)用程序的命令使用起來應(yīng)該像一個(gè)句子一樣。用戶將知道如何使用應(yīng)用程序,因?yàn)楹茏匀痪兔靼滓馑肌?br/>遵循的模式是APPNAME VERB NOUN --ADJECTIVE. 或 APPNAME COMMAND ARG --FLAG
舉幾個(gè)現(xiàn)實(shí)中比較好的例子來說明這一點(diǎn)。
在下面的例子中,server是一個(gè)命令,port是一個(gè)標(biāo)志:
hugo server --port=1313
下面這個(gè)命令告訴我們git以bare方式克隆URL
git clone URL --bare
命令是應(yīng)用程序的中心,應(yīng)用程序所支持的每一個(gè)交互都包含在命令中,一個(gè)命令可以有子命令,并可以選擇運(yùn)行一個(gè)動(dòng)作。
在上面的例子中,server是一個(gè)命令
關(guān)于cobra.Command文檔
標(biāo)志是修改命令行為的一種方式。Cobra完全符合POSIX的標(biāo)志和Go的標(biāo)志。Cobra命令可以定義所有命令都能使用的persist標(biāo)志,也能定義僅對(duì)某命令有效的標(biāo)志。
在上面的例子中,port是標(biāo)志。
標(biāo)志功能由pflag庫提供,這是標(biāo)準(zhǔn)庫中flag的一個(gè)分支,它在保持相同接口的同時(shí)增加了POSIX合規(guī)性。
使用Cobra很容易。首先,使用go get安裝最新版本的庫。該命令將安裝可執(zhí)行的cobra生成器,庫和它的依賴庫:
go get -u github.com/spf13/cobra/cobra
接下來,在你的應(yīng)用程序中國年包含Cobra:
import "github.com/spf13/cobra"
盡管歡迎您提供自己的組織,但通?;贑obra的應(yīng)用程序?qū)⒆裱韵陆M織結(jié)構(gòu):
? appName/
? cmd/
add.go
your.go
commands.go
here.go
main.go
在Cobra應(yīng)用程序中,通暢main.go文件非常簡單,它只有一個(gè)目的:初始化Cobra。
package main
import (
"fmt"
"os"
"{pathToYourApp}/cmd"
)
func main() {
cmd.Execute()
}
Cobra提供了自己的程序,它將創(chuàng)建你的應(yīng)用程序并添加你想要的任何命令。這是將Cobra整合到您的應(yīng)用程序中的最簡單方法。
cobra init [app] 命令將為你創(chuàng)建初始的應(yīng)用程序代碼。這是一個(gè)功能非常強(qiáng)大的應(yīng)用程序,它可以使您的程序具有適當(dāng)?shù)慕Y(jié)構(gòu),因此您可以立即享受到Cobra的所有好處。它也會(huì)自動(dòng)將您指定的許可證應(yīng)用于你的應(yīng)用程序。
Cobra init非常聰明。您可以提供完整的路徑,或者只是一個(gè)類似于導(dǎo)入路徑:
cobra init github.com/spf13/newApp
應(yīng)用程序初始化后,Cobra可以為您創(chuàng)建其他命令。假設(shè)您創(chuàng)建了一個(gè)應(yīng)用程序,并且需要以下命令:
app config create
在您的項(xiàng)目目錄中(您的main.go文件所在的位置),您可以運(yùn)行以下命令:
cobra add serve
cobra add config
cobra add create -p 'configCmd'
注意:對(duì)于命令名稱使用camelCase(不是snake_case / snake-case)。否則,你會(huì)遇到錯(cuò)誤。例如,cobra add add-user不正確,但是cobra add addUser有效。
一旦你運(yùn)行了這三個(gè)命令,你就會(huì)有一個(gè)類似于以下的應(yīng)用程序結(jié)構(gòu):
? app/
? cmd/
serve.go
config.go
create.go
main.go
此時(shí)你可以運(yùn)行g(shù)o run main.go,它會(huì)運(yùn)行你的應(yīng)用程序。go run main.go serve,go run main.go config,go run main.go config create以及go run main.go help serve等都可以執(zhí)行。
顯然你還沒有添加你自己的代碼。但這些命令已準(zhǔn)備好了。
如果您提供一個(gè)簡單的配置文件,Cobra生成器將更易于使用,這將幫助您避免在標(biāo)志中反復(fù)提供大量重復(fù)信息。
例如~/.cobra.yaml文件:
author: Steve Francia
license: MIT
您可以通過設(shè)置license為指定任何許可證,none或者您也可以指定自定義許可證:
license:
header: This file is part of {{ .appName }}.
text: |
{{ .copyright }}
This is my license. There are many like it, but this one is mine.
My license is my best friend. It is my life. I must master it as I must
master my life.
您也可以使用內(nèi)置許可證。例如,GPLv2,GPLv3,LGPL, AGPL,MIT,2-Clause BSD或3-Clause BSD。
要手動(dòng)實(shí)現(xiàn)Cobra您需要提供一個(gè)簡潔的mai.go文件和一個(gè)rootCmd文件。如果你認(rèn)為合適,你也可以選擇其他命令。
Cobra不需要任何構(gòu)造函數(shù),只需要?jiǎng)?chuàng)建你的命令。
理想情況下,應(yīng)該把它放在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
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
你還將在init函數(shù)中定義標(biāo)志并處理配置:
例如 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 ")
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)
}
}
您需要讓主函數(shù)執(zhí)行root命令。盡管可以在任何命令上調(diào)用Execute,但為了清晰起見,應(yīng)該在根上運(yùn)行Execute。
在Cobra應(yīng)用程序中,通常main.go文件非常簡潔。它用于初始化Cobra。
package main
import (
"fmt"
"os"
"{pathToYourApp}/cmd"
)
func main() {
cmd.Execute()
}
可以定義其他命令,并且通常分別寫在cmd/目錄中的不同文件里。
如果您像創(chuàng)建一個(gè)版本命令,你可以創(chuàng)建 cmd/version.go并導(dǎo)入:
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")
},
}
標(biāo)志是用來控制命令行為的一種方式。
由于標(biāo)志是在不同位置定義和使用的,因此我們需要在正確的范圍外定義一個(gè)變量來分配給標(biāo)志。
var Verbose bool
var Source string
有兩種不同的方法來分配一個(gè)標(biāo)志。
一個(gè)標(biāo)志是可以持久的,著意味著這個(gè)標(biāo)志將可以用于它分配的命令以及該命令下的每個(gè)命令。對(duì)于全局標(biāo)志,在根上分配一個(gè)標(biāo)志作為持久標(biāo)志。
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
一個(gè)標(biāo)志也可以在本地分配,只適用于該特定命令。
rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
默認(rèn)情況下,Cobra僅解析目標(biāo)命令上的本地標(biāo)志,父命令上的任何本地標(biāo)志都將被忽略。通過啟用Command.TraverseChildren,將在執(zhí)行目標(biāo)命令之前解析每個(gè)命令上的本地標(biāo)志。
command := cobra.Command{
Use: "print [OPTIONS] [COMMANDS]",
TraverseChildren: true,
}
你可以綁定你的flag到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"))
}
在這個(gè)例子中,持久標(biāo)志author被綁定到了viper。請(qǐng)注意,如果用戶沒有從viper中提供值,則該author不會(huì)被設(shè)置。
了解更多請(qǐng)看viper文檔
標(biāo)志默認(rèn)是可選的,如果你希望在沒有提供標(biāo)志時(shí)報(bào)錯(cuò),請(qǐng)將標(biāo)志標(biāo)記為必需的:
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
rootCmd.MarkFlagRequired("region")
位置參數(shù)的校驗(yàn)可以使用Command的Args字段。
以下是內(nèi)置的校驗(yàn)器:
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!")
},
}
在下面的例子中,我們定義了三個(gè)命令。兩個(gè)在頂層,其中cmdTimes就是頂層命令的子命令之一。在這種情況下,根不可執(zhí)行,這意味著需要子命令。這是通過不為'rootCmd'提供'Run'來實(shí)現(xiàn)的。
我們只為單個(gè)命令定義了一個(gè)標(biāo)志。
有關(guān)標(biāo)志的更多文檔可在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()
}
有關(guān)更大型應(yīng)用程序的更完整示例,請(qǐng)參見Hugo。
當(dāng)您有子命令時(shí),Cobra會(huì)自動(dòng)為您的應(yīng)用程序添加一條幫助命令。用戶運(yùn)行“app help”命令時(shí)調(diào)用該幫助命令。此外,幫助還將支持所有其他的命令作為輸入。比如說,你有一個(gè)叫做'create'的命令,沒有任何額外的配置; 幫助命令將在'app help create'運(yùn)行時(shí)被調(diào)用。每個(gè)命令都會(huì)自動(dòng)添加'--help'標(biāo)志。
例
以下輸出由Cobra自動(dòng)生成。
$ 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.
幫助就像任何其他命令一樣。周圍沒有特殊的邏輯或行為。事實(shí)上,如果你愿意,你可以提供你自己的。
你可以提供自己的幫助命令或自己的模版,用一下函數(shù):
cmd.SetHelpCommand(cmd *Command)
cmd.SetHelpFunc(f func(*Command, []string))
cmd.SetHelpTemplate(s string)
后面兩個(gè)函數(shù)也應(yīng)用于任何子命令。
當(dāng)用戶提供無效的標(biāo)志或無效的命令時(shí),Cobra會(huì)顯示使用幫助。
例子:
您可以從上面的幫助中了解到這一點(diǎn),因?yàn)槟J(rèn)幫助將使用信息作為其輸出的一部分嵌入。
$ 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.
您可以提供您自己的用法函數(shù)或模板。像幫助一樣,函數(shù)和模板可以通過方法重寫:
cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string)
如果Version字段在根命令上設(shè)置,則Cobra將添加頂級(jí)“--version”標(biāo)志。使用'--version'標(biāo)志運(yùn)行應(yīng)用程序?qū)⑹褂冒姹灸0鍖姹敬蛴〉綐?biāo)準(zhǔn)輸出。該模板可以使用該cmd.SetVersionTemplate(s string)功能進(jìn)行定制 。
可以命令Run主要功能之前或之后運(yùn)行函數(shù)。該P(yáng)ersistentPreRun和PreRun函數(shù)在Run之前被執(zhí)行。PersistentPostRun并PostRun會(huì)在Run之后被執(zhí)行。Persistent*Run如果子命令沒有聲明他們自己的函數(shù),這些函數(shù)將被繼承。這些函數(shù)按以下順序運(yùn)行:
PersistentPostRun
以下是使用所有這些特性的兩個(gè)命令的示例。當(dāng)子命令執(zhí)行時(shí),它將運(yùn)行root命令的PersistentPreRun,但不運(yùn)行root命令的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()
}
當(dāng)“unknown command”錯(cuò)誤發(fā)生時(shí),Cobra將打印自動(dòng)建議。這使得Cobra于git在發(fā)生錯(cuò)字時(shí)的表現(xiàn)類似。例如:
$ hugo srever
Error: unknown command "srever" for "hugo"
Did you mean this?
server
Run 'hugo --help' for usage.
建議是根據(jù)每個(gè)已注冊(cè)的子命令自動(dòng)生成的,并使用Levenshtein distance的實(shí)現(xiàn)。每個(gè)注冊(cè)的命令的最小距離為2(忽略大小寫)將顯示為建議。
如果您需要禁用建議或在命令中調(diào)整字符串距離,請(qǐng)使用:
command.DisableSuggestions = true
或者
command.SuggestionsMinimumDistance = 1
您還可以使用SuggestFor設(shè)置命令的建議。這允許對(duì)字符串距離不近的字符串提供建議,但對(duì)于您的一組命令以及對(duì)于某些您不想使用別名的字符串來說是有意義的。例:
$ kubectl remove
Error: unknown command "remove" for "kubectl"
Did you mean this?
delete
Run 'kubectl help' for usage.
Cobra可以使用以下格式生成基于子命令、標(biāo)志等的文檔:
Cobra可以生成一個(gè)bash完成文件。如果您在命令中添加更多信息,這些完成功能可以非常強(qiáng)大且靈活。在Bash完成中閱讀更多關(guān)于它的信息。
1、Fork倉庫
2、克隆你fork的倉庫到你的電腦上(git clone https://github.com/your_username/cobra && cd cobra)
3、創(chuàng)建您的功能分支(git checkout -b my-new-feature)
4、進(jìn)行更改并添加它們(git add .)
5、提交您的更改(git commit -m 'Add some feature')
6、推送到分支(git push origin my-new-feature)
7、創(chuàng)建新的pull request
Cobra 是在Apache 2.0許可下發(fā)布的。請(qǐng)參閱LICENSE.txt
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。