gin框架实践连载番外篇 | 打造命令行工具

3,803 阅读3分钟

引言

  • 常规来讲,命令行工具对于一个框架是蛮有用的,将很多重复性的工作提取到命令行,执行命令,比如生成Model,生成控制器,生成路由等等
  • go标准库flag是用来解析命令行参数的包
  • 不过我们选择cobra来构建我们的命令行工具,非常多知名的开源项目使用了 cobra 库构建命令行,如Kubernetes、Hugo、etcd等等等等。
  • 案例代码地址

初始化

1. 安装cobra工具

    go get github.com/spf13/cobra
    
    通常会安装到gopath目录下的bin目录
    

2. 初始化

	cobra init --pkg-name=mycmd

会新建一个mycmd目录

  ▾ mycmd/
    ▾ cmd/
       root.go
      main.go

3. 添加一个emial子命令

	cobra add email

2.特性

1. 基本概念

  • 命令(Command):就是需要执行的操作;
  • 参数(Arg):命令的参数,即要操作的对象;
  • 选项(Flag):命令选项可以调整命令的行为

2. 命令

在 cobra 中,命令和子命令都是用Command结构表示的。Command有非常多的字段,用来定制命令的行为。 在实际中,最常用的就那么几个。

  • Use 指定使用信息,即命令怎么被调用,格式为name arg1 [arg2]。name为命令名,后面的arg1为必填参数,arg3为可选参数,参数可以多个。
  • Short 简短描述
  • Long 长描述
  • Run 实际执行的函数
  • Example 使用案例

3. 选项

cobra 使用pflag解析命令行选项。pflag使用上基本与flag相同

  • 全局选项 定义它的命令和其子命令都可以使用

      rootCmd.PersistentFlags().StringVar(&cfgFile, "config", cfgFile, "config file (default is $HOME/.mycmd.toml)")
    
  • 局部选项 只能定义的字命令使用

	localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")

3、完善email子命令


package cmd

import (
	"fmt"
	"log"
	"net/smtp"

	"github.com/jordan-wright/email"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var (
	To  []string
	Cc  []string
	Bcc []string
	//主题
	Subject string
	//内容
	Text string
	//html内容(优先)
	HTML string
	//抄送附件
	AttachFileName string
	From           string
	Smtp           string
	Port           int
	Password       string
)

// emailCmd represents the email command
var emailCmd = &cobra.Command{
	Use:   "email",
	Short: "发送邮件",
	Long:  `为了更便捷的发送邮件`,
	Example: `
	基础发送:mycmd email -c "内容" -t "youremail"
	抄送:mycmd email -c "签到" -t "youremail" --cc "yourccemail"
	私密抄送:mycmd email -c "签到" -t "youremail" --bcc "yourcccemail"
	发送html:mycmd email -c "签到" -t "youremail" --html='<a href="http://www.baidu.com">点击</a>'
	发送附件:mycmd email -c "签到" -t "youremail" --file="./cmd.toml.example"
	`,
	Run: func(cmd *cobra.Command, args []string) {
		send()
	},
}

func init() {
	emailCmd.Flags().StringSliceVarP(&To, "to", "t", []string{}, "send email to")
	emailCmd.Flags().StringSliceVar(&Cc, "cc", []string{}, "send email Cc")
	emailCmd.Flags().StringSliceVar(&Bcc, "bcc", []string{}, "send email Bcc")
	emailCmd.Flags().StringVarP(&Subject, "subject", "s", "默认主题", "send email Subject")
	emailCmd.Flags().StringVarP(&Text, "context", "c", "", "send email Text")
	emailCmd.Flags().StringVar(&HTML, "html", "", "send email HTML contect")
	emailCmd.Flags().StringVar(&AttachFileName, "file", "", "send email AttachFile")
	emailCmd.MarkFlagRequired("to")
	emailCmd.MarkFlagRequired("context")
	rootCmd.AddCommand(emailCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// emailCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// emailCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

func send() {
	From = viper.GetString("email.from")
	Smtp = viper.GetString("email.smtp")
	Port = viper.GetInt("email.port")
	Password = viper.GetString("email.password")

	e := email.NewEmail()
	e.From = From
	e.To = To
	e.Cc = Cc
	e.Bcc = Bcc
	e.Subject = Subject
	e.AttachFile(AttachFileName)
	if HTML != "" {
		e.HTML = []byte(HTML)
	} else {
		e.Text = []byte(Text)
	}
	auth := smtp.PlainAuth("", From, Password, Smtp)
	addr := fmt.Sprintf("%s:%d", Smtp, Port)
	err := e.Send(addr, auth)
	if err != nil {
		log.Fatal("email ", err)
	}

	log.Println("发送成功")
}

4、测试命令

  1、编译程序 go build .
  2、按照示例执行 ./mycmd email -c "内容" -t "baichonghua@urthink.com"

5、其它

  • 验证选项必填使用 MarkFlagRequired

cobra 还提供了非常丰富的特性和定制化接口,例如:设置钩子函数,在命令执行前、后执行某些操作;生成 Markdown/ReStructed Text/Man Page 格式的文档等等,有需要的朋友自行研究

6、参考

  1. Go每日一库之cobra
  2. email

7、系列文章