cobra框架

cobra框架一个命令行框架,可以用于编写命令行工具。

创建一个项目

安装cobra

go get github.com/spf13/cobra@latest

安装viper

go get github.com/spf13/viper

 

1.入门案例

创建一个cmd目录,存放命令,而main.go作为入口

目录结构如下

比如要添加一个init命令,就在cmd目录下创建对应文件

 

首先定义root命令

package cmd

import "github.com/spf13/cobra"

var rootCmd = &cobra.Command{}

cobra.Command 结构体提供了许多属性和方法,用于定义命令和子命令的行为。

如图:

属性:

  • Use:表示命令或子命令的使用方式。它是一个字符串,描述了命令或子命令的名称和参数的使用方法。
  • Aliases:表示命令或子命令的别名列表。它是一个字符串切片,可以为命令或子命令指定多个别名。
  • Short:提供命令或子命令的简短描述。它是一个字符串,用于描述命令或子命令的功能。
  • Long:提供命令或子命令的详细描述。它是一个字符串,可以包含更详细的文档、示例和用法等信息。
  • Run:命令或子命令的执行函数。它是一个函数,用于定义命令或子命令的具体逻辑。

比如在root.go文件,Execute()给main文件调用

package cmd

import (
   "fmt"
   "github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
   Use:   "root",
   Short: "this is short description",
   Long:  "this is long description",
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("root cmd working!")
   },
}

func Execute() {
   rootCmd.Execute()
}

在使用 Cobra 构建命令行应用程序时,我们通常会定义一个根命令,它是所有其他命令和子命令的入口点。而 rootCmd.Execute() 就是用来执行这个根命令。

在main.go方法调用

package main

import "cobrademo/cmd"

func main() {
   cmd.Execute()
}

输出如下

 

 

2.定义选项

同样在root.go文件,在init函数

func init() {
    rootCmd.PersistentFlags()
    rootCmd.Flags()
}

在 Cobra 框架中,.PersistentFlags() 方法是用于获取命令的持久标志(Persistent Flags)的方法。

  • 与普通标志不同,持久标志是可以被上下文(Context)和子命令继承的标志。
  • 这意味着如果一个命令定义了一个持久标志,那么它的所有子命令都可以访问和使用该标志。
  • 根命令的持久化标志,所有命令都能使用,就是全局标志

 

在 Cobra 框架中,.Flags() 方法是用于获取命令的标志(Flags)的方法。

  • 标志是命令行应用程序中的参数选项,用于接收用户提供的值。
  • 通过调用 .Flags() 方法,我们可以获取到命令的标志对象,然后可以通过该对象来定义和管理标志。
  • 通过该方法定义的只能在该命令使用。

举例:

这里使用string类型举例,在root.go加入init函数

var config string
var time string

func init() {
   rootCmd.PersistentFlags().String("name", "mycabro", "")
   rootCmd.PersistentFlags().StringP("author", "a", "dreams", "")
   rootCmd.PersistentFlags().StringVar(&time, "time", "2024-1-1", "")
   rootCmd.PersistentFlags().StringVarP(&config, "config", "c", "", "")

   rootCmd.Flags().StringP("description", "d", "", "")
}

.String() 方法用于定义一个字符串类型的持久标志参数,并返回一个指向该标志参数值的指针。

该方法有三个参数:

  • name string:标志参数名称,用于在命令行中指定该标志参数。
  • value string:标志参数的默认值。
  • usage string:标志参数的使用说明。

.StringP() 方法用于定义一个字符串类型的持久标志参数,并返回一个指向该标志参数值的指针。

该方法有四个参数:

  • name string:标志参数名称,用于在命令行中指定该标志参数。
  • shorthand string:标志参数的简短名称,可以通过单个字符的方式指定。
  • value string:标志参数的默认值。
  • usage string:标志参数的使用说明。

.StringVar() 方法用于定义一个字符串类型的持久标志参数,并将其与一个变量绑定,以便在程序运行时直接修改该变量的值。

该方法有四个参数:

  • p *string:指向要绑定的变量的指针。
  • name string:标志参数名称,用于在命令行中指定该标志参数。
  • value string:标志参数的默认值。
  • usage string:标志参数的使用说明。

 

注意:还有其他类型如int,bool等,用法一致

.Flags() 方法同样如此使用,不再赘述

 

