mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
Fix shorthand combination edge case in c.Traverse() code path
This commit is contained in:
parent
8ba575e694
commit
b07c5cdd6f
2 changed files with 87 additions and 2 deletions
29
command.go
29
command.go
|
@ -851,6 +851,35 @@ func (c *Command) Traverse(args []string) (*Command, []string, error) {
|
||||||
// A flag without a value, or with an `=` separated value
|
// A flag without a value, or with an `=` separated value
|
||||||
case isFlagArg(arg):
|
case isFlagArg(arg):
|
||||||
flags = append(flags, arg)
|
flags = append(flags, arg)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(arg, "-") || strings.HasPrefix(arg, "--") || strings.Contains(arg, "=") || len(arg) <= 2 {
|
||||||
|
continue // Not a shorthand combination, so nothing more to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
shorthandCombination := arg[1:] // Skip leading "-"
|
||||||
|
lastPos := len(shorthandCombination) - 1
|
||||||
|
for i, shorthand := range shorthandCombination {
|
||||||
|
if shortHasNoOptDefVal(string(shorthand), c.Flags()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found a shorthand that needs a value.
|
||||||
|
|
||||||
|
if i == lastPos {
|
||||||
|
// Since we're at the end of the shorthand combination, this means that the
|
||||||
|
// value for the shorthand is given in the next argument. (e.g. '-xyzf arg',
|
||||||
|
// where -x, -y, -z are boolean flags, and -f is a flag that needs a value).
|
||||||
|
inFlag = true
|
||||||
|
} else {
|
||||||
|
// Since the shorthand combination doesn't end here, this means that the
|
||||||
|
// value for the shorthand is given in the same argument, meaning we don't
|
||||||
|
// have to consume the next one. (e.g. '-xyzfarg', where -x, -y, -z are
|
||||||
|
// boolean flags, and -f is a flag that needs a value).
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2253,7 +2253,7 @@ func TestTraverseWithParentFlags(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if len(args) != 1 && args[0] != "--add" {
|
if len(args) != 1 || args[0] != "--int" {
|
||||||
t.Errorf("Wrong args: %v", args)
|
t.Errorf("Wrong args: %v", args)
|
||||||
}
|
}
|
||||||
if c.Name() != childCmd.Name() {
|
if c.Name() != childCmd.Name() {
|
||||||
|
@ -2261,6 +2261,62 @@ func TestTraverseWithParentFlags(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTraverseWithShorthandCombinationInParentFlags(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", TraverseChildren: true}
|
||||||
|
stringVal := rootCmd.Flags().StringP("str", "s", "", "")
|
||||||
|
boolVal := rootCmd.Flags().BoolP("bool", "b", false, "")
|
||||||
|
|
||||||
|
childCmd := &Command{Use: "child"}
|
||||||
|
childCmd.Flags().Int("int", -1, "")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(childCmd)
|
||||||
|
|
||||||
|
c, args, err := rootCmd.Traverse([]string{"-bs", "ok", "child", "--int"})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if len(args) != 1 || args[0] != "--int" {
|
||||||
|
t.Errorf("Wrong args: %v", args)
|
||||||
|
}
|
||||||
|
if c.Name() != childCmd.Name() {
|
||||||
|
t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
|
||||||
|
}
|
||||||
|
if *stringVal != "ok" {
|
||||||
|
t.Errorf("Expected -s to be set to: %s, got: %s", "ok", *stringVal)
|
||||||
|
}
|
||||||
|
if !*boolVal {
|
||||||
|
t.Errorf("Expected -b to be set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraverseWithArgumentIdenticalToCommandName(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", TraverseChildren: true}
|
||||||
|
stringVal := rootCmd.Flags().StringP("str", "s", "", "")
|
||||||
|
boolVal := rootCmd.Flags().BoolP("bool", "b", false, "")
|
||||||
|
|
||||||
|
childCmd := &Command{Use: "child"}
|
||||||
|
childCmd.Flags().Int("int", -1, "")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(childCmd)
|
||||||
|
|
||||||
|
c, args, err := rootCmd.Traverse([]string{"-bs", "child", "child", "--int"})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if len(args) != 1 || args[0] != "--int" {
|
||||||
|
t.Errorf("Wrong args: %v", args)
|
||||||
|
}
|
||||||
|
if c.Name() != childCmd.Name() {
|
||||||
|
t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
|
||||||
|
}
|
||||||
|
if *stringVal != "child" {
|
||||||
|
t.Errorf("Expected -s to be set to: %s, got: %s", "child", *stringVal)
|
||||||
|
}
|
||||||
|
if !*boolVal {
|
||||||
|
t.Errorf("Expected -b to be set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTraverseNoParentFlags(t *testing.T) {
|
func TestTraverseNoParentFlags(t *testing.T) {
|
||||||
rootCmd := &Command{Use: "root", TraverseChildren: true}
|
rootCmd := &Command{Use: "root", TraverseChildren: true}
|
||||||
rootCmd.Flags().String("foo", "", "foo things")
|
rootCmd.Flags().String("foo", "", "foo things")
|
||||||
|
@ -2312,7 +2368,7 @@ func TestTraverseWithBadChildFlag(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if len(args) != 1 && args[0] != "--str" {
|
if len(args) != 1 || args[0] != "--str" {
|
||||||
t.Errorf("Wrong args: %v", args)
|
t.Errorf("Wrong args: %v", args)
|
||||||
}
|
}
|
||||||
if c.Name() != childCmd.Name() {
|
if c.Name() != childCmd.Name() {
|
||||||
|
|
Loading…
Reference in a new issue