Go第三库之命令行框架:go-cli
| 阅读 | 共 2044 字,阅读约
Overview
Go-cli
简介
- A simple, fast, and fun package for building command line apps in Go
- 一个简单的、快速的、并且有趣的用于构建go应用程序的包
- github地址
- 目标是帮助开发人员快速构建易于表达的命令行程序
- 目前存在两个版本v1、v2(新版本)
快速上手
-
- 添加模块依赖
1GO111MODULE=on go get github.com/urfave/cli/v2
-
- 使用
1package main
2
3import (
4 "os"
5 "github.com/urfave/cli/v2"
6)
7
8func main() {
9 (&cli.App{}).Run(os.Args)
10}
-
- 编译:生成可执行文件
1go build
-
- 使用:会打印出帮助文档
1./cse
2NAME:
3 cse - A new cli application
4
5USAGE:
6 cse [global options] command [command options] [arguments...]
7
8COMMANDS:
9 help, h Shows a list of commands or help for one command
10
11GLOBAL OPTIONS:
12 --help, -h show help (default: false)
使用说明
cli.App提供了很多参数,比较重要的几个有:
- Name: 应用程序名称
- Flag:参数信息
- Command:要执行的命令
Arguments
- App可以指定Action函数,action的回调函数参数为cli.Context
- 调用cli.Context的Args方法,可以查看参数
1app := &cli.App{
2 Action: func(c *cli.Context) error {
3 fmt.Printf("Hello %q", c.Args().Get(0))
4 return nil
5 },
6 }
Flag
- App的Flags参数,可以设置相关参数
常用参数
- Name: flag名称
- Aliases:别名,可以指定多个
- Usage:使用说明
- Value:默认值
- Required: 是否是必填值
1app := &cli.App{
2 ...
3 Flags: []cli.Flag{
4 &cli.IntFlag{
5 Name: "c",
6 Aliases: []string{"concurrency"},
7 Usage: "concurrency thread",
8 Value: 5,
9 Destination: &ConcurrencyThread,
10 },
11 },
12}
接收Flag
- Destination参数,用于接收传入的flag值
1app := &cli.App{
2 ...
3 Flags: []cli.Flag{
4 &cli.IntFlag{
5 Name: "c",
6 Aliases: []string{"concurrency"},
7 Usage: "concurrency thread",
8 Value: 5,
9 Destination: &ConcurrencyThread,
10 },
11 },
12}
排序
- Flag的默认排序是代码定义的顺序
- 可以设置为按照名称排序
1func main() {
2 ...
3 sort.Sort(cli.FlagsByName(app.Flags))
4
5 err := app.Run(os.Args)
6 if err != nil {
7 log.Fatal(err)
8 }
9}
读取环境变量值
- 可以为Flag的默认值为环境变量的值
- 环境变量可以设置多个,读取到的第一个有值的环境变量作为默认值
1app := &cli.App{
2 Flags: []cli.Flag{
3 &cli.StringFlag{
4 Name: "repo_url",
5 Usage: "resource repository url",
6 Value: "https://obs.cn-north-4.myhuaweicloud.com",
7 EnvVars: []string{"CSE_REPO_URL"},
8 },
9 },
10}
读取文件值
- 可以设置Flag的默认值为读取的文件中的数据
1app := &cli.App{
2 Flags: []cli.Flag{
3 &cli.StringFlag{
4 Name: "repo_url",
5 Usage: "resource repository url",
6 Value: "https://obs.cn-north-4.myhuaweicloud.com",
7 FilePath: "/etc/cse/repo_url",
8 },
9 },
10}
读取配置文件
有一个单独的包altsrc提供配置文件和flag值的关联,目前支持的文件格式包括:
- Yaml
- Json
- Toml
1// 读取load.yaml文件中的test值,作为flag的值
2func main() {
3 flags := []cli.Flag{
4 altsrc.NewIntFlag(&cli.IntFlag{Name: "test"}),
5 &cli.StringFlag{Name: "load"},
6 }
7
8 app := &cli.App{
9 Action: func(c *cli.Context) error {
10 fmt.Println("yaml ist rad")
11 return nil
12 },
13 Before: altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load")),
14 Flags: flags,
15 }
16
17 app.Run(os.Args)
18}
参数读取的优先级(由高到低)
- 0:用户通过命令行传入的值
- 1:环境变量的值(如果有)
- 2:配置文件的值(如果有)
- 3:Default参数设置的值
Command
- Command参数指定要执行操作的相关信息
- Command的Action指定真正的操作业务逻辑
1app := &cli.App{
2 ...
3 Commands: []*cli.Command{
4 {
5 Name: "download",
6 Aliases: nil,
7 Usage: "download resource by description file(project.json)",
8 Action: func(context *cli.Context) error {
9 return nil
10 },
11 },
12 },
13}
Command排序
- Command的默认排序是代码定义的顺序
- 可以设置为按照名称排序
1func main() {
2 ...
3 sort.Sort(cli.CommandsByName(app.Commands))
4
5 err := app.Run(os.Args)
6 if err != nil {
7 log.Fatal(err)
8 }
9}
子命令 SubCommand
效果:
1./cse download
2NAME:
3 cse download - download resource by description file(project.json)
4
5USAGE:
6 cse download command [command options] [arguments...]
7
8COMMANDS:
9 Installer download installer
10 Yum download yum
11 help, h Shows a list of commands or help for one command
12
13./cse download Installer
14download installer
15
1app := &cli.App{
2 ...
3 Commands: []*cli.Command{
4 {
5 Name: "download",
6 Aliases: nil,
7 Usage: "download resource by description file(project.json)",
8 Subcommands: []*cli.Command{
9 {
10 Name: "Installer",
11 Usage: "download installer",
12 Action: func(context *cli.Context) error {
13 fmt.Println("download installer")
14 return nil
15 },
16 },
17 {
18 Name: "Yum",
19 Usage: "download yum",
20 Action: func(context *cli.Context) error {
21 fmt.Println("download yum")
22 return nil
23 },
24 },
25 },
26 },
27 },
28}
命令分类
- 当有很多command时,可以将相关的command分为一个组,在帮助文档中按组展示
- 只需要添加Category字段即可
1app := &cli.App{
2 Commands: []*cli.Command{
3 {
4 Name: "noop",
5 },
6 {
7 Name: "add",
8 Category: "template",
9 },
10 {
11 Name: "remove",
12 Category: "template",
13 },
14 },
15}
所有的参数
1type App struct {
2 // The name of the program. Defaults to path.Base(os.Args[0])
3 Name string
4 // Full name of command for help, defaults to Name
5 HelpName string
6 // Description of the program.
7 Usage string
8 // Text to override the USAGE section of help
9 UsageText string
10 // Description of the program argument format.
11 ArgsUsage string
12 // Version of the program
13 Version string
14 // Description of the program
15 Description string
16 // List of commands to execute
17 Commands []*Command
18 // List of flags to parse
19 Flags []Flag
20 // Boolean to enable bash completion commands
21 EnableBashCompletion bool
22 // Boolean to hide built-in help command and help flag
23 HideHelp bool
24 // Boolean to hide built-in help command but keep help flag.
25 // Ignored if HideHelp is true.
26 HideHelpCommand bool
27 // Boolean to hide built-in version flag and the VERSION section of help
28 HideVersion bool
29 // categories contains the categorized commands and is populated on app startup
30 categories CommandCategories
31 // An action to execute when the shell completion flag is set
32 BashComplete BashCompleteFunc
33 // An action to execute before any subcommands are run, but after the context is ready
34 // If a non-nil error is returned, no subcommands are run
35 Before BeforeFunc
36 // An action to execute after any subcommands are run, but after the subcommand has finished
37 // It is run even if Action() panics
38 After AfterFunc
39 // The action to execute when no subcommands are specified
40 Action ActionFunc
41 // Execute this function if the proper command cannot be found
42 CommandNotFound CommandNotFoundFunc
43 // Execute this function if an usage error occurs
44 OnUsageError OnUsageErrorFunc
45 // Compilation date
46 Compiled time.Time
47 // List of all authors who contributed
48 Authors []*Author
49 // Copyright of the binary if any
50 Copyright string
51 // Writer writer to write output to
52 Writer io.Writer
53 // ErrWriter writes error output
54 ErrWriter io.Writer
55 // Execute this function to handle ExitErrors. If not provided, HandleExitCoder is provided to
56 // function as a default, so this is optional.
57 ExitErrHandler ExitErrHandlerFunc
58 // Other custom info
59 Metadata map[string]interface{}
60 // Carries a function which returns app specific info.
61 ExtraInfo func() map[string]string
62 // CustomAppHelpTemplate the text template for app help topic.
63 // cli.go uses text/template to render templates. You can
64 // render custom help text by setting this variable.
65 CustomAppHelpTemplate string
66 // Boolean to enable short-option handling so user can combine several
67 // single-character bool arguments into one
68 // i.e. foobar -o -v -> foobar -ov
69 UseShortOptionHandling bool
70
71 didSetup bool
72}
多个参数合并
- 如果有多个参数,传统的方法是分别指定每个参数,比如:-s -o -m
- 通过相关设置,可以将多个参数合并,比如:-som
1app := &cli.App{}
2app.UseShortOptionHandling = true
bash自动补全
- 可以通过EnableBashCompletion设置参数自动补全
- 默认只支持subcommand,可以实现补全方法
BashComplete
支持所有命令自动补全
1app := cli.NewApp()
2app.EnableBashCompletion = true
退出状态
- 调用App.Run不会自动调用os.Exit,这意味着默认的退出码将不会生效,自动变成0
- 如果出错,需要显示的在return之前调用状态码
1app := &cli.App{
2 Flags: []cli.Flag{
3 &cli.BoolFlag{
4 Name: "ginger-crouton",
5 Usage: "is it in the soup?",
6 },
7 },
8 Action: func(ctx *cli.Context) error {
9 if !ctx.Bool("ginger-crouton") {
10 return cli.Exit("Ginger croutons are not in the soup", 86)
11 }
12 return nil
13 },
14}