Cobra 命令自动补全指北
前言
用过类 Unix 系统中 Unix shell (Shell/Bash/Zsh) 的同学都应该对 TAB 键印象深刻,因为它可以帮忙补全或提示后续的命令,用户不用记住完整的命令,只需输入前几个字符,按 TAB 键,就会提示后续的命令供用户选择,用户体验极佳。目前流行的一些使用 Go 语言开发的 CLI 工具,如 kubectl
和 helm
,他们也都有 completion
也就是命令自动补全功能,通过将 source <(kubectl completion zsh)
加入 .zshrc
文件中,就可以在每次启动 shell 时自动加载自动补全脚本,之后就可以体验到与原生 shell 相同的自动补全功能了。这些 CLI 工具,都是基于 Cobra[1] 库开发,命令自动补全功能也是该库提供的一个功能,本篇文章就来讲讲如何使用 Cobra 实现命令自动补全的。
Cobra Shell Completion
Cobra 可以作为一个 Golang 包,用来构建功能强大的命令行程序;同时也可以作为 CLI 工具,用来生成应用程序和命令文件。
由于文本主要介绍 Cobra 的命令自动补全功能,更多内容请查阅官网[2]。
基础用法
Cobra 当前的最新版本为 v1.0.0
,支持生成多种 Shell 的自动补全脚本,目前支持:
Bash
Zsh
Fish
PowerShell
如上所述,Cobra 不但是一个功能强大的 Golang 包,还是一个 CLI 工具,可以用来生成应用程序和命令文件。使用如下命令,即可生成用于命令自动补全的代码:
或者也可以创建 cmd/completion.go
文件,来放置用于生成命令自动补全脚本的代码:
官方推荐将生成内容输出到 os.Stdout
,只需上面这些简单的命令,即可在你的 CLI 工具中新增 completion
子命令,执行该命令即可生成相应 Shell 的命令自动补全脚本,将其插入或保存到相应 Shell 的指定位置即可实现命令自动补全功能。
如果加载了配置文件,
os.Stdout
可能会打印多余的信息,这会导致自动补全脚本失效,所以请避免这种情况。
进阶用法
上面的这些只是基本用法,完成的只是命令补全的基本功能,但一些定制化的需求是无法实现的。比如,kubectl get [tab]
这里的预期内容是返回所有 k8s 资源名称,但是只靠上面的代码是无法实现的。这里就需要用到自定义补全,通过为每个命令增加不同的参数或方法,可以实现静态和动态补全等功能。
名称补全
名称补全其实也分静态名称和动态名称,静态名称就像 kubectl completion [tab]
预期返回的多种 shell 名称,内容为事先在代码中已经定义好的内容;而动态名称,就是像 helm status [tab]
预期返回的所有 release 名称,并不是以静态内容体现,而是通过函数动态获取的内容。
静态名称补全
静态名称补全比较简单,只要在想要自动补全的子命令中加入 ValidArgs
字段,传入一组包含预期结果的字符串数组即可,代码如下:
这里是模仿 kubectl 的 get
子命令,在执行该命令时效果如下:
如果命令有别名(Aliases)的话,则可以使用 ArgAliases
,代码如下:
别名不会在按 TAB 时提示给用户,但如果手动输入,则补全算法会将其视为有效参数,并提供后续的补全。
这里如果不声明 rc
为别名,则补全算法将无法补全后续的内容。
动态名称补全
如果需要补全的名称是动态生成的,例如 helm status [tab]
这里的 release
值,就需要用到 ValidArgsFunction
字段,将需要返回的内容以 function 的形式声明在 cobra.Command
中,代码如下:
上面这段代码是 helm
的源码,也是 Cobra 的官方示例代码,很好的展示了这个 function 的结构及返回格式,有兴趣的同学可以去看一下 helm
的源码,也是很有意思的。getReleasesFromCluster
方法是用来获取 Helm release 列表,在执行命令时,效果如下:
cobra.ShellCompDirective
可以控制自动补全的特定行为,你可以用或运算符来组合它们,像这样 cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
,下面是它们的介绍(摘自官方文档):
ValidArgs
和ValidArgsFunction
同时只能存在一个。在使用ValidArgsFunction
时,Cobra 将在解析了命令行中提供的所有 flag 和参数之后才会调用您的注册函数。
Flag 补全
指定必选 flag
大多时候,名字补全只会提示子命令的补全,但如果一些 flag 是必须的,也可以在用户按 TAB 键时进行自动补全,代码如下:
然后在执行命令时,就可以看到:
动态 flag
同名称补全类似,Cobra 提供了一个字段来完成该功能,需要使用 command.RegisterFlagCompletionFunc()
来注册自动补全的函数,代码如下:
RegisterFlagCompletionFunc()
是通过 command
与该 flag 的进行关联的,在本示例中可以看到:
使用方式和名称补全相同,这里就不做详细介绍了。
Debug
命令自动补全与其他功能不同,调试起来比较麻烦,所以 Cobra 提供了调用隐藏命令,模拟自动补全脚本的方式来帮助调试代码,你可以直接使用以下隐藏命令来模拟触发:
如果需要提示名称而非补全(就是输入命令后直接按 TAB 键),则必须将空参数传递给 __complete
命令:
同样可以用来调试 flag 的自动补全:
结语
以上内容是作者挑选的一些较为常用的功能,更多的内容详见官方文档[3]。如果想看示例的话,推荐 kubectl[4] 和 helm[5] 的源码。
当然 Cobra 还不是完美的,比如生成的 Zsh 脚本有些问题,kubectl
和 helm
都是使用将其生成的 Bash 自动补全脚本转化为 Zsh 的自动补全脚本的方式。但不得不承认,Cobra 是一个非常好用的 CLI 工具构建框架,很多流行的 CLI 工具都是使用它来构建的,这也是为什么使用 GO 语言编写的 CLI 工具如雨后春笋般快速的出现并占据了云原生工具的关键位置。
参考
版权声明: 本文为 InfoQ 作者【郭旭东】的原创文章。
原文链接:【http://xie.infoq.cn/article/7892e4dcd37e04988edf15277】。文章转载请联系作者。
评论