概述
Cobra 是一个用来创建 CLI 命令行的 golang 库,也可以用来生成以Cobra为基础的应用和命令文件。被广泛使用在各种Go的项目中,比如Kubernetes,Docker。
概念
有这样两条命令,下面以它为参考,解释cobra的几个概念。
hugo server --port=1313
git clone URL --bare
Commands
Command 是程序的中心点,不同Commands有不同行为,一个命令可能有多个子命令。示例中server
就是命令。
Flags
Flags 用来改变命令的行为,比如port
就是Flag。假设命令的flag为version
, 使用方式:--version
,也可以配置短别名:-V
。详见GNU extensions to the POSIX recommendations for command-line options
示例
工程结构
-- netrq
|-- cmd
| |-- http.go
| |-- root.go
| `-- version.go
|-- config.json
|-- main.go
`-- pkg
`-- request.go
Create rootCmd
netrq/cmd/root.go
package cmd
import (
"github.com/spf13/cobra"
"fmt"
"os"
"github.com/spf13/viper"
"github.com/mitchellh/go-homedir"
"github.com/fsnotify/fsnotify"
)
var cfgFile string
var testPersistentFlag,testLocalFlag,author string
var rootCmd = &cobra.Command{
Use: "netrq",
Short: "This tool for network request",
Long: `This tool for network request,
Complete documentation is available at http://document.netrq.com `,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(args)
author := viper.GetString("author")
if len(author) > 0 {
fmt.Println("author: ", author)
} else {
cmd.Help()
}
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
// persistent Flag: 对本命令和所有子命令都有效,Global Flags:
rootCmd.PersistentFlags().StringVarP(&testPersistentFlag, "tpFlag", "p", "", "persistent flag")
rootCmd.PersistentFlags().StringVarP(&author, "author","a", "","Author name for copyright attribution")
// local flag: 本地flag,对当前命令有效
rootCmd.Flags().StringVarP(&testPersistentFlag, "tlFlag", "l", "", "local flag")
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
}
func initConfig() {
if cfgFile != "" {
viper.SetConfigName(cfgFile)
} else {
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// home目录和当前目录查找配置文件
viper.AddConfigPath(home)
viper.AddConfigPath(".")
// 注意,我在Windows上,不需要加扩展名
viper.SetConfigName("config")
// 监听文件变化
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
})
}
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can not read config:", viper.ConfigFileUsed(),err)
}
}
rootCmd
: 根命令,是整个应用命令的入口,通过在main
函数中调用rootCmd.Execute()
启动;
- Use: 命令
- Short: 命令的简短描述
- Long: 命令的详细描述
- Run: 命令执行入口
函数initConfig()
: 用来初始化viper配置文件位置,监听变化
函数init()
: 定义flag和配置处理
rootCmd.PersistentFlags().StringVarP(&author, "author","a", "","Author name for copyright attribution")
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
把viper配置项author和flag绑定,也就是说,&author变量的值会从配置文件中读取,如果命令有flag--author
,变量将使用此flag的值:
Create your main.go
文件netrq/main.go
import (
"netrq/cmd"
)
func main() {
cmd.Execute();
}
有这俩文件,可以编译执行:
cd netrq
go build .
./netrq -h #将列出可用命令和flag
Create additional commands
我希望执行netrq version
时输出 version : 1.0.0
,也就是给netrq添加一个子命令,输出版本号;
netrq/cmd/version.go
package cmd
import "github.com/spf13/cobra"
func init() {
// versionCmd作为rootCmd的子命令
rootCmd.AddCommand(versionCmd)
}
const version string = "1.0.0"
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the netrq version number",
Run: func(cmd *cobra.Command, args []string) {
println("version : ", version)
},
}
同样,也可以添加一个http的子命令,用来发起http请求;
netrq/cmd/http.go
package cmd
import (
"github.com/spf13/cobra"
"netrq/pkg"
)
var url,method string
var httpCmd = &cobra.Command{
Use: "http",
Short: "Short desc: invoke http request",
Long: `Long description: invoke http request
http [flags]
`,
Run: func(cmd *cobra.Command, args []string) {
if len(url) == 0 {
cmd.Help()
return
}
pkg.HttpRequest(url, method)
},
}
func init() {
httpCmd.Flags().StringVarP(&url, "url", "U", "", "http url")
// required
httpCmd.MarkFlagRequired("url")
httpCmd.Flags().StringVarP(&method, "method", "X", "GET", "http method")
// add
rootCmd.AddCommand(httpCmd)
}
netrq/pkg/request.go
package pkg
import (
"net/http"
"log"
"io/ioutil"
"fmt"
)
func HttpRequest(url string, method string) {
client := &http.Client{}
req, err := http.NewRequest(method, url, nil)
if err != nil {
log.Println(err)
return
}
//req.Header.Set("Content-Type", "application/json; charset=UTF-8")
resp, err := client.Do(req)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return
}
fmt.Println(string(body))
}
测试:
$ netrq http -X GET -U https://api.github.com/users/ThoreauZZ
{"login":"ThoreauZZ","id":10337273,"avatar_url":"https://avatars1.githubusercontent.com/u/10337273?v=4","gravatar_id":"","url":"https://api.github.com/users/ThoreauZZ
","html_url":"https://github.com/ThoreauZZ","followers_url":"https://api.github.com/users/ThoreauZZ/followers","following_url":"https://api.github.com/users/ThoreauZZ
/following{/other_user}","gists_url":"https://api.github.com/users/ThoreauZZ/gists{/gist_id}","starred_url":"https://api.github.com/users/ThoreauZZ/starred{/owner}{/r
epo}","subscriptions_url":"https://api.github.com/users/ThoreauZZ/subscriptions","organizations_url":"https://api.github.com/users/ThoreauZZ/orgs","repos_url":"https:
//api.github.com/users/ThoreauZZ/repos","events_url":"https://api.github.com/users/ThoreauZZ/events{/privacy}","received_events_url":"https://api.github.com/users/Tho
reauZZ/received_events","type":"User","site_admin":false,"name":"thoreau","company":null,"blog":"","location":null,"email":null,"hireable":null,"bio":null,"public_rep
os":30,"public_gists":0,"followers":10,"following":4,"created_at":"2014-12-29T08:15:41Z","updated_at":"2018-03-05T09:27:29Z"}
$ netrq http -X POST -U https://api.github.com/users/ThoreauZZ
{"message":"Not Found","documentation_url":"https://developer.github.com/v3"}
Cobra Generator
cobra除了作为一个库,还是一个生成工具.
安装
go get github.com/spf13/cobra/cobra
使用
# 生成项目init
cobra init github.com/ThoreauZZ/newApp
cd newApp/
# 添加命令add
cobra add server
cobra add config
# 自动生成的文件
tree
|-- LICENSE
|-- cmd
| |-- config.go
| |-- root.go
| `-- serve.go
`-- main.go