一 背景

在云原生如日中天的当下,相信很多人对Kubernetes/etcd等都有所听闻,当我们看其源码或对其进行二次开发的时候,可以发现其均使用了一个命令行程序库Cobra,其是一个用来编写命令行的神器,提供了一个脚手架,用于快速生成基于Cobra应用程序框架。

其作者是非常有名的spf13,相信大家对vim都有所了解,可以去使用vim的终极终端spf13-vim,可以一键配置,非常的方便,其还有作品viper是一个完整的配置解决方案,支持JSON/YAML/TOML/HCL/envFile等配置文件,还可以热加载,配置保存等,hugo也是其的作品。

我们可以利用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

3.1 安装

Cobra安装非常简单,可以使用go get获取即可,安装完成后,打开GOPATH目录,bin目录下应该有已经编译好的cobra,当然也可以使用源码编译安装。
在使用cobra之前需要了解三个概念,其也是命令行的三部分内容,command、flag和args

  • 命令自身的一些基本信息,用command表示,具体对象是 cobra.Command
  • 命令的一些标致或者选项,用flag表示,具体对象是 flag.FlagSet
  • 最后的参数,用args表示,通常是[]string

对应如下例子:

go get -u test.com/a/b

这里 get 就是commond(这里比较特殊), -u 就是flag, test.com/a/b 就是args

3.2 生成应用程序

$ /Users/xuel/workspace/goworkspace/bin/cobra init --pkg-name smartant-cli
Your Cobra application is ready at
/Users/xuel/workspace/goworkspace/src/github.com/kaliarch/smartant-cli
$ ls
LICENSE cmd     go.mod  go.sum  main.go
$ tree
.
├── LICENSE
├── cmd
│   └── root.go
├── go.mod
├── go.sum
└── main.go1 directory, 5 files

3.3 设计cls程序

在smartant-cli 目录下创建imp目录,器重编写utils.go文件,内入如下

package utilsimport "fmt"func Show(name string, age int) {fmt.Printf("name is %s, age is %d", name, age)
}
  • main.go
package mainimport "github.com/kaliarch/smartant-cli/cmd"func main() {cmd.Execute()
}

可以看出main函数执行cmd包,所以我们只需要在cmd包内调用utils包就能实现smartant-cli程序的需求。接着打开root.go文件查看:

  • root.go
