Added ValidArgs as object to prevent memory wasting using new Command to subsubcommands

This commit is contained in:
themester 2017-11-11 00:01:00 +01:00
parent 2da4a54c5c
commit b415b76121
7 changed files with 75 additions and 23 deletions

View file

@ -35,7 +35,14 @@ func NoArgs(cmd *Command, args []string) error {
func OnlyValidArgs(cmd *Command, args []string) error { func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 { if len(cmd.ValidArgs) > 0 {
for _, v := range args { for _, v := range args {
if !stringInSlice(v, cmd.ValidArgs) { if !func() bool {
for _, cmdargs := range cmd.ValidArgs {
if v == cmdargs.Name {
return true
}
}
return false
}() {
return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
} }
} }

View file

@ -34,10 +34,13 @@ func TestNoArgsWithArgs(t *testing.T) {
func TestOnlyValidArgs(t *testing.T) { func TestOnlyValidArgs(t *testing.T) {
c := &Command{ c := &Command{
Use: "c", Use: "c",
Args: OnlyValidArgs, Args: OnlyValidArgs,
ValidArgs: []string{"one", "two"}, ValidArgs: []ValidArgs{
Run: emptyRun, {"one", "one thing"},
{"two", "two things"},
},
Run: emptyRun,
} }
output, err := executeCommand(c, "one", "two") output, err := executeCommand(c, "one", "two")
@ -51,10 +54,13 @@ func TestOnlyValidArgs(t *testing.T) {
func TestOnlyValidArgsWithInvalidArgs(t *testing.T) { func TestOnlyValidArgsWithInvalidArgs(t *testing.T) {
c := &Command{ c := &Command{
Use: "c", Use: "c",
Args: OnlyValidArgs, Args: OnlyValidArgs,
ValidArgs: []string{"one", "two"}, ValidArgs: []ValidArgs{
Run: emptyRun, {"one", "one thing"},
{"two", "two things"},
},
Run: emptyRun,
} }
_, err := executeCommand(c, "three") _, err := executeCommand(c, "three")

View file

@ -428,9 +428,11 @@ func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
buf.WriteString(" must_have_one_noun=()\n") buf.WriteString(" must_have_one_noun=()\n")
sort.Sort(sort.StringSlice(cmd.ValidArgs)) sort.Slice(cmd.ValidArgs, func(i, j int) bool {
return cmd.ValidArgs[i].Name < cmd.ValidArgs[j].Name
})
for _, value := range cmd.ValidArgs { for _, value := range cmd.ValidArgs {
buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value)) buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value.Name))
} }
} }

View file

@ -80,7 +80,12 @@ The `BashCompletionFunction` option is really only valid/useful on the root comm
In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like:
```go ```go
validArgs []string = { "pod", "node", "service", "replicationcontroller" } validArgs []ValidArgs = {
{"pod", ""},
{"node", ""},
{"service", ""},
{"replicationcontroller", ""},
}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",

View file

@ -48,9 +48,14 @@ const bashCompletionFunc = `__custom_func() {
func TestBashCompletions(t *testing.T) { func TestBashCompletions(t *testing.T) {
rootCmd := &Command{ rootCmd := &Command{
Use: "root", Use: "root",
ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"}, ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"},
ValidArgs: []string{"pod", "node", "service", "replicationcontroller"}, ValidArgs: []ValidArgs{
{"pod", ""},
{"node", ""},
{"service", ""},
{"replicationcontroller", ""},
},
BashCompletionFunction: bashCompletionFunc, BashCompletionFunction: bashCompletionFunc,
Run: emptyRun, Run: emptyRun,
} }
@ -111,10 +116,15 @@ func TestBashCompletions(t *testing.T) {
Use: "times [# times] [string to echo]", Use: "times [# times] [string to echo]",
SuggestFor: []string{"counts"}, SuggestFor: []string{"counts"},
Args: OnlyValidArgs, Args: OnlyValidArgs,
ValidArgs: []string{"one", "two", "three", "four"}, ValidArgs: []ValidArgs{
Short: "Echo anything to the screen more times", {"one", ""},
Long: "a slightly useless command for testing.", {"two", ""},
Run: emptyRun, {"three", ""},
{"four", ""},
},
Short: "Echo anything to the screen more times",
Long: "a slightly useless command for testing.",
Run: emptyRun,
} }
echoCmd.AddCommand(timesCmd) echoCmd.AddCommand(timesCmd)

View file

@ -1,4 +1,4 @@
// Copyright © 2013 Steve Francia <spf@spf13.com>. // Copyright © 2013 Steve Francia <spf@spf13.com>.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.

View file

@ -1,4 +1,3 @@
// Copyright © 2013 Steve Francia <spf@spf13.com>.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -27,6 +26,17 @@ import (
flag "github.com/spf13/pflag" flag "github.com/spf13/pflag"
) )
// This structure has been created to replace
// ValidArgs []string in Command object to prevent
// wasting memory when new command objects are added simply
// to add new subsubcommands.
type ValidArgs struct {
// Name of subcommand
Name string
// Short description
Short string
}
// Command is just that, a command for your application. // Command is just that, a command for your application.
// E.g. 'go run ...' - 'run' is the command. Cobra requires // E.g. 'go run ...' - 'run' is the command. Cobra requires
// you to define the usage and description as part of your command // you to define the usage and description as part of your command
@ -52,7 +62,9 @@ type Command struct {
Example string Example string
// ValidArgs is list of all valid non-flag arguments that are accepted in bash completions // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions
ValidArgs []string // We can use ValidArgs instead of adding new commands to list. This is to prevent
// wasting memory with new Command objects.
ValidArgs []ValidArgs
// Expected arguments // Expected arguments
Args PositionalArgs Args PositionalArgs
@ -372,7 +384,10 @@ func (c *Command) UsageTemplate() string {
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
Aliases: Aliases:
{{.NameAndAliases}}{{end}}{{if .HasExample}} {{.NameAndAliases}}{{end}}{{if .HasValidArgs}}
Valid Args:{{range .ValidArgs}}
{{.Name}} {{.Short}}{{end}}{{end}}{{if .HasExample}}
Examples: Examples:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}} {{.Example}}{{end}}{{if .HasAvailableSubCommands}}
@ -393,6 +408,13 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e
` `
} }
func (c *Command) HasValidArgs() bool {
if len(c.ValidArgs) > 0 {
return true
}
return false
}
// HelpTemplate return help template for the command. // HelpTemplate return help template for the command.
func (c *Command) HelpTemplate() string { func (c *Command) HelpTemplate() string {
if c.helpTemplate != "" { if c.helpTemplate != "" {