cobra 是 go 語言的一個庫,能夠用於編寫命令行工具。一般咱們能夠看到git pull
、docker container start
、apt install
等等這樣命令,均可以很容易用corba來實現,另外,go 語言是很容易編譯成一個二進制文件,本文將實現一個簡單的命令行工具。html
cobra 的主要功能以下,能夠說每一項都很實用:git
cobra 中有個重要的概念,分別是 commands、arguments 和 flags。其中 commands 表明行爲,arguments 就是命令行參數(或者稱爲位置參數),flags 表明對行爲的改變(也就是咱們常說的命令行選項)。執行命令行程序時的通常格式爲:
APPNAME COMMAND ARG --FLAG
好比下面的例子:github
# server是 commands,port 是 flag hugo server --port=1313 # clone 是 commands,URL 是 arguments,brae 是 flag git clone URL --bare
若是是一個簡單的程序(功能單一的程序),使用 commands 的方式可能會很囉嗦,可是像 git、docker 等應用,把這些本就很複雜的功能劃分爲子命令的形式,會方便使用(對程序的設計者來講又未嘗不是如此)。docker
在建立 cobra 應用前須要先安裝 cobra 包: go get -u github.com/spf13/cobra/cobrabash
而後就能夠用 cobra 程序生成應用程序框架了: cobra init --pkg-name cobrademo [在cobrademo目錄下執行]app
除了生成應用程序框架,還能夠經過 cobra add 命令生成子命令的代碼文件,好比下面的命令會添加兩個子命令 image 和 container 相關的代碼文件: cobra add image 和 cobra add container框架
這兩條命令分別生成了 cobrademo 程序中 image 和 container 子命令的代碼,固然了,具體的功能還得靠咱們本身實現。ide
到目前爲止,咱們一共爲 cobrademo 程序添加了三個 Command,分別是 rootCmd(cobra init 命令默認生成)、imageCmd 和 containerCmd。
打開文件 root.go ,找到變量 rootCmd 的初始化過程併爲之設置 Run 方法:工具
Run: func(cmd *cobra.Command, args []string) { fmt.Println("cobra demo program") },
從新編譯 cobrademo 程序並不帶參數運行【初次要執行 go mod init】,此次就再也不輸出幫助信息了,而是執行了 rootCmd 的 Run 方法:fetch
D:\Project\GoProject\src\cobrademo>go build -o . D:\Project\GoProject\src\cobrademo>cobrademo.exe cobra demo program
再建立一個 version Command 用來輸出當前的軟件版本。先在 cmd 目錄下添加 version.go 文件[ cobra add version],編輯文件的內容以下:
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 cobrademo", Long: `All software has versions. This is cobrademo's`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("cobrademo version is v1.0") }, }
D:\Project\GoProject\src\cobrademo>go run main.go version cobrademo version is v1.0
選項(flags)用來控制 Command 的具體行爲。根據選項的做用範圍,能夠把選項分爲兩類:
對於 persistent 類型的選項,既能夠設置給該 Command,又能夠設置給該 Command 的子 Command。對於一些全局性的選項,比較適合設置爲 persistent 類型,好比控制輸出的 verbose 選項:
var Verbose bool rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
local 類型的選項只能設置給指定的 Command,好比下面定義的 source 選項:
var Source string rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
該選項不能指定給 rootCmd 以外的其它 Command。
默認狀況下的選項都是可選的,但一些用例要求用戶必須設置某些選項,這種狀況 cobra 也是支持的,經過 Command 的 MarkFlagRequired 方法標記該選項便可:
var Name string rootCmd.Flags().StringVarP(&Name, "name", "n", "", "user name (required)") rootCmd.MarkFlagRequired("name")
首先咱們來搞清楚命令行參數(arguments)與命令行選項的區別(flags/options)。以常見的 ls 命令來講,其命令行的格式爲:
ls [OPTION]... [FILE]…
其中的 OPTION 對應本文中介紹的 flags,以 - 或 -- 開頭;而 FILE 則被稱爲參數(arguments)或位置參數。通常的規則是參數在全部選項的後面,上面的 … 表示能夠指定多個選項和多個參數。
cobra 默認提供了一些驗證方法:
咱們在前面建立的代碼的基礎上,爲 image 命令添加行爲(打印信息到控制檯),併爲它添加一個子命令 cmdTimes,下面是更新後的 image.go 文件的內容:
package cmd import ( "fmt" "strings" "github.com/spf13/cobra" ) // imageCmd represents the image command var imageCmd = &cobra.Command{ Use: "image", Short: "Print images information", Long: "Print all images information", Run: func(cmd *cobra.Command, args []string) { fmt.Println("image one is win7") fmt.Println("image two is win10") fmt.Println("image args are : " + strings.Join(args, " ")) }, } var echoTimes int var cmdTimes = &cobra.Command{ Use: "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, " ")) } }, } func init() { rootCmd.AddCommand(imageCmd) cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") imageCmd.AddCommand(cmdTimes) }
編譯後執行命令:
D:\Project\GoProject\src\cobrademo>go run main.go image hello image one is win7 image two is win10 image args are : hello D:\Project\GoProject\src\cobrademo>go run main.go image times -t=3 world Echo: world Echo: world Echo: world D:\Project\GoProject\src\cobrademo>go run main.go image times -t=3 Error: requires at least 1 arg(s), only received 0 Usage: cobrademo image times [string to echo] [flags] Flags: -h, --help help for times -t, --times int times to echo the input (default 1) Global Flags: --config string config file (default is $HOME/.cobrademo.yaml) requires at least 1 arg(s), only received 0 exit status 1 D:\Project\GoProject\src\cobrademo>
由於咱們爲 cmdTimes 命令設置了 Args: cobra.MinimumNArgs(1),因此必須爲 times 子命令傳入一個參數,否則 times 子命令會報錯:
cobra 會自動添加 --help(-h)選項,因此咱們能夠沒必要添加該選項而直接使用:
D:\Project\GoProject\src\cobrademo>go run main.go -h 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. Usage: cobrademo [flags] cobrademo [command] Available Commands: container A brief description of your command help Help about any command image Print images information version Print the version number of cobrademo Flags: --config string config file (default is $HOME/.cobrademo.yaml) -h, --help help for cobrademo -t, --toggle Help message for toggle Use "cobrademo [command] --help" for more information about a command.
cobra 同時還自動添加了 help 子命,默認效果和使用 --help 選項相同。若是爲 help 命令傳遞其它命令做爲參數,則會顯示對應命令的幫助信息,下面的命令輸出 image 子命令的幫助信息:
D:\Project\GoProject\src\cobrademo>go run main.go help image Print all images information Usage: cobrademo image [flags] cobrademo image [command] Available Commands: times Echo anything to the screen more times Flags: -h, --help help for image Global Flags: --config string config file (default is $HOME/.cobrademo.yaml) Use "cobrademo image [command] --help" for more information about a command.
固然也能夠經過這種方式查看子命令的子命令的幫助文檔:go run main.go help image times
除了 cobra 默認的幫助命令,咱們還能夠經過下面的方式進行自定義:
cmd.SetHelpCommand(cmd *Command) cmd.SetHelpFunc(f func(*Command, []string)) cmd.SetHelpTemplate(s string)
提示信息和幫助信息很類似,只不過它是在你輸入了非法的參數、選項或命令時纔出現的,和幫助信息同樣,咱們也能夠經過下面的方式自定義提示信息:
cmd.SetUsageFunc(f func(*Command) error) cmd.SetUsageTemplate(s string)
Command 執行的操做是經過 Command.Run 方法實現的,爲了支持咱們在 Run 方法執行的先後執行一些其它的操做,Command 還提供了額外的幾個方法,它們的執行順序以下:
1. PersistentPreRun
2. PreRun
3. Run
4. PostRun
5. PersistentPostRun
修改 rootCmd 的初始化代碼以下:
var rootCmd = &cobra.Command{ Use: "cobrademo", Short: "sparkdev's cobra demo", Long: "the demo show how to use cobra package", 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("cobra demo program, 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) }, }
從新編譯 cobrademo 程序並執行,輸出結果中能夠看到這些方法的執行順序
D:\Project\GoProject\src\cobrademo>go run main.go Inside rootCmd PersistentPreRun with args: [] Inside rootCmd PreRun with args: [] cobra demo program, with args: [] Inside rootCmd PostRun with args: [] Inside rootCmd PersistentPostRun with args: [] D:\Project\GoProject\src\cobrademo>go run main.go image hello Inside rootCmd PersistentPreRun with args: [hello] image one is win7 image two is win10 image args are : hello Inside rootCmd PersistentPostRun with args: [hello] D:\Project\GoProject\src\cobrademo>
其中的 PersistentPreRun 方法和 PersistentPostRun 方法會伴隨任何子命令的執行:
若是咱們輸入了不正確的命令或者是選項,cobra 還會智能的給出提示,對於這樣的提示咱們也是能夠自定義的,或者若是覺着沒用就直接關閉掉。
參考: