ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 底层库的选择 Go 的命令行底层库有两个非常知名的选项: * [github.com/urfave/cli](https://github.com/urfave/cli)一万多 star * [github.com/spf13/cobra](https://github.com/spf13/cobra)两万多 star Gohub 项目里,我们将选择 star 数更高的 cobra 项目。cobra 功能比较强大,设计优良,最重要的**它支持全局选项**。 cli 库做不到`--env`参数后加子命令,例如说: ~~~php # 指定加载 .env.testing 设定的环境变量来运行 migrate 子命令 $ gohub --env=testing migrate ~~~ 主要还是跟其实现方式有关,cli 依赖于官方的 flag 包。而 flag 包的逻辑是会把`--env`参数后面的所有内容都当做选项的值,详细的讨论请见[github.com/urfave/cli/issues/427](https://github.com/urfave/cli/issues/427)。 Cobra 使用的是自己实现的选项解析器 ——[github.com/spf13/pflag](https://github.com/spf13/pflag),故不存在此问题。 另外一个 cli 的不足之处是不支持全局选项,无法满足我们全局选项`--env`的需求。 ## cobra.Command struct 在 Cobra 里,所有命令都是一个 cobra.Command 的实现。一个简单示例: ~~~php var CmdMakeSeeder = &cobra.Command{ Use: "seeder", Short: "Create seeder file, example: make seeder user", Run: runMakeSeeder, Args: cobra.ExactArgs(1), // 只允许且必须传 1 个参数 } ~~~ 下面是一个 cobra.Command 的注释,基本上涵盖 Cobra 的大部分功能点: ~~~php // Command代表执行命令的结构 type Command struct { // 代表当前命令的,如何执行,root 最好和生成的命令工具名称一致 Use string // 代表这个工具的别名,在 subCommand 中有用,比如 root cmd1 和 root cmd_1 想要都执行一个 subCommand 就需要这样 Aliases []string // 由于不强制设置,用于输入错误的时候建议字段 SuggestFor []string // 这个就是在 help 的时候一句话描述这个命令的功能 Short string // 详细描述这个命令的功能 Long string // 例子,调用示例 Example string // 参数白名单(非 flag),只允许传这里定制的参数 // 此处的参数被被自动补全 ValidArgs []string // 参数验证器(可设置不接受参数,或者最多、最少参数) Args PositionalArgs // 参数别名 ArgAliases []string // 自动补全的命令设置,只能在 root 命令设置 BashCompletionFunction string // 如果这个命令已经废弃了,那么就这里写上废弃信息 Deprecated string // 如果这个命令要被隐藏,设置这个字段 Hidden bool // 设置命令分组注释 Annotations map[string]string // 设置命令的版本 Version string // The *Run 函数运行顺序: // * PersistentPreRun() // * PreRun() // * Run() // * PostRun() // * PersistentPostRun() // 会被子命令继承的前置 Run PersistentPreRun func(cmd *Command, args []string) // 会被子命令继承的前置 Run, 带 error PersistentPreRunE func(cmd *Command, args []string) error // 当前这个命令的前置 Run PreRun func(cmd *Command, args []string) // 当前这个命令的前置 Run,带 Error PreRunE func(cmd *Command, args []string) error // zh: 实际跑的时候运行的函数 Run func(cmd *Command, args []string) // zh: Run 执行错误了之后 RunE func(cmd *Command, args []string) error // 后置运行 PostRun func(cmd *Command, args []string) // 后置运行,带 error PostRunE func(cmd *Command, args []string) error // 会被子命令继承的后置运行 PersistentPostRun func(cmd *Command, args []string) // 会被子命令继承的后置运行,带 error PersistentPostRunE func(cmd *Command, args []string) error // 是否要打印错误信息 SilenceErrors bool // 是否关闭使用建议(当命令不存在,或参数有误时) SilenceUsage bool // 是否有 flag,如果这个命令没有 flag,设置为 true,那么所有的命令后面的参数都会是 arguments DisableFlagParsing bool // 生成文档时,是否打印自动生成字样: ("Auto generated by spf13/cobra...") DisableAutoGenTag bool // 是否显示[flags]字样 DisableFlagsInUseLine bool // 是否打印建议,当命令行出错时,匹配字数,然后给出建议的命令,提高用户体验 DisableSuggestions bool // 多少个字才会触发 suggest,必须大于 0 SuggestionsMinimumDistance int // 是否使用 Traverse 的方式来解析参数 TraverseChildren bool // 解析错误白名单, 比如像未知参数 FParseErrWhitelist FParseErrWhitelist } ~~~ ## 命令钩子 重点关注下 cobra 命令的钩子: ~~~php // The *Run 函数运行顺序: // * PersistentPreRun() // * PreRun() // * Run() // * PostRun() // * PersistentPostRun() // 会被子命令继承的前置 Run PersistentPreRun func(cmd *Command, args []string) // 会被子命令继承的前置 Run, 带 error PersistentPreRunE func(cmd *Command, args []string) error // 当前这个命令的前置 Run PreRun func(cmd *Command, args []string) // 当前这个命令的前置 Run,带 Error PreRunE func(cmd *Command, args []string) error // zh: 实际跑的时候运行的函数 Run func(cmd *Command, args []string) // zh: Run 执行错误了之后 RunE func(cmd *Command, args []string) error // 后置运行 PostRun func(cmd *Command, args []string) // 后置运行,带 error PostRunE func(cmd *Command, args []string) error // 会被子命令继承的后置运行 PersistentPostRun func(cmd *Command, args []string) // 会被子命令继承的后置运行,带 error PersistentPostRunE func(cmd *Command, args []string) error ~~~