COBRA既是一个用来创建强大的现代CLI命令行的GOLANG库,也是一个生成程序应用和命令行文件的程序
git repo
- https://github.com/spf13/cobra
示例
Cobra提供的功能
- 简易的子命令行模式,如 app server, app fetch等等
- 完全兼容posix命令行模式
- 嵌套子命令subcommand
- 支持全局,局部,串联flags
- 使用Cobra很容易的生成应用程序和命令,使用cobra create appname和cobra add cmdname
- 如果命令输入错误,将提供智能建议,如 app srver,将提示srver没有,是否是app server
- 自动生成commands和flags的帮助信息
- 自动生成详细的help信息,如app help
- 自动识别-h,–help帮助flag
- 自动生成应用程序在bash下命令自动完成功能
- 自动生成应用程序的man手册
- 命令行别名
- 自定义help和usage信息
- 可选的紧密集成的viper apps
如何使用
安装cobra
go get -v github.com/spf13/cobra/cobra
在安装的过程中,由于GWF(长城防火墙)的原因,golang的资源无法访问
- 解决的思路:git clone 源代码,在GOPATH的src目录中建立相关目录,将clone的源码拷贝进去
- 注意:目录的名称会有变化
- 举例如下:
- 直接找到github上的源码地址,Git clone https://github.com/go-yaml/yaml.git
- 在src 目录下 创建 gopkg.in 目录 把yaml 重命名为yaml.v2
little example
package main
import (
"fmt"
"github.com/spf13/cobra"
)
func main() {
var name string
var food string
var myFood string
// 1. 主命令
var rootCmd = &cobra.Command{
Use: "personLikeEat",
Short: "Input the chinese name and food name",
//命令执行的函数
Run: func(cmd *cobra.Command, args []string) {
if len(name) == 0 {
cmd.Help()
return
}
if len(food) == 0 {
cmd.Help()
return
}
fmt.Printf("%s like eat %s.\n", name, food)
},
}
// 2. 子命令
var subCmd = &cobra.Command{
Use: "ILikeEat",
Short: "Input food information",
//命令执行的函数
Run: func(cmd *cobra.Command, args []string) {
if len(myFood) == 0 {
cmd.Help()
return
}
fmt.Printf("I like eat %s.\n", myFood)
},
}
// 添加子命令
rootCmd.AddCommand(subCmd)
// 3.1 主命令添加选项
rootCmd.Flags().StringVarP(&name, "name", "n", "", "person's name")
rootCmd.Flags().StringVarP(&food, "food", "f", "", "food's name")
// 3.2 子命令添加选项
subCmd.Flags().StringVarP(&myFood, "food", "f", "", "food's name")
// 执行命令
rootCmd.Execute()
}
运行结果如下:
E:\mygo\src\test\demo\personLikeEat>personLikeEat
Input the chinese name and food name
Usage:
personLikeEat [flags]
personLikeEat [command]
Available Commands:
ILikeEat Input food information
Flags:
-f, --food string food's name
-n, --name string person's name
Use "personLikeEat [command] --help" for more information about a command.
E:\mygo\src\test\demo\personLikeEat>personLikeEat -n yp -f apple
yp like eat apple.
E:\mygo\src\test\demo\personLikeEat>personLikeEat ILikeEat
Input food information
Usage:
personLikeEat ILikeEat [flags]
Flags:
-f, --food string food's name
E:\mygo\src\test\demo\personLikeEat>personLikeEat ILikeEat -f banana
I like eat banana.
基本用法就是这四步:
- 主命令
- 子命令
- 添加选项
- 执行命令
使用cobra生成应用程序
假设现在我们要开发一个基于CLIs的命令程序,名字为cobraDemo。首先打开CMD,切换到GOPATH的src目录下,执行如下指令:
E:\mygo\src>..\bin\cobra.exe init cobraDemo
Your Cobra application is ready at
E:\mygo\src\cobraDemo
Give it a try by going there and running `go run main.go`
Add commands to it by running `cobra add [cmdname]`
在src目录下会生成一个cobraDemo的文件夹,如下:
cobraDemo
│ LICENSE
│ main.go
│
└─cmd
root.go
如果你的cobraDemo程序没有subcommands,那么cobra生成应用程序的操作就结束了。
如何实现没有子命令的CLIs程序
接下来就是可以继续cobraDemo的功能设计了。例如我在demo下面新建一个包,名称为imp。如下:
cobraDemo
│ LICENSE
│ main.go
│
├─cmd
│ root.go
│
└─imp
imp.go
imp.go文件的代码如下:
package imp
import(
"fmt"
)
func Show(name string, age int) {
fmt.Printf("My Name is %s, My age is %d\n", name, age)
}
cobraDemo程序成命令行接收两个参数name和age,然后打印出来。打开cobra自动生成的main.go文件查看:
// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import "cobraDemo/cmd"
func main() {
cmd.Execute()
}
可以看出main函数执行cmd包,所以我们只需要在cmd包内调用imp包就能实现demo程序的需求。接着打开root.go文件查看:
// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "cobraDemo",
Short: "A brief description of your application",
Long: `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.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}
// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags, which, if defined here,
// will be global for your application.
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobraDemo.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" { // enable ability to specify config file via flag
viper.SetConfigFile(cfgFile)
}
viper.SetConfigName(".cobraDemo") // name of config file (without extension)
viper.AddConfigPath("$HOME") // adding home directory as first search path
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
从源代码来看cmd包进行了一些初始化操作并提供了Execute接口。十分简单,其中viper是cobra集成的配置文件读取的库,这里不需要使用,我们可以注释掉(不注释可能生成的应用程序很大约10M,这里没用到最好是注释掉)。cobra的所有命令都是通过cobra.Command这个结构体实现的。为了实现demo功能,显然我们需要修改RootCmd。修改后的代码如下:
// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
// "github.com/spf13/viper"
"cobraDemo/imp"
)
// var cfgFile string
var name string
var age int
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "cobraDemo",
Short: "A test demo",
Long: `Demo is a test appcation for print things`,
// Uncomment the following line if your bare application
// has an action associated with it:
Run: func(cmd *cobra.Command, args []string) {
if len(name) == 0 {
cmd.Help()
return
}
imp.Show(name, age)
},
}
// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
func init() {
// cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags, which, if defined here,
// will be global for your application.
// RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobraDemo.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
// RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
RootCmd.Flags().StringVarP(&name, "name", "n", "", "person's name")
RootCmd.Flags().IntVarP(&age, "age", "a", 0, "person's age")
}
// initConfig reads in config file and ENV variables if set.
// func initConfig() {
// if cfgFile != "" { // enable ability to specify config file via flag
// viper.SetConfigFile(cfgFile)
// }
// viper.SetConfigName(".cobraDemo") // name of config file (without extension)
// viper.AddConfigPath("$HOME") // adding home directory as first search path
// viper.AutomaticEnv() // read in environment variables that match
// // If a config file is found, read it in.
// if err := viper.ReadInConfig(); err == nil {
// fmt.Println("Using config file:", viper.ConfigFileUsed())
// }
//}
到此demo的功能已经实现了,我们编译运行一下看看实际效果:
E:\mygo\src\cobraDemo>go build
E:\mygo\src\cobraDemo>cobraDemo.exe
Demo is a test appcation for print things
Usage:
cobraDemo [flags]
Flags:
-a, --age int person's age
-n, --name string person's name
E:\mygo\src\cobraDemo>cobraDemo.exe -n yp -a 26
My Name is yp, My age is 26
如何实现带有子命令的CLIs程序
在执行cobra.exe init demo之后,继续使用cobra为demo添加子命令test:
E:\mygo\src\cobraDemo>..\..\bin\cobra add test
test created at E:\mygo\src\cobraDemo\cmd\test.go
在src目录下demo的文件夹下生成了一个cmd\test.go文件,如下:
cobraDemo
│ cobraDemo.exe
│ LICENSE
│ main.go
│
├─cmd
│ root.go
│ test.go
│
└─imp
imp.go
接下来的操作就和上面修改root.go文件一样去配置test子命令。效果如下:
E:\mygo\src\cobraDemo>go build
E:\mygo\src\cobraDemo>cobraDemo.exe
Demo is a test appcation for print things
Usage:
cobraDemo [flags]
cobraDemo [command]
Available Commands:
test A brief description of your command
Flags:
-a, --age int person's age
-n, --name string person's name
Use "cobraDemo [command] --help" for more information about a command.
可以看出demo既支持直接使用标记flag,又能使用子命令
E:\mygo\src\cobraDemo>cobraDemo.exe test -h
A longer description that spans multiple lines and likely contains examples
and usage of using your command. 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 test [flags]
调用test命令输出信息,这里没有对默认信息进行修改。
E:\mygo\src\cobraDemo>cobraDemo.exe tet
Error: unknown command "tet" for "cobraDemo"
Did you mean this?
test
Run 'cobraDemo --help' for usage.
unknown command "tet" for "cobraDemo"
Did you mean this?
test
这是错误命令提示功能
函数解析
函数说明
关于代码执行顺序
// The *Run functions are executed in the following order:
// * PersistentPreRun()
// * PreRun()
// * Run()
// * PostRun()
// * PersistentPostRun()
修改root.go文件如下:
// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
// "github.com/spf13/viper"
"cobraDemo/imp"
)
// var cfgFile string
var name string
var age int
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "cobraDemo",
Short: "A test demo",
Long: `Demo is a test appcation for print things`,
// Uncomment the following line if your bare application
// has an action associated with it:
// The *Run functions are executed in the following order:
// * PersistentPreRun()
// * PreRun()
// * Run()
// * PostRun()
// * PersistentPostRun()
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) {
if len(name) == 0 {
cmd.Help()
return
}
imp.Show(name, age)
},
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)
},
}
// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
func init() {
// cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags, which, if defined here,
// will be global for your application.
// RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobraDemo.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
// RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
RootCmd.Flags().StringVarP(&name, "name", "n", "", "person's name")
RootCmd.Flags().IntVarP(&age, "age", "a", 0, "person's age")
}
测试结果如下:
E:\mygo\src\cobraDemo>go build
E:\mygo\src\cobraDemo>cobraDemo.exe
Inside rootCmd PersistentPreRun with args: []
Inside rootCmd PreRun with args: []
Demo is a test appcation for print things
Usage:
cobraDemo [flags]
cobraDemo [command]
Available Commands:
test A brief description of your command
Flags:
-a, --age int person's age
-n, --name string person's name
Use "cobraDemo [command] --help" for more information about a command.
Inside rootCmd PostRun with args: []
Inside rootCmd PersistentPostRun with args: []
E:\mygo\src\cobraDemo>cobraDemo.exe -n yp -a 26
Inside rootCmd PersistentPreRun with args: []
Inside rootCmd PreRun with args: []
My Name is yp, My age is 26
Inside rootCmd PostRun with args: []
Inside rootCmd PersistentPostRun with args: []
E:\mygo\src\cobraDemo>cobraDemo.exe test
Inside rootCmd PersistentPreRun with args: []
test called
Inside rootCmd PersistentPostRun with args: []
当使用–help命令的时候,PersistentPreRun、PreRun、PostRun、PersistentPostRun不会被调用 示例如下:
E:\mygo\src\cobraDemo>cobraDemo.exe --help
Demo is a test appcation for print things
Usage:
cobraDemo [flags]
cobraDemo [command]
Available Commands:
test A brief description of your command
Flags:
-a, --age int person's age
-n, --name string person's name
Use "cobraDemo [command] --help" for more information about a command.
“数据类型” + “P”
此种类型支持短标记
// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool {
p := new(bool)
f.BoolVarP(p, name, shorthand, value, usage)
return p
}
“数据类型” + “Var”
此种类型表示变量
// BoolVar defines a bool flag with specified name, default value, and usage string.
// The argument p points to a bool variable in which to store the value of the flag.
func BoolVar(p *bool, name string, value bool, usage string) {
BoolVarP(p, name, "", value, usage)
}
全局短标记过时
RootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
RootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
示例如下:
E:\mygo\src\cobraDemo>cobraDemo.exe -h
Flag shorthand -h has been deprecated, please use --help
Demo is a test appcation for print things
Usage:
cobraDemo [flags]
cobraDemo [command]
Available Commands:
test A brief description of your command
Flags:
-a, --age int person's age
--help Print usage
-n, --name string person's name
Use "cobraDemo [command] --help" for more information about a command.
E:\mygo\src\cobraDemo>cobraDemo.exe test -h
Flag shorthand -h has been deprecated, please use --help
A longer description that spans multiple lines and likely contains examples
and usage of using your command. 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 test [flags]
Global Flags:
--help Print usage
文档信息
- 本文作者:Yu Peng
- 本文链接:https://www.y2p.cc/2017/02/17/cobra/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)