Golang中如何在子命令前使用Cobra框架处理可变参数
Golang中如何在子命令前使用Cobra框架处理可变参数 我是一名Go语言新手,尽管我已经用其他语言编写代码几十年了。
我正在考虑编写类似“kubectl”的工具,但其中总是有一个代表上下文的首个参数,然后是子命令,接着是选项标志。
也有可能只存在上下文名称,没有子命令,这将代表一个“隐含”的子命令,用于打印给定上下文名称作为子字符串的上下文名称列表。
我不确定如何使用Cobra构建类似这样的东西。是否有合理的方法来修改默认结构以实现此目的?
1 回复
更多关于Golang中如何在子命令前使用Cobra框架处理可变参数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Cobra框架中处理可变参数并实现类似kubectl的上下文参数模式,可以通过自定义参数验证和命令执行流程来实现。以下是一个实现示例:
package main
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
)
var contexts = []string{"prod-cluster", "staging-cluster", "dev-cluster", "test-cluster"}
func main() {
var rootCmd = &cobra.Command{
Use: "myctl",
Short: "A kubectl-like tool with context parameter",
// 禁用默认的参数验证,我们将自定义处理
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// 处理没有子命令的情况
if len(args) == 0 {
// 显示所有上下文
fmt.Println("Available contexts:")
for _, ctx := range contexts {
fmt.Printf(" %s\n", ctx)
}
return nil
}
// 第一个参数是上下文
context := args[0]
// 如果没有子命令,执行隐式子命令
if len(args) == 1 {
// 查找匹配的上下文
fmt.Printf("Contexts matching '%s':\n", context)
for _, ctx := range contexts {
if strings.Contains(ctx, context) {
fmt.Printf(" %s\n", ctx)
}
}
return nil
}
// 如果有子命令,将上下文传递给子命令
// 这里需要手动执行子命令
cmd.SilenceUsage = true
return fmt.Errorf("use 'myctl %s [command]'", context)
},
}
// 添加子命令
var getCmd = &cobra.Command{
Use: "get [resource]",
Short: "Get resources",
Run: func(cmd *cobra.Command, args []string) {
// 上下文通过父命令的PersistentFlags获取
context, _ := cmd.Parent().PersistentFlags().GetString("context")
fmt.Printf("Getting resources in context: %s\n", context)
fmt.Printf("Resource: %v\n", args)
},
}
var describeCmd = &cobra.Command{
Use: "describe [resource]",
Short: "Describe resource",
Run: func(cmd *cobra.Command, args []string) {
context, _ := cmd.Parent().PersistentFlags().GetString("context")
fmt.Printf("Describing resource in context: %s\n", context)
fmt.Printf("Resource: %v\n", args)
},
}
// 创建带上下文的命令包装器
for _, ctx := range contexts {
ctxCmd := &cobra.Command{
Use: ctx,
Short: fmt.Sprintf("Commands for context %s", ctx),
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// 设置上下文标志
cmd.PersistentFlags().Set("context", cmd.Name())
},
}
// 为每个上下文添加子命令
ctxCmd.AddCommand(getCmd, describeCmd)
// 添加上下文特定的标志
ctxCmd.PersistentFlags().String("namespace", "default", "Namespace for this context")
rootCmd.AddCommand(ctxCmd)
}
// 添加全局标志
rootCmd.PersistentFlags().String("context", "", "Context to use")
rootCmd.PersistentFlags().Bool("verbose", false, "Verbose output")
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
另一个更灵活的实现方式,使用中间件模式处理上下文参数:
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
type ContextAwareCommand struct {
*cobra.Command
context string
}
func NewContextAwareCommand() *ContextAwareCommand {
cmd := &cobra.Command{
Use: "myctl [context] [command]",
Short: "Context-aware CLI tool",
Args: cobra.MinimumNArgs(1),
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// 保存上下文到命令的注解中
if len(args) > 0 {
cmd.Annotations["context"] = args[0]
}
return nil
},
}
return &ContextAwareCommand{
Command: cmd,
}
}
func (c *ContextAwareCommand) AddContextCommand(context string) *cobra.Command {
ctxCmd := &cobra.Command{
Use: context,
Short: fmt.Sprintf("Commands for %s context", context),
Args: cobra.ArbitraryArgs,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Printf("Available commands for context '%s':\n", context)
for _, subCmd := range cmd.Commands() {
if !subCmd.Hidden {
fmt.Printf(" %-15s %s\n", subCmd.Name(), subCmd.Short)
}
}
return
}
cmd.Help()
},
}
// 添加子命令到上下文命令
getCmd := &cobra.Command{
Use: "get [resource]",
Short: "Get resources",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Getting resources in context: %s\n", context)
if len(args) > 0 {
fmt.Printf("Resource: %s\n", args[0])
}
},
}
logsCmd := &cobra.Command{
Use: "logs [pod]",
Short: "Get pod logs",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Getting logs in context: %s\n", context)
if len(args) > 0 {
fmt.Printf("Pod: %s\n", args[0])
}
},
}
ctxCmd.AddCommand(getCmd, logsCmd)
c.AddCommand(ctxCmd)
return ctxCmd
}
func main() {
rootCmd := NewContextAwareCommand()
// 添加上下文命令
contexts := []string{"prod", "staging", "dev"}
for _, ctx := range contexts {
rootCmd.AddContextCommand(ctx)
}
// 添加全局命令(不需要上下文)
versionCmd := &cobra.Command{
Use: "version",
Short: "Print version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("myctl v1.0.0")
},
}
rootCmd.AddCommand(versionCmd)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
这个实现提供了:
- 第一个参数作为上下文处理
- 支持隐式子命令(当只有上下文参数时)
- 上下文特定的子命令结构
- 通过PersistentFlags在命令间传递上下文
执行示例:
# 显示所有上下文
$ myctl
# 查找匹配的上下文
$ myctl prod
# 在特定上下文中执行命令
$ myctl prod get pods
$ myctl staging logs my-app

