手把手教你开发docker一样的命令行

目录

前言

Cobra是一个壮大的用来构建下令行程序的库,许多盛行的Go项目都是用它来构建的,好比Kubernetes、Docker、etcd、Istio、Github CLI等等。

接下来,演示开发一个我们自己的下令行程序chenqionghe,模拟一下docker下令行,预期功效如下

# 查看辅助
chenqiong -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

二、初始化应用

gomod初始化

这里我的应用名叫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可以看到生效了
手把手教你开发docker一样的命令行

三、天生Command

建立hello子下令

cobra add hello

会在cmd下天生一个hello.cmd的下令,天生的下令是长下面这样的,焦点是挪用了AddCommand方式
手把手教你开发docker一样的命令行

我们把没用的信息干掉,精简后如下

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

手把手教你开发docker一样的命令行

建立version子下令

同理,我们再建立一个version下令

cobra add version

修改一下Run方式

Run: func(cmd *cobra.Command, args []string) {
   fmt.Println("chenqionghe version v0.0.1")
},

运行如下
手把手教你开发docker一样的命令行

四、若何设置flag选项

flag选项按作用局限分为persistent和local两类

全局选项

persistent是全局选项,对应的方式为PersistentFlags,可以分配给下令和下令下的所有子下令,上面的rootCmd和helloCmd都是可以挪用flag
例如,添加一个-v选项

func init() {
	var Verbose bool
	rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "全局版本")
}

运行,可以看到生效了
手把手教你开发docker一样的命令行

springboot + aop + Lua分布式限流的最佳实践

内陆选项

local为内陆选项,对应方式为Flags,只对指定的Command生效,我们往hello下令的init里边添加一个内陆flag

func init() {
	rootCmd.AddCommand(helloCmd)
	//内陆flag
	var Source string
	helloCmd.Flags().StringVarP(&Source, "source", "s", "", "读取文件路径")
}

运行如下
手把手教你开发docker一样的命令行

设置必填

我们在init函数添加以下代码

rootCmd.Flags().StringVarP(&Name, "name", "n", "", "你的名字")
rootCmd.MarkFlagRequired("name")

运行如下,必须填写name参数才可以运行
手把手教你开发docker一样的命令行

绑定设置

添加一个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),
}

运行输出
手把手教你开发docker一样的命令行

六、若何使用参数

我们可以看到焦点的方式,实在就是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)
	},
}

运行如下
手把手教你开发docker一样的命令行

获取args参数

var helloCmd = &cobra.Command{
	Use:   "hello",
	Short: "hello下令简介",
	Long:  `hello下令详细先容`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println(args)
	},
	TraverseChildren: true,
}

挪用如下,可以看到已经取出了所有的args参数
手把手教你开发docker一样的命令行

七、若何设置钩子

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)
	},
}

运行如下
手把手教你开发docker一样的命令行

总结

到这里,我们就已经学会了若是设置子下令、flag参数、arguments参数以及编写方式使用这些参数,
另有最后一步,就是编译出我们的二进制程序,验证一下我们之前的需求

  • 编译
go build -o chenqionghe

如下,已经天生二进制文件chenqionghe
手把手教你开发docker一样的命令行

  • 运行下令
./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

手把手教你开发docker一样的命令行

可以看到,完善的实现了预期需求,就是这么简朴,light weight baby!

原创文章,作者:2d28新闻网,如若转载,请注明出处:https://www.2d28.com/archives/4596.html