/*
Copyright © 2021 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 athttp://www.apache.org/licenses/LICENSE-2.0Unless 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 cmdimport ("fmt""github.com/spf13/cobra""os"homedir "github.com/mitchellh/go-homedir""github.com/spf13/viper"
)var cfgFile string// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{Use:   "smartant-cli",Short: "SmartAnt linux agent cli",Long: `
smartant-cli is a CLI for SmartAnt applications.
This application is a tool to migrations linux system.`,// 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 and 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/.smartant-cli.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 != "" {// 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 ".smartant-cli" (without extension).viper.AddConfigPath(home)viper.SetConfigName(".smartant-cli")}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这个结构体实现的。为了实现smartant-cli功能,显然我们需要修改RootCmd。修改后的代码如下:

/*
Copyright © 2021 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 athttp://www.apache.org/licenses/LICENSE-2.0Unless 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 cmdimport ("fmt""github.com/spf13/cobra"//"github.com/spf13/viper""github.com/kaliarch/cobra-demo/utils""os"
)var cfgFile string//var name string
//var age int
var command string// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{Use:   "cobra-demo",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) { },Run: func(cmd *cobra.Command, args []string) {//if len(name) == 0 {//    cmd.Help()//    return//}//imp.Show(name, age)if len(command) == 0 {cmd.Help()return}utils.Cmd(command)},
}// Execute adds all child commands to the root command and 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/.smartant-agent.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.PersistentFlags().StringVarP(&name, "name", "n", "", "person name")//rootCmd.PersistentFlags().IntVarP(&age, "age", "a", 0, "person age")rootCmd.PersistentFlags().StringVarP(&command, "command", "o", "", "execute command context")}// initConfig reads in config file and ENV variables if set.
//func initConfig() {//  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-demo" (without extension).
//      viper.AddConfigPath(home)
//      viper.SetConfigName(".cobra-demo")
//  }
//
//  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())
//  }
//}

3.4 执行

# 编译
$ go build -o smartant-cli
$ ./smartant-cli smartant-cli is a CLI for SmartAnt applications.
This application is a tool to migrations linux system.Usage:smartant-cli [flags]Flags:-a, --age int       persons age-h, --help          help for smartant-cli-n, --name string   persons name
$ ./smartant-cli -a 11 -n "xuel"
name is xuel, age is 11%

四 实现带有子命令的clis

在执行cobra.exe init demo之后,继续使用cobra为demo添加子命令test:

4.1 生成sysinfo子命令

$ /Users/xuel/workspace/goworkspace/bin/cobra add sysinfo
sysinfo created at /Users/xuel/workspace/goworkspace/src/github.com/kaliarch/smartant-cli
$ tree
.
├── LICENSE
├── cmd
│   ├── root.go
│   └── sysinfo.go
├── go.mod
├── go.sum
├── main.go
├── smartant-cli
└── utils└── utils.go

4.2 查看子命令

$ go build -o smartant-cli
$ ./smartant-cli smartant-cli is a CLI for SmartAnt applications.
This application is a tool to migrations linux system.Usage:smartant-cli [flags]smartant-cli [command]Available Commands:help        Help about any commandsysinfo     A brief description of your commandFlags:-a, --age int       persons age-h, --help          help for smartant-cli-n, --name string   persons nameUse "smartant-cli [command] --help" for more information about a command.
$ ./smartant-cli sysinfo -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:smartant-cli sysinfo [flags]Flags:-h, --help   help for sysinfo

4.3 编写子命令

  • sysinfo.go
/*
Copyright © 2021 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 athttp://www.apache.org/licenses/LICENSE-2.0Unless 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 cmdimport ("fmt""github.com/kaliarch/smartant-cli/utils""github.com/spf13/cobra"
)var (host, pwd, username stringport                intcommand             string
)// sysinfoCmd represents the sysinfo command
var sysinfoCmd = &cobra.Command{Use:   "sysinfo",Short: "check sys info message",Long: `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.`,Run: func(cmd *cobra.Command, args []string) {if len(host) == 0 || len(pwd) == 0 {cmd.Help()return}fmt.Println("sysinfo called")utils.Sysinfo(host, pwd, username, port, command)fmt.Println("sysinfo called commpled")},
}func init() {rootCmd.AddCommand(sysinfoCmd)// Here you will define your flags and configuration settings.// Cobra supports Persistent Flags which will work for this command// and all subcommands, e.g.:// sysinfoCmd.PersistentFlags().String("foo", "", "A help for foo")// Cobra supports local flags which will only run when this command// is called directly, e.g.:// sysinfoCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")sysinfoCmd.Flags().StringVarP(&host, "host", "i", "", "host ip addr")sysinfoCmd.Flags().StringVarP(&username, "username", "u", "", "host username")sysinfoCmd.Flags().StringVarP(&command, "command", "c", "", "command")sysinfoCmd.Flags().StringVarP(&pwd, "pwd", "p", "", "host password")sysinfoCmd.Flags().IntVarP(&port, "port", "P", 0, "host port")
}
  • utils.go
package utilsimport ("bytes""fmt""golang.org/x/crypto/ssh""net""strings"//"strconv""log"
)// smartant-cli
func Show(name string, age int) {fmt.Printf("name is %s, age is %d", name, age)
}func sshConnect(user, pwd, host string, port int) (*ssh.Session, error) {var (auth         []ssh.AuthMethodaddr         stringclientConfig *ssh.ClientConfigclient       *ssh.Clientsession      *ssh.Sessionerr          error)// get auth methodauth = make([]ssh.AuthMethod, 0)auth = append(auth, ssh.Password(pwd))// host key callbkhostKeyCallbk := func(host string, remote net.Addr, key ssh.PublicKey) error {return nil}clientConfig = &ssh.ClientConfig{User:            user,Auth:            auth,HostKeyCallback: hostKeyCallbk,BannerCallback:  nil,//ClientVersion:     "",//HostKeyAlgorithms: nil,//Timeout: 10000000,}// connet to sshaddr = fmt.Sprintf("%s:%d", host, port)if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {return nil, err}// create sessionif session, err = client.NewSession(); err != nil {return nil, err}return session, nil
}func Sysinfo(host, pwd, username string, port int, cmd string) {var stdOut, stdErr bytes.Buffer// 使用用户名,密码登陆session, err := sshConnect(username, pwd, host, port)if err != nil {log.Fatal(err)}defer session.Close()session.Stdout = &stdOutsession.Stderr = &stdErrsession.Run(cmd)fmt.Println(strings.Replace(stdOut.String(), "\n", " ", -1))
}
  • 执行测试
$ ./smartant-cli sysinfo
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:smartant-cli sysinfo [flags]Flags:-c, --command string    command-h, --help              help for sysinfo-i, --host string       host ip addr-P, --port int          host port-p, --pwd string        host password-u, --username string   host username$ ./smartant-cli sysinfo -i 121.3.10.55 -u root -P 22 -p xxxxxxx -c "cat /etc/hosts"
sysinfo called
::1     localhost       localhost.localdomain   localhost6      localhost6.localdomain6  127.0.0.1      localhost       localhost.localdomain   localhost4      localhost4.localdomain4 127.0.0.1   localhost        localhost 127.0.0.1     hw-server       hw-server
sysinfo called commpled

五 其他

Cobra非常强大,能够帮助我们快速创建命令行工具,但是如果直接仅仅写一个非常简单的命令行工具,flag选项非常少,golang built-in的flag库够了。当然使用看个人选择,Cobra更适合复杂的命令行工具。

golang/云原生/Docker/DevOps/K8S/持续集成/分布式/etcd/ipfs 学习群:960994558

Golang 开发之Cobra初探相关推荐

  1. 问题 | golang开发之go.mod的使用方法

    文章目录 go mod之坑 背景 项目 mod实战 主程序调用同目录里面的包 主程序调用其他目录的包 重要提醒 问答FAQs 1. 有些包由于特定网络原因无法访问怎么办? 2. 公司通过 gitlab ...

  2. android 监听安装来源_Flutter插件开发之APK自动安装

    点击上方的终端研发部,右上角选择"设为星标" 每日早9点半,技术文章准时送上 公众号后台回复"学习",获取作者独家秘制精品资料 往期文章 记五月的一个Andro ...

  3. android中oncreate方法,android开发之onCreate( )方法详解

    这里我们只关注一句话:This is where you should do all of your normal static set up.其中我们只关注normal static, normal ...

  4. WEB开发之HTML与CSS够用即可-庞永旺-专题视频课程

    WEB开发之HTML与CSS够用即可-113人已学习 课程介绍         讲解常用的HTML标签与CSS样式.这些常用的HTML标签与CSS样式都是本人多年从业经验的总结.只要熟练我总结的HTM ...

  5. Python开发之pandas行和列的获取

    Python开发之pandas行和列的获取 0 1. 行和列的获取 1.1 根据索引获取行 1.2 根据条件获取行 1.3 获取列 2 区域选取 2.1 df.loc[] 2.1.1 行选取 2.1. ...

  6. 镜像处理坐标 android,Android应用开发之Android重写ImageView实现图片镜像效果的代码教程...

    本文将带你了解Android应用开发之Android重写ImageView实现图片镜像效果的代码教程,希望本文对大家学Android有所帮助. 前两天朋友问我一个问题,如何实现从手机系统相册加载一张图 ...

  7. iOS开发之AVKit框架使用

    2019独角兽企业重金招聘Python工程师标准>>> iOS开发之AVKit框架使用 一.引言 在iOS开发框架中,AVKit是一个非常上层,偏应用的框架,它是基于AVFounda ...

  8. Android NDK开发之旅31 FFmpeg音频解码

    ###前言 #####基于Android NDK开发之旅30--FFmpeg视频播放这篇文章,我们已经学会视频解码基本过程.这篇文章就对音频解码进行分析. #####音频解码和视频解码的套路基本是一样 ...

  9. android 监听物理返回键,Android应用开发之react-native 监听Android物理返回键

    本文将带你了解Android应用开发之react-native 监听Android物理返回键,希望本文对大家学Android有所帮助. 1. componentWillMount(){         ...

最新文章

  1. 多线程真的会使用CPU所有的内核吗?
  2. java 算法练习题
  3. linux后台运行python脚本
  4. 《UML大战需求分析》阅读笔记01
  5. 《IBM-PC汇编语言程序设计》(第2版)【沈美明 温冬婵】——自编解析与答案
  6. 机器学习和数据科学领域必读的10本免费书籍
  7. Python实现二叉搜索树
  8. Pentium的指令系统(4)——串操作指令
  9. 从鲁班造木鸢到智能控制,图解世界无人机发展简史
  10. 股票历史数据下载接口汇总(动态更新)
  11. 菜鸟安装linux虚拟机
  12. 小米mix2安兔兔html5跑分,小米MIX 2S跑分多少?高通骁龙845安兔兔跑分实测 (全文)...
  13. 金士顿DT100 G3 PS2251-07海力士U盘量产修复成功教程
  14. 为什么提问能力很重要?
  15. 数据结构:选择类型排序的总结(考研)
  16. 2021年2月28日【Jiawei_Z】Ethercat的整个实现过程(举例:Lan9252)
  17. 10年回顾:世界各地开发高手谈Java
  18. 写字机结构---coreXY结构
  19. python爬虫利用线程池下载视频
  20. 还在死守TCP吗,来看看即将成为HTTP3.0标准协议的QUIC

热门文章

  1. android 版本更新原理,蒲公英 - 文档中心 - SDK 自动更新机制
  2. 吹响重型战争号角:美国的基建支持计划会带动技术升级吗?
  3. MIME类型 swfupload 及 php
  4. ZeroClipboard2跨浏览器复制粘贴
  5. 数字图像处理Matlab
  6. SecureCRT通过SSH服务登录ubuntu出错:Password authentication failed, Please verify that the username and passw
  7. java常见编程练习hw二(中等难度)
  8. 怎么在Linux下执行sql文件
  9. 了解Windows WDDM 驱动程序
  10. 【数据结构与算法】填空练习题