命令行管理痛点
- 需要手动传入硬编码的参数索引或者选项名称信息来获取数据
- 难以定义参数/选项的说明介绍
- 难以定义参数/选项的数据类型
- 难以对参数/选项进行通用性的数据校验
- 对于需要管理大量命令行的项目是个灾难
对象化管理命令
我们来一个最简单的结构化管理参数示例。我们将前面介绍过的Command
示例改造为结构化管理:
可以看到,我们通过对象的形式来管理父级命令,通过方法的形式来管理其下一层级的子级命令,并通过规范化的Input
输入参数对象来定义子级命令的描述/参数/选项。大部分场景下,大家可以忽略Output
返回对象的使用,但为规范化及扩展性需要保留,如果未用到,该返回参数直接返回nil
即可。关于其中的结构体标签,后续会有介绍。
我们将示例代码编译后,执行查看效果:
USAGE
main COMMAND [OPTION]
COMMAND
http start http server
grpc start grpc server
DESCRIPTION
this is the command entry for starting your process
使用http
命令:
使用grpc
命令:
$ main grpc
start grpc server
效果和前面介绍的示例一致。
结构化管理入参
我们将上面的实例简化一下,来个简单的例子,实现通过http
命令开启http
服务:
我们为http
命令定义了两个输入参数:
NAME
服务的名称,通过参数输入。这里使用了大写形式,方便展示在自动生成的帮助信息中port
服务的端口,通过p/port
选项输入
并且我们通过校验标签为这两个参数都绑定的必需的校验规则。是的,在GoFrame
框架中,只要涉及到校验的地方都使用了统一的校验组件,具体请参考章节:数据校验
我们编译后执行看看效果:
arguments validation failed for command "http": The Name field is required
1. arguments validation failed for command "http"
1). github.com/gogf/gf/v2/os/gcmd.newCommandFromMethod.func1
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_object.go:290
2). github.com/gogf/gf/v2/os/gcmd.(*Command).doRun
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go:120
3). github.com/gogf/gf/v2/os/gcmd.(*Command).RunWithValueError
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go:77
4). github.com/gogf/gf/v2/os/gcmd.(*Command).RunWithValue
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go:32
5). github.com/gogf/gf/v2/os/gcmd.(*Command).Run
/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go:26
6). main.main
2. The Name field is required
执行后,报错了,这个错误来自于数据校验,表示必须参数(Name/Port
)必须传递。
这里的报错打印了堆栈信息,因为GoFrame
框架采用了全错误堆栈设计,所有组件错误都会带有自底向上的错误堆栈,以方便错误快速定位。当然我们可以通过RunWithError
方法获取返回的错误对象关闭堆栈信息。
是的,这就对了。
完整使用案例
GoFrame
框架的开发工具普通使用了对象化、结构化的命令行管理,大家感兴趣可以更进一步查看源码了解:https://github.com/gogf/gf/tree/master/cmd/gf
预定义的标签
在结构化设计中,我们使用了一些结构体标签,大部分来源于Command
命令的属性,这里我们来介绍一下:
高级特性
结构化的参数输入支持自动的数据类型转换,您只需要定义好数据类型,其他的事情交给框架组件即可。自动数据类型转换出现在框架的很多组件中,特别是HTTP/GRPC
服务的参数输入中。底层数据转换组件使用的是:类型转换
命令行参数的数据转换采用不区分大小写、且忽略特殊字符的规则来匹配属性字段。例如,如果入参结构体中存在Name
字段属性,无论命令行输入name
还是NAME
的命名参数,都将能被Name
字段属性接收。
当命令行中没有传递对应的数据时,输入参数的结构体数据支持从配置组件中自动获取,只需要在Meta
中设置标签即可,配置来源于默认的全局单例配置对象。具体示例可以参考GoFrame
框架开发工具源码: