go cli脚手架开发利器

您所在的位置:网站首页 command名词 go cli脚手架开发利器

go cli脚手架开发利器

2023-07-05 11:55| 来源: 网络整理| 查看: 265

文章目录 关于说明cobra 简介cobra 概念CommandsFlagsArgs 教程正文demo1 快速了解demo知识点:Command创建命令 demo2 使用参数验证器、钩子函数demo知识点:参数验证方法知识点:生命周期钩子函数知识点:帮助命令知识点:使用信息 demo3 生成帮助文档文件(markdown文件)demo知识点 生成帮助文档文件(markdown文件)

关于

×错例:

不能完全代替shell,cobra能支持的脚本格式比较局限

无法像Java -jar -Dxx=str1 -Dxx2=str2 那样读取-D指示的值

读取参数只能为无格式纯文本,不要尝试读取json、特殊字符、转义符和富文本。

避免一大堆可变配置参数都通过flag传,参数太多建议改成读取配置文件

√正确:

读取5个以上的flag时使用,配置文件+viper,环境变量等,减少flag的个数到5个以内;

参数的值不要过长,仅纯文本string、int和bool类型,富文本、json等建议通过flag传文件路径,在run方法的逻辑读取文件,进行操作

短平快、小型脚手架推荐使用cobra封装命令集,同时学习了解pflag、flag、viper库

说明 cobra 简介

cobra既是一个用于创建强大现代CLI应用程序的库,也是一个生成应用程序和命令文件的程序。cobra被用在很多go语言的项目中,比如 Kubernetes、Docker、Istio、ETCD、Hugo、Github CLI等等,更多项目详见此列表。

cobra 概念

cobra由命令、参数、标志组成 commands代表动作,args是事物,flags是动作的修饰符(一般两个-连接符) 模式如下: APPNAME VERB NOUN --ADJECTIVE. or APPNAME COMMAND ARG --FLAG(APPNAME 动词 名词 形容词 或者 APPNAME 命令 参数 标志) 如下的例子,server 是command,port是flag

hugo server --port=1313

Commands

命令是交互程序的中心,每一个命令都有子命令。 链接:cobra package - github.com/spf13/cobra - Go Packages 需要rootCmd和其他命令(按需)

Flags

flag是一种修改命令行为的方式,cobra支持完全兼容POSIX标志,也支持go flag package,cobra可以定义到子命令上的标志,也可以仅对该命令可用的标志

Args

args参数是命令command需要识别的一些值,cobra可以指定读取任意数量的参数,也可以不接受参数,此时该输入会被当作未定义的command报错。 command、args搭配使用

教程正文 demo1 快速了解

参考:Go语言命令行利器cobra使用教程 - 简书

demo

main.go负责调用rootCmd execute方法

import "cobra_cmd/cmd" func main() { cmd.Execute() }

在cmd目录下创建rootcmd.go

//每一个command命令,都是一个 &cobra.Command{ } 示例 var rootCmd = &cobra.Command{ Use: "root-cli", Short: "示例脚本 root cli", Long: `这是 cobra 测试程序使用的示例脚本,您可参考cobra其他文档并随时更新本demo`, //参数验证器,设置某个脚本 能接受参数的个数。 Args: cobra.MinimumNArgs(1), RunE: runRoot, //RunE Run字段都是执行具体的函数 ,抽到别处定义 } //rootCmd.Execute() 是命令执行入口 func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } //具体的执行逻辑 func runRoot(cmd *cobra.Command, args []string) error { fmt.Printf("execute %s args:%v \n", cmd.Name(), args) //例如 这里处理无参数启动时程序处理 if len(args) Use: "print [string to print]", Short: "Print anything to the screen", Long: `print is for printing anything back to the screen. For many years people have printed back to the screen.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Print: " + strings.Join(args, " ")) }, } var cmdEcho = &cobra.Command{ Use: "echo [string to echo]", Short: "Echo anything to the screen", Long: `echo is for echoing anything back. Echo works a lot like print, except it has a child command.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Print: " + strings.Join(args, " ")) }, } var cmdTimes = &cobra.Command{ Use: "times [# times] [string to echo]", Short: "Echo anything to the screen more times", Long: `echo things multiple times back to the user by providing a count and a string.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { for i := 0; i //通过AddCommand组成父子关系,多级命令 rootCmd.AddCommand(helloCmd) // root有两个子命令,和一个cmdEcho命令下的子命令cmdTimes //一级root --> 二级print,echo --> 三级times rootCmd.AddCommand(cmdPrint, cmdEcho) cmdEcho.AddCommand(cmdTimes) //本地标志,只在mdTimes命令 起作用 cmdTimes.Flags().IntVarP(&echoTimes, "echoTimes", "t", 1, "times to echo the input") }

以上是一个入门demo,演示了命令command结构、标志的定义和读取、命令组成上下级、父子关系。

