DevopsCamp 第一期作业: 《cobra - 03 交互式命令(简单)》 解题答案
原文链接: tangx.in/posts/2023/…
本文为 DevOpsCamp 实战训练作业 cobra - 03 配置文件的读取与写入(简单) 的解题答案
DevoOpsCamp 作业地址: www.devopscamp.cc/semi-plan-2…
作业: cobra - 03 交互式命令
要求:
-
使用 github.com/spf13/cobra 实现命令工具
-
使用 github.com/go-survey/s… 实现交互式命令
-
实现 Demo 效果
除了官方效果之外, 我还发现了 aliyun 命令行工具在配置账户的时候使用的是 交互式 , 如下
为了更好的体现 实战性, 我们将以 aliyun configure --profile 的作为例子, 并进行一些优化。
解题过程
1. 安装 survey 依赖
这是一个意外收获, survey 库的 Github 地址与 go module 名称不一致。 同时, survey 版本还是 v2 了。
关于 go module version , 参考文章: go.dev/doc/modules…
话说回来, 虽然 github 仓库地址是 https://github.com/go-survey/survey , 但安装库需要使用命令
$ go get -u github.com/AlecAivazis/survey/v2
在 go.mod 第一行中, 也可以看到 module 的名称
module github.com/AlecAivazis/survey/v2
平时在使用的时候, 应该多注意官方文档的 Usage、 exmaple 或者 _test.go 等。
2. 需要使用的交互组件
survey 提供了很多组件类型以及 Option 参数、 验证器 等功能,非常全面。 在这里简单介绍常用的几种
Input组件: 普通输入框, 输入什么就显示什么。Password组件: 密码输入框, 输入的内容不直接显示, 使用*替代。Select组件: 单选框。MultiSelect组件: 多选框, 结果为 切片 类型。Confirm组件: 确认框, 结果为 布尔 类型。
更多其它组件, 可以参考官方文档。
3. 代码片段
参考 aliyun 命令行, 我们自己实现的功能需要以下字段。
- Access Secret ID
- Access Secret Key
- Region
- Language
代码中, 创建了 匿名 struct , 并创建 实例 赋值给 answers
answers := struct {
ID string
Key string
ChinaRegion string `survey:"region"`
Language []string
}{}
其中 ChinaRegion 字段通过 tag survey:"region" 指定了一个映射名字 region。 回想一下, 这种用法是不是和上一篇配置文件中的 json, yaml 字段的映射名字用法一样?
另一方面, 我们还准备了一系列问题, 引导用户输入
// the questions to ask
var qs = []*survey.Question{
{
// 1. Input 输入框
Name: "id",
Prompt: &survey.Input{
Message: "Access Secret ID: ",
},
Validate: survey.Required,
},
{
// 2. Password 密码输入框
Name: "key",
Prompt: &survey.Password{
Message: "Access Secret Key: ",
},
Validate: survey.Required,
},
{
// 3. Select 单选框
Name: "region",
Prompt: &survey.Select{
Message: "Choose a region:",
Options: []string{"cn-shanghai", "cn-hangzhou"},
Default: "cn-hangzhou",
},
},
{
// 4. MultiSelect 多选框
Name: "language",
Prompt: &survey.MultiSelect{
Message: "Supported Configure Language: ",
Options: []string{"zh", "en", "jp"},
},
},
}
qs中的Name名称与answers中的字段名称都是一一对应的。- 在
id和key字段, 设置了验证器, 要求 必须提供。 - 在
region字段, 设置cn-hangzhou为默认值, 虽然在切片中排在第二位。
另外, 我们还使用 Confirm 组件引导用户确认是否将输入内容保存到文件中。 由于 保存确认 并不需要保存到配置文件中, 因此我们将其单独封装在了 confirm 函数中。
func confirm() bool {
ok := false
// 5. Confirm 确认框
prompt := &survey.Confirm{
Message: "是否保存文件?",
}
survey.AskOne(prompt, &ok)
return ok
}
4. JSON MashralIndent
为了更好的可读性, 这次在保存配置文件的时候, 使用了 MarshalIndent 方法。
{
"ID": "AKID-demodemo-adsfasdf",
"Key": "flasjdflaksdjf",
"ChinaRegion": "cn-shanghai",
"Language": [
"zh",
"en"
]
}
5. 全局 profile 字段
你可能已经注意到了, 目前所有的代码都在 main 包下面, 并没有 划分目录结构。
var profile string
因此定义的 profile 是全局变量, 可以在 任意位置 直接使用。
但是我们在使用的时候并没有在函数中直接使用, 而是通过 函数参数 的方式传递下去的。 这是我们 刻意 回避直接在 dumpConfig 中直接使用 全局的profile 的。
关于 目录结构 我们将会在后面的作业中提到。
var root = &cobra.Command{
Use: "aliyunx",
Short: "aliyun 配置中心",
Run: func(cmd *cobra.Command, args []string) {
// 1. 使用全局 profile
interactive(profile)
},
}
func interactive(profile string) {
// 2. 参数传递
dumpConfig(profile, answers)
}
func dumpConfig(profile string, answer any) {
// 3. 参数传递
name := fmt.Sprintf("%s.config.json", profile)
err2 := os.WriteFile(name, b, os.ModePerm)
if err2 != nil {
panic(err2)
}
}
效果展示
互相吹捧, 共同进步
欢迎和我一起学习进步:可以在掘金私信我
DevOpsCamp星球 是一个完全免费的学习星球。 每月1日和15日 发布作业和扩展阅读文章。 其存在的意义是 帮助和引导 那些愿意学习的人。 想睡的人叫不醒, 想走的人留不住