这里我们使用命令行启动

go run .\main.go -h

可以我们定义的看到全部出来了

注意:可以看到-h是其自动存在的,用于查看帮助信息

 

3.绑定配置文件

首先我们在当前目录下新建一个配置文件config.yaml

name: test
auther: test
time: 2024-2-2
url: www.tanjy.site

 

前面我们已经安装了viper

go get github.com/spf13/viper

常用方法如下:

  • viper.SetConfigFile(config) 是一个配置文件的设置方法,它通过将文件路径传递给 SetConfigFile 函数来指定要使用的配置文件。
  • os.UserHomeDir() 是 Go 标准库中的一个函数,用于获取当前用户的主目录路径。该函数会返回两个值,分别是当前用户的主目录路径和可能发生的错误
  • cobra.CheckErr(error) 是使用 Cobra 框架时常用的一个辅助函数,用于检查错误并在出现错误时终止程序执行。
  • viper.AddConfigPath(home) 是使用 Viper 库时常用的一个函数,用于指定配置文件的搜索路径。
  • viper.SetConfigType(“yaml”) 是 Viper 库中用于指定配置文件类型的函数调用。在这个例子中,它告诉 Viper 库要解析的配置文件类型为 YAML 格式。
  • viper.SetConfigType(“yaml”) 是 Viper 库中用于指定配置文件类型的函数调用。在这个例子中,它告诉 Viper 库要解析的配置文件类型为 YAML 格式。
  • viper.AutomaticEnv() 是 Viper 库中的一个函数,用于将环境变量自动加载到 Viper 实例中。
  • 当调用 viper.ReadInConfig() 函数时,Viper 会尝试从预定义的路径和文件名中读取配置文件。如果成功读取配置文件,则返回值 err 将为 nil,表示没有错误发生。
  • viper.ConfigFileUsed() 是 Viper 库中的一个函数,用于获取当前正在使用的配置文件的路径。

 

cobra.OnInitialize() 是 Cobra 库中的一个函数,它用于在执行命令前初始化应用程序。它通常被用来设置全局变量、读取配置文件、建立数据库连接等操作,他接收一个函数

在root.go文件的init函数加入以下代码

cobra.OnInitialize(initConfig)

 

initConfig是一个函数,定义如下:

同样在root.go加入函数

func initConfig() {
   if config != "" {
      viper.SetConfigFile(config)
   } else {
      home, error := os.UserHomeDir()
      cobra.CheckErr(error)
      viper.AddConfigPath(home)
      viper.SetConfigType("yaml")
      viper.SetConfigName(".cobra")
   }
   // 检查环境变量,将配置的键值加载到viper
   viper.AutomaticEnv()
   if err := viper.ReadInConfig(); err != nil {
      fmt.Println(err)
   }
   fmt.Println("use config file :", viper.ConfigFileUsed())
}

这里尝试输出,更改root.go文件

cmd.PersistentFlags().Lookup(“config”).Value 是 Cobra 库中的一个表达式,用于获取名为 “config” 的持久性标志的当前值。

.GetString() 方法是 Viper 库中的一个函数,用于获取 Viper 实例中配置项的当前值。

var rootCmd = &cobra.Command{
   Use:   "root",
   Short: "this is short description",
   Long:  "this is long description",
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("root cmd working!")
      fmt.Println("description的值 : ", cmd.Flags().Lookup("description").Value)
      fmt.Println("author的值 : ", cmd.PersistentFlags().Lookup("author").Value)
      fmt.Println("name的值 : ", cmd.PersistentFlags().Lookup("name").Value)
      fmt.Println("config的值 : ", cmd.PersistentFlags().Lookup("config").Value)
      fmt.Println("----------")
      fmt.Println("author的值 : ", viper.GetString("author"))
      fmt.Println("name的值 : ", viper.GetString("name"))
   },
}
更改root.go文件的init函数

viper.BindPFlag() 是 Viper 库中的一个函数,用于将 Cobra 命令行标志与 Viper 配置项绑定。

