Go技巧 - 经典命令行工具库cobra
cobra简介
Go
程序的主流交付的形式为2种:服务端程序与命令行工具。服务端程序一般长期运行在服务器上,而命令行工具则往往是一次性运行的,又被称为CLI
,即client
客户端的简写。
CLI
工具的开发不难,但要做到方便易用,类似于Kubernetes
的kubectl
,还是非常考验开发能力的。今天,我介绍一款开发命令行程序的利器 - cobra。
cobra
的安装命令如下:
1 | go get -u github.com/spf13/cobra@latest |
初始化
cobra init
可以快速地初始化一个程序:
1 | 初始化 go module |
接下来,我会从结构与功能两个层面,对cobra
进行介绍:
结构
新增子命令
1 | 新增子命令 create和delete |
在运行完上述两个命令后,我们编译一下程序,尝试着运行一下这个工具:
1 | [root@localhost] ./cobra-demo -h |
相关的提示已经自动添加了。而整体的代码架构也很清晰:
1 | - cmd/ |
新增多级子命令
当工具变得复杂时,多级命令的可读性会比较棒,cobra
也支持这个功能。假设我们要对上述的 cobra-demo create
增加一种mock
机制,即和正常创建方式区分开来,那么我们就可以运行以下命令:
1 | p即parent,对应的父命令 |
整个文件目录就成了
1 | - cmd/ |
重新编译后,命令行工具运行create
时多了一个子命令提示:
1 | [root@localhost] ./cobra-demo create |
功能
参数解析
cobra
工具在生成时,支持对每一个命令进行参数解析。官方在生成代码时提供了示例:
1 | var ( |
这里的注释写得很清楚,参数分为2类:
Persistent Flags
- 对该命令以及它的所有子命令生效Local Flags
- 仅对该命令生效
在复杂命令行工具的开发中,Flag
经常会变得很多、很乱,我有两点建议:
- 用增加子命令的方式来减少入参的数量:参数越多,往往会让使用变得复杂性;而子命令相对而言更容易理解
- 特殊的功能单独开放一个子命令:隔离复杂度
Command钩子
cobra
最核心的能力都放在结构体cobra.Command
里,内部包含了诸多可自定义的能力,如简写、数据校验、版本等,而最核心的运行逻辑则是为以下5步(按顺序执行):
- PersistentPreRun()
- PreRun()
- Run()
- PostRun()
- PersistentPostRun()
如果想要支持返回error
,则将XXXRun()
调整为XXXRunE()
即可。cobra
是一个开放的、普适性的工具,我们在使用它的特性时需要节制,才能保证后续的可维护性,例如:
- 如果有复杂的业务功能,独立到另一个
package
中单独维护; - 如果有数据一致性的要求,就尽量维护在一个命令中操作,如
Run
;
一般建议在cobra
命令层做的只做三件事:提高命令的可读性、解析参数 与 校验参数的基本格式。
小结
cobra
工具是帮助开发者构建CLI
程序的一款利器,核心优势在于能大幅度地提升使用者的体验(尤其是结合了Terminal中命令自动填充、美化等扩展能力)。
而在复杂项目中,则应提前考虑分层设计:隔离cobra
生成代码与人工编写的业务代码 - 前者是命令式地执行,后者更需要抽象。
编程思考 - 以终为始的思维方式
以终为始,初听像是一个只停留于方法论的词汇,但它所代表的思维方式是非常有意义的。
以接口的两种风格为例:命令式 像是指挥者,必须很清楚内部的各项实现,然后指挥系统一步一步执行;而声明式则是告诉平台自己所期望的最终状态,而不关心其内部具体是怎么实现的。
命令式固然是一个很棒的解决方案,可以明确地指导我们达成目标,但过程中往往会遇到各种瓶颈,导致最终结果产生偏差;而声明式则是一种“以终为始”的解决方式,先明确自己的最终目标是什么,再逐步探索达到目标的路径。也许两者最终的效果一致,但“以终为始”的方式能让我们更聚焦于目标,减少过程中的损耗。
我们的开发工作也十分类似。过程中存在诸多的不确定性,未达预期是一种常态。以终为始的思路,能让我们减少复杂过程中的损耗。
工作生活 - 资产配置
最近我开始接触理财相关的概念,其中印象最为深刻的是 4321原则,即
- 40%投资
- 30%生活开销
- 20%储蓄备用
- 10%保险
各位如果和我一样是个理财新手,不妨先按这种方式梳理一下个人或家庭的资产情况。这个理论提供的只是参考值,真正的执行可以按需调整,重点是要有长期的投资思想,如个人成长、房地产、股票,在人生的不同阶段有不同选择。
Github: https://github.com/Junedayday/code_reading
Blog: http://junes.tech/
Bilibili: https://space.bilibili.com/293775192
公众号: golangcoding