2
cobra 是由 spf13 大佬写的一个开发客户端工具的 golang 库,通过 cobra 可以很方便的开发可执行文件。源码地址:https://github.com/spf13/cobra

概念

Cobra 是建立在一系列的命令、参数和标识之上的库。

  • Commands 代表的是动作
  • Args 代表的是这个动作需要的事务
  • Flags 表示动作的修饰

一个好的命令工具,读起来应该像一个句子一样,比如:

git clone URL --bare

# git 就是可执行文件名
# clone 就是命令(Command)
# URL 就是事务(Arg)
# --bare 就是修饰动作的Flag

Commands

Command 结构定义如下(仅仅列出了常用的):

type Command struct {
    // 使用单行去显示这个命令的使用信息。
    // 推荐的语法如下:
    //   [ ] 标识一个可选的flag。
    //   ... 表示前面的参数可以出现多次
    //   |   使用分割线表示互斥的信息
    // Example: add [-F file | -D dir]... [-f format] profile
    Use string

    // 别名数组,和上面 Use 的第一个字符串意义相同
    Aliases []string

    // help 输出的短描述
    Short string

    // help 输出的长描述
    Long string

    // 使用例子
    Example string

    // 期望参数校验
    Args PositionalArgs

    // 如果某个命令废弃了 则使用这个命令的时候打印
    Deprecated string

    Version string

    // The *Run functions are executed in the following order:
    //   * PersistentPreRun()
    //   * PreRun()
    //   * Run()
    //   * PostRun()
    //   * PersistentPostRun()
    // All functions get the same args, the arguments after the command name.
    //
    // PersistentPreRun: children of this command will inherit and execute.
    PersistentPreRun func(cmd *Command, args []string)
    // PersistentPreRunE: PersistentPreRun but returns an error.
    PersistentPreRunE func(cmd *Command, args []string) error
    // PreRun: children of this command will not inherit.
    PreRun func(cmd *Command, args []string)
    // PreRunE: PreRun but returns an error.
    PreRunE func(cmd *Command, args []string) error
    // Run: Typically the actual work function. Most commands will only implement this.
    Run func(cmd *Command, args []string)
    // RunE: Run but returns an error.
    RunE func(cmd *Command, args []string) error
    // PostRun: run after the Run command.
    PostRun func(cmd *Command, args []string)
    // PostRunE: PostRun but returns an error.
    PostRunE func(cmd *Command, args []string) error
    // PersistentPostRun: children of this command will inherit and execute after PostRun.
    PersistentPostRun func(cmd *Command, args []string)
    // PersistentPostRunE: PersistentPostRun but returns an error.
    PersistentPostRunE func(cmd *Command, args []string) error
}

Flags

Cobra 的 flag 解析由 pflag library 完成。符合 POSIX-compliant flags 和 Go flag package 标准。

安装

使用 go get 安装cobra:

go get -u github.com/spf13/cobra/cobra

之后,使用下列代码在你的应用中使用 cobra:

import "github.com/spf13/cobra"

实战

通常使用 Cobra 的应用,一般的文件架构如下:

 ▾ appName/
    ▾ cmd/
        add.go
        your.go
        commands.go
        here.go
      main.go

在 main.go 中,我们只需要编写如下代码:

package main

import (
    "path/cmd"
)

func main() {
    cmd.Execute()
}

创建应用

我们开始以实战创建一个 cobra 项目。

我们开一个 tools 工具,该工具具有如下功能:

tools [command]
    - time 打印当前时间
        -f format 格式化打印当前时间

首先,我们先创建一个tools应用。

mkdir -p ${GO_PATH}/src/github.com/tools/cmd

cd ${GO_PATH}/src/github.com/tools

go mod init github.com/tools

然后我们在 tools 目录下创建 tools.go,在 cmd 目录下创建 time.go.

我们的目录层次如下:

.
├── cmd
│   └── time.go
├── go.mod
└── tools.go

编写代码

main.go 里面的逻辑比较简单,代码如下:

package main

import (
    "github.com/tools/cmd"
    "log"
)

func main()  {
    tools := cmd.NewToolsCommand()
    if err := tools.Execute(); err != nil {
        log.Fatal(err)
    }
}

接下来编写 time.go .

我们需要先编写 tools 这个工具:

rootCmd := &cobra.Command{
    Use:  "tools",
    Long: "tools 工具有很多用法,期待你的探索",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("欢迎使用 tools 工具")
    },
}

然后编写 time 子命令:

timeCmd := &cobra.Command{
    Use:     "time [-f format]",
    Short:   "time 子命令可以打印时间",
    Long:    "time 子命令是tools工具的一大特点,你可以使用time子命令灵活的输出当前时间",
    Example: "tools time [-f format]",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println(time.Now())
    },
}

由于我们需要使用 flags ,所以先定义一个 flag:

var format string

// Flags() 和 PersistentFlags()的区别是 前者只作用在当前命令,后者也会作用在子命令
// 参数分别是:标志结果、长选项、短选项、默认值、描述
timeCmd.Flags().StringVarP(&format, "format", "f", "2006-01-02 15:04:05", "desc")

// 如果我们希望这个flag必须要,可以使用 timeCmd.MarkFlagRequired("format")

定好了标识,我们就需要改写 time 命令的 RUN:

func(cmd *cobra.Command, args []string) {
    if format != "" {
        fmt.Println(time.Now().Format(format))
        return
    }
    fmt.Println(time.Now())
}

完整代码如下:

package cmd

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

var (
    format string
)

func NewToolsCommand() *cobra.Command {
    rootCmd := &cobra.Command{
        Use:  "tools",
        Long: "tools 工具有很多用法,期待你的探索",
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Println("欢迎使用 tools 工具")
        },
    }
    
    timeCmd := &cobra.Command{
        Use:     "time [-f format]",
        Short:   "time 子命令可以打印时间",
        Long:    "time 子命令是tools工具的一大特点,你可以使用time子命令灵活的输出当前时间",
        Example: "tools time [-f format]",
        Run: func(cmd *cobra.Command, args []string) {
            if format != "" {
                fmt.Println(time.Now().Format(format))
                return
            }
            fmt.Println(time.Now())
        },
    }

    timeCmd.Flags().StringVarP(&format, "format", "f", "2006-01-02 15:04:05", "格式化参数,612345")

    rootCmd.AddCommand(timeCmd)
    
    return rootCmd
}

我们使用 go build tools.go, 然后运行:

$ go build tools.go 

$ ./tools time
2020-08-26 16:03:37

$ ./tools time -f "2006/01/02 15:04:05"
2020/08/26 16:03:43

实战完成!


pengdafu
7 声望1 粉丝

人生苦短


引用和评论

0 条评论