重点: 1.rootCmd和其他command放 cmd 包下; 2.在单独的commandXxx.go文件里,为每一个command定义 &cobra.Command{} 结构体并在init()方法里通过AddCommand() 做父子上下级关系关联、以及flag标志的读取操作; 3.main()入口方法调用到rootCmd.Execute()即完成工作。

知识点:Command创建命令

结构如下,列举大概常用的字段:

&cobra.Command{ // 命令名称 Use: "echo [string to echo]", // 命令别名 Aliases: []string{"log","output"}, // 命令简介 Short: "Echo anything to the screen", // 命令详细说明 Long: `echo is for echoing anything back. Echo works a lot like print, except it has a child command.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Print: " + strings.Join(args, " ")) }, } use 是该命令的用法,单行用法消息,表示了某一级命令,可以理解为该命令的名字;Short、Long是该命令的一行简介、一大段详细介绍文本;具体会在输出help帮助时才有不一样的提示,可以粗暴设置成同样内容;Run、RunE是命令被执行时的具体逻辑,RunE会返回error给上层;Alias是一组可代替Use那个名字的,同名,都会映射到本命令;Args:参数验证,可以限制参数的个数等等,有如图几种验证方法: 在这里插入图片描述 demo2 使用参数验证器、钩子函数 demo package main import ( "bufio" "fmt" "github.com/spf13/cobra" "github.com/spf13/viper" "os" ) var rootCmd = &cobra.Command{ Use: "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.`, //运行命令的逻辑 //Run: func(cmd *cobra.Command, args []string) { //debug //fmt.Println("== root命令运行成功 ==") //}, } // 再定义二级子命令: var createCmd = &cobra.Command{ Use: "create", Short: "创建书签", } var urlCmd = &cobra.Command{ Use: "url", Short: "Bookmark a url link ", Long: "收藏一个url链接", //cobra 常用的参数配置校验器如下: // //MinimumNArgs(int) 当参数数目低于配置的最小参数个数时报错 //MaximumNArgs(int) 当参数数目大于配置的最大参数个数时报错 //ExactArgs(int) 如果参数数目不是配置的参数个数时报错 //NoArgs 没有参数则报错 //参数验证除了RangeArgs 还有 NoArg、ExactArgs、 Args: cobra.RangeArgs(1, 3), Run: func(cmd *cobra.Command, args []string) { fmt.Println("link is:", link) if len(args) == 2 { fmt.Println(args[0], args[1]) } else if len(args) == 0 { fmt.Println("收藏链接参数:", args) return } else { fmt.Println("收藏链接参数:", args) } file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { fmt.Println(err) } //及时关闭file句柄 defer file.Close() //写入文件时,使用带缓存的 *Writer write := bufio.NewWriter(file) for i := 0; i rootCmd.AddCommand(createCmd) createCmd.AddCommand(urlCmd) //持久标志,传递给所有子命令 rootCmd.PersistentFlags().StringVarP(&filePath, "path", "p", "./bookmarks.txt", "save to txt file") //局部标志,仅用于具体一个子命令 urlCmd.Flags().StringVarP(&link, "link", "l", "", "收藏链接格式: 链接地址 名称") //钩子函数演示 rootCmd.AddCommand(hookCmd) hookCmd.AddCommand(hookSub) hookSub.AddCommand(hookfinal) } func main() { // For environment variables. viper.SetEnvPrefix("core") viper.AutomaticEnv() if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } } // / 钩子函数测试 var hookCmd = &cobra.Command{ Use: "hookroot", Short: "钩子函数测试 一级", Long: "测试 生命周期的不同钩子函数的继承关系", PersistentPreRun: func(cmd *cobra.Command, args []string) { fmt.Println("hookroot: PersistentPreRun") }, PreRun: func(cmd *cobra.Command, args []string) { fmt.Println("hookroot: PreRun") }, Run: func(cmd *cobra.Command, args []string) { fmt.Println("hookroot: Running...") }, PostRun: func(cmd *cobra.Command, args []string) { fmt.Println("hookroot: PostRun") }, PersistentPostRun: func(cmd *cobra.Command, args []string) { fmt.Println("hookroot: PersistentPostRun") }, } // // 会继承 父命令的PersistentPreRun、PersistentPostRun var hookSub = &cobra.Command{ Use: "hooksub", Short: "钩子函数测试 二级", PreRun: func(cmd *cobra.Command, args []string) { fmt.Println("hooksub: PreRun") }, Run: func(cmd *cobra.Command, args []string) { fmt.Println("hooksub: Running...") }, PersistentPostRun: func(cmd *cobra.Command, args []string) { fmt.Println("hooksub: PersistentPostRun") //覆盖了root的PersistentPostRun,并传给下级 }, } // // 会继承 父命令的PersistentPreRun、PersistentPostRun var hookfinal = &cobra.Command{ Use: "hookfinal", Aliases: []string{"final", "finally"}, Short: "钩子函数测试 三级", PreRun: func(cmd *cobra.Command, args []string) { fmt.Println("hookfinal: PreRun") }, Run: func(cmd *cobra.Command, args []string) { fmt.Println("hookfinal: Running...") }, } output: //go run .\helloworld.go hookroot hooksub hookfinal //hookroot: PersistentPreRun //hookfinal: PreRun //hookfinal: Running... //hooksub: PersistentPostRun/

以上是一个进阶demo,演示了PersistentFlags和Flags的区别,以及钩子函数在向下传递时可被覆盖

重点: 1.PersistentFlags 设置的是持久标志,由rootCmd根命令设置,可被其他命令使用,而flag设置的只能在当前命令使用; 2.在单独的command执行之前、之后都可以执行其他操作,也即预先处理、后置处理。执行顺序为PersistentPreRun、PreRun、Run、PostRun、PersistentPostRun 3.带Persistent的可以传递给子命令(继承),但也可以被子命令重新声明而被覆盖(重写) 4.不带Persistent开头的前后处理

知识点:参数验证方法

以下代码:Args: cobra.MinimumNArgs(1)就是一个验证方法

import ( "github.com/spf13/cobra" ) var rootCmd = &cobra.Command{ Use: "myapp", 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.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { // Do something here }, } func init() { // Here you will define your flags and configuration settings. } func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } }

可以看到在 rootCmd 中设置了 Args: cobra.MinimumNArgs(1),这将强制要求至少传入一个参数,否则会抛出一个错误。此外,还可以使用 cobra 提供的其他参数验证方法,例如:

cobra.MaximumNArgs(n int):强制要求不超过 n 个参数。 cobra.OnlyValidArgs([]string):强制要求传入的参数必须是所指定的 string 类型的 slice 中的值。 cobra.ArgRange(min, max int):强制要求传入参数的数量在 min 和 max 之间。 以上是一些常用的参数验证方法,Cobra 还有更多的验证方法和选项,可以根据实际需求进行选择和设置。

知识点:生命周期钩子函数

参考: Go 每日一库之 cobra - 知乎 Cobra 中文文档 - 掘金

可以在执行命令之前和之后运行一个函数。PersistentPreRun 和 PreRun 函数将在 Run 之前执行。PersistentPostRun 和 PostRun 会在 Run 之后运行。如果子级未声明自己的 Persistent * Run 函数,则子级将继承父级的。这些函数的执行顺续如下:

PersistentPreRun PreRun Run PostRun PersistentPostRun PersistentXxx是可以被子命令继承的前、后置处理

知识点:帮助命令

当你添加了子命令,Cobra 会自动添加一些帮助命令。当你执行 app help 命令时会显示帮助信息。另外,help 还支持其他命令作为输入参数。举例来说,你有一个没有额外配置的 create 命令,app help create 是有效的。每一个命令还会自动获取一个 --help 标志。

help 就像其他命令一样。并没有特殊的逻辑或行为。实际上,你可以根据需要提供自己的服务。 定义你自己的 help 你可以使用下面的方法提供你自己的 Help 命令或模板。

cmd.SetHelpCommand(cmd *Command) cmd.setHelpCommand(f func(*Command, []string)) cmd.setHelpTemplate(s string)

后两者也适用于所有子命令。

知识点:使用信息

当用户提供无效的标志或无效的命令时,Cobra 会通过向用户显示 usage 进行响应。 这时可以自定义usage用法,提供自己的 usage函数和模板

cmd.SetUsageFunc(f func(*Command) error) cmd.SetUsageTemplate(s string)

可以参考 GitHub CLI 项目中usage使用信息的写法。

demo3 生成帮助文档文件(markdown文件)

参考cobra document#mrkdown-docs cobra支持生成所有命令的帮助文档树doc.GenMarkdownTree(cmd,dir)

demo

main.go:

import ( "github.com/spf13/cobra/doc" "log" "os" ) func InitCommand() { rootCmd.AddCommand(helloCmd) // 两个顶层的命令,和一个cmdEcho命令下的子命令cmdTimes rootCmd.AddCommand(cmdPrint, cmdEcho) cmdEcho.AddCommand(cmdTimes) //utils.Mkdir("./docs") os.MkdirAll("H:\\docs", os.ModePerm) //显式创建目标文件夹,文件夹存在时再次调用不会做任何事情 err := doc.GenMarkdownTree(rootCmd, "H:\\docs") //核心api GenMarkdownTree if err != nil { log.Fatal(err) } } 知识点 生成帮助文档文件(markdown文件)

给某个命令及其子命令生成帮助文档树(一系列文档),参考以下代码片段:

err := doc.GenMarkdownTree(rootCmd, "H:\\docs") //核心api GenMarkdownTree if err != nil { log.Fatal(err) }

即可在目标文件夹下看到生成的md文件: 在这里插入图片描述

其他高级用法或生成其他格式帮助文档,请参考cobra document#mrkdown-docs ,以及cobra代码库的github.com/spf13/cobra/doc文件夹下的代码和文档。

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3