func init() {
   cobra.OnInitialize(initConfig)
   rootCmd.PersistentFlags().String("name", "mycabro", "")
   rootCmd.PersistentFlags().StringP("author", "a", "dreams", "")
   rootCmd.PersistentFlags().StringVar(&time, "time", "2024-1-1", "")
   rootCmd.PersistentFlags().StringVarP(&config, "config", "c", "", "")
   rootCmd.Flags().StringP("description", "d", "", "")
   // 配置绑定
   viper.BindPFlag("name", rootCmd.PersistentFlags().Lookup("name"))
   viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
   // 默认值
   viper.SetDefault("name", "default name")
   viper.SetDefault("author", "default author")
}

运行,如果我们指定了name和author,就输出指定的值

go run .\main.go --author=tanjy --name=dreams --config=config.yaml

 

没有指定就输出配置文件的值,可以快点配置文件是保存到viper中

go run .\main.go --config=config.yaml

 

 

4.父子传递

在Cobra中,TraverseChildren属性是一个bool类型的变量,用于控制命令的参数是否应该被传递给子命令。

TraverseChildren: true,

当TraverseChildren属性为true时,如果用户输入了一个父命令和一个或多个参数,这些参数会被传递到子命令中。例如,如果用户输入myapp parent-command child-command arg1 arg2,则arg1和arg2将被传递到child-command中。

当TraverseChildren属性为false时,任何参数都不会被传递给子命令。在上述示例中,arg1和arg2将留在parent-command的作用域中,不会被传递到child-command中。

 

为了显示好看,我们在root.go加入中文描述

 

这里我们完善一下init命令

在cmd/init.go

.AddCommand方法用于将一个子命令添加到父命令中。它接受一个表示子命令的对象作为参数,并将其添加到父命令的列表中。

package cmd

import (
   "fmt"
   "github.com/spf13/cobra"
   "github.com/spf13/viper"
)

var initCmd = &cobra.Command{
   Use:   "init",
   Short: "初始化命令",
   Long:  "初始化命令,完成初始化",
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("init cmd working!")
      fmt.Println("author的值 : ", viper.GetString("author"))
      fmt.Println("name的值 : ", viper.GetString("name"))
   },
}

func init() {
   rootCmd.AddCommand(initCmd)
   //定义如同root,不再举例
   initCmd.PersistentFlags().StringP("many", "m", "", "测试")
}

运行

go run .\main.go -h
可以看到init出现了

加上init

go run .\main.go init -h

 

如果想获取父的值

在cmd/root.go,修改

var initCmd = &cobra.Command{
   Use:   "init",
   Short: "初始化命令",
   Long:  "初始化命令,完成初始化",
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("init cmd working!")
      fmt.Println("description的值 : ", cmd.Flags().Lookup("description").Value)
      fmt.Println("author的值 : ", cmd.PersistentFlags().Lookup("author").Value)
      fmt.Println("name的值 : ", cmd.PersistentFlags().Lookup("name").Value)
      fmt.Println("config的值 : ", cmd.PersistentFlags().Lookup("config").Value)
      fmt.Println("----------")
      fmt.Println("author的值 : ", viper.GetString("author"))
      fmt.Println("name的值 : ", viper.GetString("name"))
   },
}

运行会报错

 

所以只能使用cmd.Flags()获取

var initCmd = &cobra.Command{
   Use:   "init",
   Short: "初始化命令",
   Long:  "初始化命令,完成初始化",
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("init cmd working!")
      fmt.Println("author的值 : ", cmd.Flags().Lookup("author").Value)
      fmt.Println("name的值 : ", cmd.Flags().Lookup("name").Value)
      fmt.Println("config的值 : ", cmd.Flags().Lookup("config").Value)
      fmt.Println("----------")
      fmt.Println("author的值 : ", viper.GetString("author"))
      fmt.Println("name的值 : ", viper.GetString("name"))
   },
}

 

父类的参数在init前使用即可

go run .\main.go -d hello init -a PomsAndDreams

 

子类获取父类使用

cmd.Parent().Flags().Lookup("description").Value

例如:

var initCmd = &cobra.Command{
   Use:   "init",
   Short: "初始化命令",
   Long:  "初始化命令,完成初始化",
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("init cmd working!")
      fmt.Println("author的值 : ", cmd.Flags().Lookup("author").Value)
      fmt.Println("name的值 : ", cmd.Flags().Lookup("name").Value)
      fmt.Println("config的值 : ", cmd.Flags().Lookup("config").Value)
      fmt.Println("----------")
      fmt.Println("author的值 : ", viper.GetString("author"))
      fmt.Println("name的值 : ", viper.GetString("name"))

      fmt.Println("description的值 : ", cmd.Parent().Flags().Lookup("description").Value)

   },
}

