教你用Cobra开发类似docker的命令行
前言
Cobra是一个强大的用来构建命令行程序的库,许多流行的Go项目都是用它来构建的,比如Kubernetes、Docker、etcd、Istio、Github CLI等等。
接下来,演示开发一个我们自己的命令行程序chenqionghe,模仿一下docker命令行,预期功能如下
# 查看帮助
chenqionghe -h
# 查看版本,类似docker version
chenqionghe version
# 查看hello命令帮助,类似docker ps -h
chenqionghe hello -h
# 使用hello命令,类似docker run --name app --volume /app/data
chenqionghe hello --name light-weight-baby --author gym
Cobra基于三个基本概念
- commands(行为)
- arguments(位置参数)
- flags(命令行选项)
使用基本模式是APPNAME VERB NOUN --ADJECTIVE或APPNAME COMMAND ARG --FLAG,例如
# server是一个command,--port=1313是一个命令行选项
hugo server --port=1313
# clone 是 commands,URL 是 arguments,brae是命令行选项
git clone URL --bare
一、安装
go get -u github.com/spf13/cobra/cobra
go install github.com/spf13/cobra/cobra
二、初始化应用
初始化项目
这里我的应用名叫chenqionghe
go mod init chenqionghe
创建入口文件cmd/root.go
创建文件夹cmd,并创建文件cmd/root.go,这是用来放所有的命令的基本文件
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"os"
)
var rootCmd = &cobra.Command{
Use: "chenqionghe",
Short: "getting muscle is not easy",
Long: `let's do it, yeah buddy light weight baby!`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("hello chenqionghe")
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
创建主程序main.go
package main
import "chenqionghe/cmd"
func main() {
cmd.Execute()
}
运行一下main.go可以看到生效了
三、如何自定义命令
创建hello子命令
cobra add hello
会在cmd下生成一个hello.cmd的命令,生成的命令是长下面这样的,核心是调用了AddCommand方法
我们把没用的信息干掉,精简后如下
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var helloCmd = &cobra.Command{
Use: "hello",
Short: "hello命令简介",
Long: `hello命令详细介绍`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("hello called")
},
TraverseChildren: true,
}
func init() {
rootCmd.AddCommand(helloCmd)
}
直接运行看看
go run main.go hello
创建version子命令
同理,我们再创建一个version命令
cobra add version
修改一下Run方法
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("chenqionghe version v0.0.1")
},
运行如下
四、如何设置flag选项
flag选项按作用范围分为persistent和local两类
全局选项
persistent是全局选项,对应的方法为PersistentFlags,可以分配给命令和命令下的所有子命令,上面的rootCmd和helloCmd都是可以调用flag
例如,添加一个-v选项
func init() {
var Verbose bool
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "全局版本")
}
运行,可以看到生效了
本地选项
local为本地选项,对应方法为Flags,只对指定的Command生效,我们往hello命令的init里边添加一个本地flag
func init() {
rootCmd.AddCommand(helloCmd)
//本地flag
var Source string
helloCmd.Flags().StringVarP(&Source, "source", "s", "", "读取文件路径")
}
运行如下
设置必填
我们在init函数添加以下代码
rootCmd.Flags().StringVarP(&Name, "name", "n", "", "你的名字")
rootCmd.MarkFlagRequired("name")
运行如下,必须填写name参数才可以运行
绑定配置
添加一个initConfig方法
func initConfig() {
viper.AddConfigPath("./")
viper.AddConfigPath("./conf")
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
}
在init中调用
cobra.OnInitialize(initConfig) //这会在运行每个子命令之前运行
rootCmd.PersistentFlags().StringVar(&Author, "author", "defaultAuthor", "作者名")
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
这将把viper配置和flag绑定,如果用户不设置-author选项,将从配置中查找
五、如何设置arguments
cobra默认提供了一些验证方法
- NoArgs: 如果包含任何位置参数,命令报错
- ArbitraryArgs: 命令接受任何参数
- OnlyValidArgs: 如果有位置参数不在ValidArgs中,命令报错
- MinimumArgs(init): 如果参数数目少于N个后,命令行报错
- MaximumArgs(init): 如果参数数目多于N个后,命令行报错
- ExactArgs(init): 如果参数数目不是N个话,命令行报错
- RangeArgs(min, max): 如果参数数目不在范围(min, max)中,命令行报错
使用示例
往Command中添加参数Args,我们规定参数不能少于5个,如下
var rootCmd = &cobra.Command{
Use: "chenqionghe",
Short: "getting muscle is not easy",
Long: `let's do it, yeah buddy light weight baby!`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("hello chenqionghe")
},
Args: cobra.MinimumNArgs(5),
}
运行输出
六、如何使用参数
我们可以看到核心的方法,其实就是cobra.Command中的Run参数,指定了func(cmd *cobra.Command, args []string)类型的回调
代表我们可以直接使用cmd和args来编写我们的程序
获取flag参数
我们可以直接使用cmd的flag方法获取传递的flag
var helloCmd = &cobra.Command{
Use: "hello",
Short: "hello命令简介",
Long: `hello命令详细介绍`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(cmd.Flag("author").Value)
fmt.Println(cmd.Flag("name").Value)
},
}
运行如下
获取args参数
var helloCmd = &cobra.Command{
Use: "hello",
Short: "hello命令简介",
Long: `hello命令详细介绍`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(args)
},
TraverseChildren: true,
}
调用如下,可以看到已经取出了所有的args参数
七、如何设置钩子
cobra提供了很多钩子方法,可按运行顺序排列如下
- PersistentPreRun
- PreRun
- Run
- PostRun
- PersistentPostRun
使用示例
var helloCmd = &cobra.Command{
Use: "hello",
Short: "hello命令简介",
Long: `hello命令详细介绍`,
//Args: cobra.MinimumNArgs(1),
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("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)
},
}
运行如下
总结
到这里,我们就已经学会了如果设置子命令、flag参数、arguments参数以及编写方法使用这些参数,
还有最后一步,就是编译出我们的二进制程序,验证一下我们之前的需求
- 编译
go build -o chenqionghe
如下,已经生成二进制文件chenqionghe
- 运行命令
./chenqionghe -h # 查看帮助
./chenqionghe version # 查看版本,类似docker version
./chenqionghe hello -h # 查看hello命令帮助,类似docker ps -h
./chenqionghe hello --name light-weight-baby --author gym # 使用hello命令,类似docker run --name app --volume /app/data
可以看到,完美的实现了预期需求,就是这么简单,light weight baby!
教你用Cobra开发类似docker的命令行的更多相关文章
- [编译] 6、开源两个简单且有用的安卓APP命令行开发工具和nRF51822命令行开发工具
星期四, 27. 九月 2018 12:00上午 - BEAUTIFULZZZZ 一.前言 前几天给大家介绍了如何手动搭建安卓APP命令行开发环境和nRF51822命令行开发环境,中秋这几天我把上面篇 ...
- Docker Kubernetes 命令行创建容器
Docker Kubernetes 命令行创建容器 环境: 系统:Centos 7.4 x64 Docker版本:18.09.0 Kubernetes版本:v1.8 管理节点:192.168.1.79 ...
- 【Windows10 IoT开发系列】Powershell命令行实用程序
原文:[Windows10 IoT开发系列]Powershell命令行实用程序 更新帐户密码: 强烈建议你更新默认的管理员帐户密码.若要更新帐户密码,你可以发出以下命令: net user Admin ...
- Docker常用命令行
原文出处:https://blog.csdn.net/qq_29303759/article/details/87639016 启动docker 启动docker systemctl start do ...
- 【Howie玩docker】-命令行只显示-bash-4.1#
灵雀云上面用docker建了个centOS的实例,首个免费,正好当云主机来玩. 但是,打开有个问题,命令行不显示当前用户和路径. 只显示: -bash-4.1# 简单,配置文件不全而已. 下面对其重新 ...
- docker常用命令行集锦
对工作中用到的docker命令行进行一个汇总,方便以后的命令行查询,同时也为了加强记忆,会把工作中用到的命令,持续更新上 1.查看私有仓库都有哪些镜像 curl -X GET http://10.27 ...
- golang开发:类库篇(三)命令行工具cli的使用
为什么要使用命令行 觉得这个问题不应该列出来,又觉得如果初次进行WEB开发的话,可能会觉得所有的东西都可以使用API去做,会觉得命令行没有必要. 其实,一个生产的项目命令行是绕不过去的.比如运营需要导 ...
- docker mac 命令行登录报错处理 : Error saving credentials: error storing credentials - err: exit status 1
参考:https://blog.csdn.net/xufwind/article/details/88756557 比较新版本的docker命令行登录会出现以下错误: Error saving cre ...
- kubectl&docker容器命令行窗口太小
#k8s kubectl exec -ti busybox env COLUMNS=$COLUMNS LINES=$LINES bash #k8s example kubectl exec -t ...
随机推荐
- 【django】 接收所有文件,前端展示文件(包括视频,文件,图片)ajax请求
如果是后台上传文件: setting配置: STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ...
- Simple: 一个支持中文和拼音搜索的 sqlite fts5插件
之前的工作关系,需要在手机上支持中文和拼音搜索.由于手机上存储数据一般都是用 sqlite,所以是基于 sqlite3 fts5 来实现.这段时间再次入门 c++,所以想用 c++ 实现一下,一来用于 ...
- python打包py为exe程序:PyInstaller
打包库:PyInstaller python程序编写过程中的脚本文件为py格式的文件,当我们想将编写好的程序移植到其他机器上给其他人使用时,如果目标机器没有安装python环境,py文件将无法运行,而 ...
- iOS围绕某点缩放或旋转的AnchorPoint的设定
经常会遇到需求,要求手势的缩放或者旋转操作,要求动作变化围绕某一个特定点,或者是两指的中心点,或者是某一个点. 这个问题首先要清晰的知道,iOS各个view的层次关系.特别是,要清除的知道,当前vie ...
- form里面文件上传并预览
其实form里面是不能嵌套form的,如果form里面有图片上传和其他input框,我们希望上传图片并预览图片,然后将其他input框填写完毕,再提交整个表单的话,有两种方式! 方式一:点击上传按钮的 ...
- js中排序方法
有些代码一两个月都会忘了,有空多做下总结,记录下来,等需要用到的时候可以来翻翻总结的博客.写技术博客,对自己是一种总结,对别人,是一种参考. 1.sort()方法 var ar1=[2,4,6,8,1 ...
- Python只有文件不存在才能写文件
当我们在Python里面写文件时,我们常用的模式为 w模式,这种模式下,如果文件不存在,就会生成文件:如果文件已经存在,就会直接覆盖. 有时候,如果文件已经存在,直接覆盖文件可能会导致重要数据丢失.你 ...
- 5.创建app、创建user表、配置media、数据迁移
目录 user模块User表 创建user模块 创建User表对应的model:user/models.py 注册user模块,配置User表:dev.py 配置media 数据库迁移 user模块U ...
- 教你如何利用threejs对3D模型皮肤进行DIY
一步一步教你如何利用threejs加载gltf模型来实现DIY换肤功能. 模型准备 模型制作 模型可以通过网上下载,也可以自己通过c4d.maya.blender等模型制作软件得到.这里就不叙述有关模 ...
- Python-标准模块与第三方模块
标准模块 python官方自己的模块 os os与os.path os.chdir('desktop') 跳转至指定目录 os.listdir() ...