Merge pull request #84 from eparis/subcommand-invalid-flag
Stop special casing runnable root commands
This commit is contained in:
		@ -3,11 +3,13 @@ package cobra
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ = fmt.Println
 | 
					var _ = fmt.Println
 | 
				
			||||||
 | 
					var _ = os.Stderr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var tp, te, tt, t1 []string
 | 
					var tp, te, tt, t1 []string
 | 
				
			||||||
var flagb1, flagb2, flagb3, flagbr, flagbp bool
 | 
					var flagb1, flagb2, flagb3, flagbr, flagbp bool
 | 
				
			||||||
@ -22,7 +24,7 @@ const strtwoChildHelp = "help message for child flag strtwo"
 | 
				
			|||||||
var cmdPrint = &Command{
 | 
					var cmdPrint = &Command{
 | 
				
			||||||
	Use:   "print [string to print]",
 | 
						Use:   "print [string to print]",
 | 
				
			||||||
	Short: "Print anything to the screen",
 | 
						Short: "Print anything to the screen",
 | 
				
			||||||
	Long:  `an utterly useless command for testing.`,
 | 
						Long:  `an absolutely utterly useless command for testing.`,
 | 
				
			||||||
	Run: func(cmd *Command, args []string) {
 | 
						Run: func(cmd *Command, args []string) {
 | 
				
			||||||
		tp = args
 | 
							tp = args
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@ -41,7 +43,7 @@ var cmdEcho = &Command{
 | 
				
			|||||||
var cmdTimes = &Command{
 | 
					var cmdTimes = &Command{
 | 
				
			||||||
	Use:   "times [# times] [string to echo]",
 | 
						Use:   "times [# times] [string to echo]",
 | 
				
			||||||
	Short: "Echo anything to the screen more times",
 | 
						Short: "Echo anything to the screen more times",
 | 
				
			||||||
	Long:  `an slightly useless command for testing.`,
 | 
						Long:  `a slightly useless command for testing.`,
 | 
				
			||||||
	Run: func(cmd *Command, args []string) {
 | 
						Run: func(cmd *Command, args []string) {
 | 
				
			||||||
		tt = args
 | 
							tt = args
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@ -417,6 +419,20 @@ func TestTrailingCommandFlags(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestInvalidSubCommandFlags(t *testing.T) {
 | 
				
			||||||
 | 
						cmd := initializeWithRootCmd()
 | 
				
			||||||
 | 
						cmd.AddCommand(cmdTimes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result := simpleTester(cmd, "times --inttwo=2 --badflag=bar")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						checkResultContains(t, result, "unknown flag: --badflag")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if strings.Contains(result.Output, "unknown flag: --inttwo") {
 | 
				
			||||||
 | 
							t.Errorf("invalid --badflag flag shouldn't fail on 'unknown' --inttwo flag")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPersistentFlags(t *testing.T) {
 | 
					func TestPersistentFlags(t *testing.T) {
 | 
				
			||||||
	fullSetupTest("echo -s something -p more here")
 | 
						fullSetupTest("echo -s something -p more here")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -473,6 +489,53 @@ func TestRunnableRootCommand(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRunnableRootCommandNilInput(t *testing.T) {
 | 
				
			||||||
 | 
						empty_arg := make([]string, 0)
 | 
				
			||||||
 | 
						c := initializeWithRootCmd()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf := new(bytes.Buffer)
 | 
				
			||||||
 | 
						// Testing flag with invalid input
 | 
				
			||||||
 | 
						c.SetOutput(buf)
 | 
				
			||||||
 | 
						cmdEcho.AddCommand(cmdTimes)
 | 
				
			||||||
 | 
						c.AddCommand(cmdPrint, cmdEcho)
 | 
				
			||||||
 | 
						c.SetArgs(empty_arg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Execute()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rootcalled != true {
 | 
				
			||||||
 | 
							t.Errorf("Root Function was not called")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRunnableRootCommandEmptyInput(t *testing.T) {
 | 
				
			||||||
 | 
						args := make([]string, 3)
 | 
				
			||||||
 | 
						args[0] = ""
 | 
				
			||||||
 | 
						args[1] = "--introot=12"
 | 
				
			||||||
 | 
						args[2] = ""
 | 
				
			||||||
 | 
						c := initializeWithRootCmd()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf := new(bytes.Buffer)
 | 
				
			||||||
 | 
						// Testing flag with invalid input
 | 
				
			||||||
 | 
						c.SetOutput(buf)
 | 
				
			||||||
 | 
						cmdEcho.AddCommand(cmdTimes)
 | 
				
			||||||
 | 
						c.AddCommand(cmdPrint, cmdEcho)
 | 
				
			||||||
 | 
						c.SetArgs(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Execute()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rootcalled != true {
 | 
				
			||||||
 | 
							t.Errorf("Root Function was not called.\n\nOutput was:\n\n%s\n", buf)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestInvalidSubcommandWhenArgsAllowed(t *testing.T) {
 | 
				
			||||||
 | 
						fullSetupTest("echo invalid-sub")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if te[0] != "invalid-sub" {
 | 
				
			||||||
 | 
							t.Errorf("Subcommand didn't work...")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRootFlags(t *testing.T) {
 | 
					func TestRootFlags(t *testing.T) {
 | 
				
			||||||
	fullSetupTest("-i 17 -b")
 | 
						fullSetupTest("-i 17 -b")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -534,6 +597,24 @@ func TestFlagAccess(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNoNRunnableRootCommandNilInput(t *testing.T) {
 | 
				
			||||||
 | 
						args := make([]string, 0)
 | 
				
			||||||
 | 
						c := initialize()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf := new(bytes.Buffer)
 | 
				
			||||||
 | 
						// Testing flag with invalid input
 | 
				
			||||||
 | 
						c.SetOutput(buf)
 | 
				
			||||||
 | 
						cmdEcho.AddCommand(cmdTimes)
 | 
				
			||||||
 | 
						c.AddCommand(cmdPrint, cmdEcho)
 | 
				
			||||||
 | 
						c.SetArgs(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Execute()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !strings.Contains(buf.String(), cmdRootNoRun.Long) {
 | 
				
			||||||
 | 
							t.Errorf("Expected to get help output, Got: \n %s", buf)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRootNoCommandHelp(t *testing.T) {
 | 
					func TestRootNoCommandHelp(t *testing.T) {
 | 
				
			||||||
	x := rootOnlySetupTest("--help")
 | 
						x := rootOnlySetupTest("--help")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										55
									
								
								command.go
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								command.go
									
									
									
									
									
								
							@ -305,6 +305,8 @@ func stripFlags(args []string, c *Command) []string {
 | 
				
			|||||||
				inFlag = true
 | 
									inFlag = true
 | 
				
			||||||
			case inFlag:
 | 
								case inFlag:
 | 
				
			||||||
				inFlag = false
 | 
									inFlag = false
 | 
				
			||||||
 | 
								case y == "":
 | 
				
			||||||
 | 
									// strip empty commands, as the go tests expect this to be ok....
 | 
				
			||||||
			case !strings.HasPrefix(y, "-"):
 | 
								case !strings.HasPrefix(y, "-"):
 | 
				
			||||||
				commands = append(commands, y)
 | 
									commands = append(commands, y)
 | 
				
			||||||
				inFlag = false
 | 
									inFlag = false
 | 
				
			||||||
@ -375,9 +377,8 @@ func (c *Command) Find(arrs []string) (*Command, []string, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	commandFound, a := innerfind(c, arrs)
 | 
						commandFound, a := innerfind(c, arrs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// if commander returned and the first argument (if it exists) doesn't
 | 
						// If we matched on the root, but we asked for a subcommand, return an error
 | 
				
			||||||
	// match the command name, return nil & error
 | 
						if commandFound.Name() == c.Name() && len(stripFlags(arrs, c)) > 0 && commandFound.Name() != arrs[0] {
 | 
				
			||||||
	if commandFound.Name() == c.Name() && len(arrs[0]) > 0 && commandFound.Name() != arrs[0] {
 | 
					 | 
				
			||||||
		return nil, a, fmt.Errorf("unknown command %q", a[0])
 | 
							return nil, a, fmt.Errorf("unknown command %q", a[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -398,16 +399,6 @@ func (c *Command) Root() *Command {
 | 
				
			|||||||
	return findRoot(c)
 | 
						return findRoot(c)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// execute the command determined by args and the command tree
 | 
					 | 
				
			||||||
func (c *Command) findAndExecute(args []string) (err error) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd, a, e := c.Find(args)
 | 
					 | 
				
			||||||
	if e != nil {
 | 
					 | 
				
			||||||
		return e
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return cmd.execute(a)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Command) execute(a []string) (err error) {
 | 
					func (c *Command) execute(a []string) (err error) {
 | 
				
			||||||
	if c == nil {
 | 
						if c == nil {
 | 
				
			||||||
		return fmt.Errorf("Called Execute() on a nil Command")
 | 
							return fmt.Errorf("Called Execute() on a nil Command")
 | 
				
			||||||
@ -494,45 +485,11 @@ func (c *Command) Execute() (err error) {
 | 
				
			|||||||
			c.Help()
 | 
								c.Help()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		err = c.findAndExecute(args)
 | 
							cmd, flags, e := c.Find(args)
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Now handle the case where the root is runnable and only flags are provided
 | 
					 | 
				
			||||||
	if err != nil && c.Runnable() {
 | 
					 | 
				
			||||||
		// This is pretty much a custom version of the *Command.execute method
 | 
					 | 
				
			||||||
		// with a few differences because it's the final command (no fall back)
 | 
					 | 
				
			||||||
		e := c.ParseFlags(args)
 | 
					 | 
				
			||||||
		if e != nil {
 | 
							if e != nil {
 | 
				
			||||||
			// Flags parsing had an error.
 | 
					 | 
				
			||||||
			// If an error happens here, we have to report it to the user
 | 
					 | 
				
			||||||
			c.Println(e.Error())
 | 
					 | 
				
			||||||
			// If an error happens search also for subcommand info about that
 | 
					 | 
				
			||||||
			if c.cmdErrorBuf != nil && c.cmdErrorBuf.Len() > 0 {
 | 
					 | 
				
			||||||
				c.Println(c.cmdErrorBuf.String())
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				c.Usage()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			err = e
 | 
								err = e
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// If help is called, regardless of other flags, we print that
 | 
								err = cmd.execute(flags)
 | 
				
			||||||
			if c.helpFlagVal {
 | 
					 | 
				
			||||||
				c.Help()
 | 
					 | 
				
			||||||
				return nil
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			argWoFlags := c.Flags().Args()
 | 
					 | 
				
			||||||
			if len(argWoFlags) > 0 {
 | 
					 | 
				
			||||||
				// If there are arguments (not flags) one of the earlier
 | 
					 | 
				
			||||||
				// cases should have caught it.. It means invalid usage
 | 
					 | 
				
			||||||
				// print the usage
 | 
					 | 
				
			||||||
				c.Usage()
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				// Only flags left... Call root.Run
 | 
					 | 
				
			||||||
				c.preRun()
 | 
					 | 
				
			||||||
				c.Run(c, argWoFlags)
 | 
					 | 
				
			||||||
				err = nil
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user