运行,TraverseChildren为true才能如此

 

 

5.定义参数

基本操作与选项定义一致,只是在定义时多了Args属性,而获取可以在Run属性中的args中

在 Cobra 框架中,Args 属性用于获取用户在命令行输入的所有非标记参数。可以将 Args 看作是一个字符串切片,其中每个元素都是用户输入的一个非标记参数,一般可以在这做参数验证

在cmd目录下新建useArgs.go

package cmd

import (
   "errors"
   "fmt"
   "github.com/spf13/cobra"
)

var useArgs = &cobra.Command{
   Use: "useArgs",
   Args: func(cmd *cobra.Command, args []string) error {
      if len(args) < 1 {
         return errors.New("请输入参数")
      }
      return nil
   },
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("Args参数为 : ", args)
   },
}

func init() {
   rootCmd.AddCommand(useArgs)
}

运行:

go run .\main.go useArgs args1 args2

 

 

Args 属性还内置了参数验证

比如:

在 Cobra 框架中,Args: cobra.NoArgs 是一种特殊的用法,用于定义一个命令或子命令不接受任何非标记参数的情况。它表示该命令或子命令不期望用户在命令行中输入任何额外的参数。

当使用 cobra.NoArgs 时,如果用户在命令行中输入了非标记参数,Cobra 框架会报错并提示用户不应该输入参数。这对于需要确保命令或子命令的参数是固定的,不允许用户输入其他参数的情况非常有用。

在cmd目录下新建noArgs.go

package cmd

import (
   "fmt"
   "github.com/spf13/cobra"
)

var noArgs = &cobra.Command{
   Use:  "noArgs",
   Args: cobra.NoArgs,
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("Args参数为 : ", args)
   },
}

func init() {
   rootCmd.AddCommand(noArgs)
}

运行

go run .\main.go noArgs

 

ValidArgs: []string{…}:指定合法的参数值列表,用于验证用户输入的参数是否符合预期。这不是Args的参数,需要搭配cobra.OnlyValidArgs 。

cobra.OnlyValidArgs 是一个选项函数,可以用于在解析命令行参数时,只保留合法的参数值。

在cmd目录下新建validArgs.go

package cmd

import (
   "fmt"
   "github.com/spf13/cobra"
)

var validArgs = &cobra.Command{
   Use:       "validArgs",
   Args:      cobra.OnlyValidArgs,
   ValidArgs: []string{"hello", "Hi"},
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("Args参数为 : ", args)
   },
}

func init() {
   rootCmd.AddCommand(validArgs)
}

如果不是定义的可选参数就会异常

 

还有

  • Args: cobra.MaximumNArgs(n int) 是一种用法,用于限制用户在命令行中输入的非标记参数的数量不超过 n 个。它表示该命令或子命令最多接受 n 个非标记参数。
  • Args: cobra.MinimumNArgs(n int):限制用户在命令行中输入的非标记参数的数量不少于 n 个,类似于 cobra.MaximumNArgs()。
  • Args: cobra.ArbitraryArgs:接受任意数量的非标记参数
  • Args: cobra.ExactArgs(n)要求恰好n个参数

 

6.钩子函数

在cmd目录下新建hook.go

package cmd

import (
   "fmt"
   "github.com/spf13/cobra"
)

var hook = &cobra.Command{
   Use: "hook",
   Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("Run----")
   },

   PersistentPreRun: func(cmd *cobra.Command, args []string) {
      //run函数之前,如果父类存在子类不存在使用父类,如果父类存在子类也存在使用子类。
      fmt.Println("PersistentPreRun----")
   },

   PersistentPostRun: func(cmd *cobra.Command, args []string) {
      //run函数之后,同上
      fmt.Println("PersistentPostRun---")
   },

   PreRun: func(cmd *cobra.Command, args []string) {
      //run函数之前,PersistentPreRun之后
      fmt.Println("PreRun---")
   },

   PostRun: func(cmd *cobra.Command, args []string) {
      //run函数之后,PersistentPostRun之前
      fmt.Println("PostRun---")
   },
}

func init() {
   rootCmd.AddCommand(hook)
}

执行顺序一目了然

 

 

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