本文总结了在使用cobra的一些经验
例如 --tenant_id
和 --tenant-id
for _, cmd := range RootCmd.Commands() {
cmd.Flags().SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(strings.ReplaceAll(name, "_", "-"))
})
}
通过调用rootCmd的所有命令的SetNormalizeFunc,使得所有root命令和所有子命令都同时支持中划线参数和下划线参数
同时如果要执行参数名称的大小写不敏感,也可以使用参数这个实现
一般来说,我们如果想实现类似python argparse的中可选变量
parser.add_argument('--admin_state_up', choices=['True', 'False', 'true', 'false'], help=_('admin state of agent'))
如上的python列子中,限制admin_state_up参数只能在四种值中选择,如果输入其他值,则会报错,但是在cobra中,并没有提供内置的choices功能,可以通过自定义类型来实现这个功能
type AdminStateUp string
var Choices = []string{"True", "true", "False", "false"}
func (f *AdminStateUp) Set(value string) error {
for _, choice := range Choices {
if value == choice {
*f = AdminStateUp(choice)
}
}
return fmt.Errorf("%s is ivalid, choice=%v", value, Choices)
}
func (f *AdminStateUp) String() string {
return fmt.Sprintf("%v", *f)
}
func (f *AdminStateUp) Type() string {
return "string"
}
使用方法
adminStateUp := AdminStateUp("")
RootCmd.Flags().Var(&adminStateUp, "admin-state-up", "set admin state up")
如果输入非预期的值,会报如下错误
Error: invalid argument "TRue" for "--admin-state-up" flag: TRue is ivalid, choice=[True true False false]
使用自定义类型也可以非常方便的实现参数输入校验,而不用在也业务逻辑搅合在用一起
对于cobra子命令来说,默认的usage不仅会显示自己的参数,还会显示parent命令的参数,如果只是想显示自己的参数,那么可以通过两种方法来自定义usage的显示
方法一 通过设置usage模版
SetUsageTemplate
至于模版改如何编写,可以参考 https://github.com/spf13/cobra/issues/1995
方法二 使用SetUsageFunc来自定义输出
这个我们在下一后面会讲到如何通过这个方法来实现参数分组
在python的argparse中,可以很方便的实现参数分组,如下效果所示
output formatters:
output formatter options
-f {csv,json,table,value,yaml}, --format {csv,json,table,value,yaml}
the output format, defaults to table
CSV Formatter:
--quote {all,minimal,none,nonnumeric}
when to include quotes, defaults to nonnumeric
那么在cobra中如何实现这样的效果呢,诀窍就是我们前面讲过的SetUsageFunc方法。我们可以在SetUsageFunc中自定义usage输出,废话不多说,完整的例子如下
package main
import (
"fmt"
"os"
"strings"
"unicode"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
type NameFlagSet struct {
name string
desc string
fs *pflag.FlagSet
}
var nameFlagSets []NameFlagSet
func main() {
RootCmd := &cobra.Command{
Use: "hello",
Short: fmt.Sprintf("Commands for Hello"),
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if cmd.Flags().Changed("version") {
os.Exit(0)
}
},
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
SilenceUsage: true,
}
fs1 := pflag.NewFlagSet("output formatters", pflag.ExitOnError)
fs1.StringP("format", "p", "json", "the output format, defaults to table")
fs2 := pflag.NewFlagSet("cvs formatter", pflag.ExitOnError)
fs2.String("quote", "", "when to include quotes, defaults to nonnumeric")
RootCmd.Flags().AddFlagSet(fs1)
RootCmd.Flags().AddFlagSet(fs2)
nameFlagSets = append(nameFlagSets, NameFlagSet{
name: "output formatters",
desc: "output formatter options",
fs: fs1,
})
nameFlagSets = append(nameFlagSets, NameFlagSet{
name: "CSV Formatter",
fs: fs2,
})
RootCmd.SetUsageFunc(func(cmd *cobra.Command) error {
if cmd == nil {
return fmt.Errorf("nil command")
}
usage := []string{fmt.Sprintf("Usage: %s", cmd.UseLine())}
if cmd.HasAvailableSubCommands() {
usage = append(usage, "\nCommands:")
for _, subCommand := range cmd.Commands() {
usage = append(usage, fmt.Sprintf(" %-10s %s", subCommand.Name(), subCommand.Short))
}
}
for _, nfs := range nameFlagSets {
usage = append(usage, fmt.Sprintf("\n\033[4m%s:\033[0m", nfs.name))
if nfs.desc != "" {
usage = append(usage, fmt.Sprintf(" %s", nfs.desc))
}
usage = append(usage, strings.TrimRightFunc(nfs.fs.FlagUsages(), unicode.IsSpace))
}
usage = append(usage,
fmt.Sprintf("\nUse '%s [command] --help' for more information about a command.\n",
cmd.CommandPath()))
cmd.Println(strings.Join(usage, "\n"))
return nil
})
if err := RootCmd.Execute(); err != nil {
os.Exit(1)
}
}
输出
Usage: hello [flags]
output formatters:
output formatter options
-p, --format string the output format, defaults to table (default "json")
CSV Formatter:
--quote string when to include quotes, defaults to nonnumeric
Use 'hello [command] --help' for more information about a command.
原理:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。