Repository: spf13/cobra (go)

Issue:
If no subcommand, how to get args?
example:

``` go
package main

import (
    "fmt"
    "github.com/spf13/cobra"
)

func main() {
    var echo = &cobra.Command{
        Use:    "echo [string...]",
        Short:  "echo all strings",
        Long:   "echo string string string string...",
        Run:    func(cmd *cobra.Command, args []string) {
            fmt.Printf("%v\n", args)
        },
    }

    echo.Execute()
}
```

```
[bash]# go run echo.go aa bb cc dd

Usage:
  echo [string...] [flags]

 Available Flags:
  -h, --help=false: help for echo
Error: unknown command "aa"
Run 'help' for usage.

echo: invalid command [`aa` `bb` `cc` `dd`]
Run 'echo help' for usage
```

```
[bash]# go run echo.go echo aa bb cc dd
[echo aa bb cc dd]
```

```
[bash]# go run echo.go
[]
```

Thanks!


Pull request:
Support validation of positional arguments
Fixes #42
Branched from #120

Adds a new field `Args` that allows a user to define the expected positional arguments that a command should receive. If a command doesn't receive the expected args it returns an error.

By accepting a validation function users can create their own custom validation for positional args. This PR includes validators for the most common cases.


Patch:
diff --git a/README.md b/README.md
index 4dd5429..3dbb187 100644
--- a/README.md
+++ b/README.md
@@ -140,8 +140,8 @@ import "github.com/spf13/cobra"
 
 # Getting Started
 
-While you are welcome to provide your own organization, typically a Cobra based
-application will follow the following organizational structure.
+While you are welcome to provide your own organization, typically a Cobra-based
+application will follow the following organizational structure:
 
 ```
   ▾ appName/
@@ -153,7 +153,7 @@ application will follow the following organizational structure.
       main.go
 ```
 
-In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra.
+In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra.
 
 ```go
 package main
@@ -216,10 +216,11 @@ cobra add create -p 'configCmd'
 ```
 
 *Note: Use camelCase (not snake_case/snake-case) for command names.
-Otherwise, you will become unexpected errors.
+Otherwise, you will encounter errors.
 For example, `cobra add add-user` is incorrect, but `cobra add addUser` is valid.*
 
-Once you have run these three commands you would have an app structure that would look like:
+Once you have run these three commands you would have an app structure similar to
+the following:
 
 ```
   ▾ app/
@@ -232,14 +233,14 @@ Once you have run these three commands you would have an app structure that woul
 
 At this point you can run `go run main.go` and it would run your app. `go run
 main.go serve`, `go run main.go config`, `go run main.go config create` along
-with `go run main.go help serve`, etc would all work.
+with `go run main.go help serve`, etc. would all work.
 
-Obviously you haven't added your own code to these yet, the commands are ready
+Obviously you haven't added your own code to these yet. The commands are ready
 for you to give them their tasks. Have fun!
 
 ### Configuring the cobra generator
 
-The cobra generator will be easier to use if you provide a simple configuration
+The Cobra generator will be easier to use if you provide a simple configuration
 file which will help you eliminate providing a bunch of repeated information in
 flags over and over.
 
@@ -269,7 +270,7 @@ You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**,
 
 ## Manually implementing Cobra
 
-To manually implement cobra you need to create a bare main.go file and a RootCmd file.
+To manually implement Cobra you need to create a bare main.go file and a RootCmd file.
 You will optionally provide additional commands as you see fit.
 
 ### Create the root command
@@ -323,7 +324,11 @@ func init() {
 	viper.SetDefault("license", "apache")
 }
 
-func main() {
+func Execute() {
+	RootCmd.Execute()
+}
+
+func initConfig() {
   // Don't forget to read config either from cfgFile or from home directory!
 	if cfgFile != "" {
 		// Use config file from the flag.
@@ -332,7 +337,7 @@ func main() {
 		// Find home directory.
 		home, err := homedir.Dir()
 		if err != nil {
-			fmt.Println(home)
+			fmt.Println(err)
 			os.Exit(1)
 		}
 
@@ -343,7 +348,7 @@ func main() {
 
 	if err := viper.ReadInConfig(); err != nil {
 		fmt.Println("Can't read config:", err)
-    os.Exit(1)
+		os.Exit(1)
 	}
 }
 ```
@@ -462,6 +467,36 @@ A flag can also be assigned locally which will only apply to that specific comma
 RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
 ```
 
+## Positional and Custom Arguments
+
+Validation of positional arguments can be specified using the `Args` field.
+
+The follow validators are built in:
+
+- `NoArgs` - the command will report an error if there are any positional args.
+- `ArbitraryArgs` - the command will accept any args.
+- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the ValidArgs list.
+- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args.
+- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args.
+- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
+- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
+
+A custom validator can be provided like this:
+
+```go
+
+Args: func validColorArgs(cmd *cobra.Command, args []string) error {
+  if err := cli.RequiresMinArgs(1)(cmd, args); err != nil {
+    return err
+  }
+  if myapp.IsValidColor(args[0]) {
+     return nil
+  }
+  return fmt.Errorf("Invalid color specified: %s", args[0])
+}
+
+```
+
 ### Bind Flags with Config
 
 You can also bind your flags with [viper](https://github.com/spf13/viper):
@@ -480,6 +515,7 @@ when the `--author` flag is not provided by user.
 
 More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
 
+
 ## Example
 
 In the example below, we have defined three commands. Two are at the top level
diff --git a/args.go b/args.go
new file mode 100644
index 0000000..94a6ca2
--- /dev/null
+++ b/args.go
@@ -0,0 +1,98 @@
+package cobra
+
+import (
+	"fmt"
+)
+
+type PositionalArgs func(cmd *Command, args []string) error
+
+// Legacy arg validation has the following behaviour:
+// - root commands with no subcommands can take arbitrary arguments
+// - root commands with subcommands will do subcommand validity checking
+// - subcommands will always accept arbitrary arguments
+func legacyArgs(cmd *Command, args []string) error {
+	// no subcommand, always take args
+	if !cmd.HasSubCommands() {
+		return nil
+	}
+
+	// root command with subcommands, do subcommand checking
+	if !cmd.HasParent() && len(args) > 0 {
+		return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
+	}
+	return nil
+}
+
+// NoArgs returns an error if any args are included
+func NoArgs(cmd *Command, args []string) error {
+	if len(args) > 0 {
+		return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
+	}
+	return nil
+}
+
+// OnlyValidArgs returns an error if any args are not in the list of ValidArgs
+func OnlyValidArgs(cmd *Command, args []string) error {
+	if len(cmd.ValidArgs) > 0 {
+		for _, v := range args {
+			if !stringInSlice(v, cmd.ValidArgs) {
+				return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
+			}
+		}
+	}
+	return nil
+}
+
+func stringInSlice(a string, list []string) bool {
+	for _, b := range list {
+		if b == a {
+			return true
+		}
+	}
+	return false
+}
+
+// ArbitraryArgs never returns an error
+func ArbitraryArgs(cmd *Command, args []string) error {
+	return nil
+}
+
+// MinimumNArgs returns an error if there is not at least N args
+func MinimumNArgs(n int) PositionalArgs {
+	return func(cmd *Command, args []string) error {
+		if len(args) < n {
+			return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args))
+		}
+		return nil
+	}
+}
+
+// MaximumNArgs returns an error if there are more than N args
+func MaximumNArgs(n int) PositionalArgs {
+	return func(cmd *Command, args []string) error {
+		if len(args) > n {
+			return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args))
+		}
+		return nil
+	}
+}
+
+// ExactArgs returns an error if there are not exactly n args
+func ExactArgs(n int) PositionalArgs {
+	return func(cmd *Command, args []string) error {
+		if len(args) != n {
+			return fmt.Errorf("accepts %d arg(s), received %d", n, len(args))
+		}
+		return nil
+	}
+}
+
+// RangeArgs returns an error if the number of args is not within the expected range
+func RangeArgs(min int, max int) PositionalArgs {
+	return func(cmd *Command, args []string) error {
+		if len(args) < min || len(args) > max {
+			return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args))
+		}
+		return nil
+	}
+}
diff --git a/cobra.go b/cobra.go
index 2726d19..8928cef 100644
--- a/cobra.go
+++ b/cobra.go
@@ -47,6 +47,15 @@ var EnablePrefixMatching = false
 // To disable sorting, set it to false.
 var EnableCommandSorting = true
 
+// MousetrapHelpText enables an information splash screen on Windows
+// if the CLI is started from explorer.exe.
+// To disable the mousetrap, just set this variable to blank string ("").
+// Works only on Microsoft Windows.
+var MousetrapHelpText string = `This is a command line tool.
+
+You need to open cmd.exe and run it from there.
+`
+
 // AddTemplateFunc adds a template function that's available to Usage and Help
 // template generation.
 func AddTemplateFunc(name string, tmplFunc interface{}) {
diff --git a/cobra/cmd/add.go b/cobra/cmd/add.go
index 8897f8f..45f00bb 100644
--- a/cobra/cmd/add.go
+++ b/cobra/cmd/add.go
@@ -23,10 +23,11 @@ import (
 )
 
 func init() {
+	addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)")
 	addCmd.Flags().StringVarP(&parentName, "parent", "p", "RootCmd", "name of parent command for this command")
 }
 
-var parentName string
+var packageName, parentName string
 
 var addCmd = &cobra.Command{
 	Use:     "add [command name]",
@@ -45,11 +46,17 @@ Example: cobra add server -> resulting in a new cmd/server.go`,
 		if len(args) < 1 {
 			er("add needs a name for the command")
 		}
-		wd, err := os.Getwd()
-		if err != nil {
-			er(err)
+
+		var project *Project
+		if packageName != "" {
+			project = NewProject(packageName)
+		} else {
+			wd, err := os.Getwd()
+			if err != nil {
+				er(err)
+			}
+			project = NewProjectFromPath(wd)
 		}
-		project := NewProjectFromPath(wd)
 
 		cmdName := validateCmdName(args[0])
 		cmdPath := filepath.Join(project.CmdPath(), cmdName+".go")
diff --git a/cobra/cmd/helpers.go b/cobra/cmd/helpers.go
index 6114227..c5e261c 100644
--- a/cobra/cmd/helpers.go
+++ b/cobra/cmd/helpers.go
@@ -45,24 +45,34 @@ func er(msg interface{}) {
 }
 
 // isEmpty checks if a given path is empty.
+// Hidden files in path are ignored.
 func isEmpty(path string) bool {
 	fi, err := os.Stat(path)
 	if err != nil {
 		er(err)
 	}
-	if fi.IsDir() {
-		f, err := os.Open(path)
-		if err != nil {
-			er(err)
-		}
-		defer f.Close()
-		dirs, err := f.Readdirnames(1)
-		if err != nil && err != io.EOF {
-			er(err)
+
+	if !fi.IsDir() {
+		return fi.Size() == 0
+	}
+
+	f, err := os.Open(path)
+	if err != nil {
+		er(err)
+	}
+	defer f.Close()
+
+	names, err := f.Readdirnames(-1)
+	if err != nil && err != io.EOF {
+		er(err)
+	}
+
+	for _, name := range names {
+		if len(name) > 0 && name[0] != '.' {
+			return false
 		}
-		return len(dirs) == 0
 	}
-	return fi.Size() == 0
+	return true
 }
 
 // exists checks if a file or directory exists.
diff --git a/cobra/cmd/init.go b/cobra/cmd/init.go
index 0e2b22a..149aabe 100644
--- a/cobra/cmd/init.go
+++ b/cobra/cmd/init.go
@@ -59,7 +59,7 @@ Init will not use an existing directory with contents.`,
 				project = NewProject(arg)
 			}
 		} else {
-			er("please enter the name")
+			er("please provide only one argument")
 		}
 
 		initializeProject(project)
@@ -142,13 +142,13 @@ package cmd
 import (
 	"fmt"
 	"os"
+{{if .viper}}
+	homedir "github.com/mitchellh/go-homedir"{{end}}
+	"github.com/spf13/cobra"{{if .viper}}
+	"github.com/spf13/viper"{{end}}
+){{if .viper}}
 
-	homedir "github.com/mitchellh/go-homedir"
-	"github.com/spf13/cobra"
-{{if .viper}}	"github.com/spf13/viper"{{end}}
-)
-
-{{if .viper}}var cfgFile string{{end}}
+var cfgFile string{{end}}
 
 // RootCmd represents the base command when called without any subcommands
 var RootCmd = &cobra.Command{
@@ -165,7 +165,7 @@ to quickly create a Cobra application.` + "`" + `,
 	//	Run: func(cmd *cobra.Command, args []string) { },
 }
 
-// Execute adds all child commands to the root command sets flags appropriately.
+// Execute adds all child commands to the root command and sets flags appropriately.
 // This is called by main.main(). It only needs to happen once to the rootCmd.
 func Execute() {
 	if err := RootCmd.Execute(); err != nil {
@@ -174,9 +174,9 @@ func Execute() {
 	}
 }
 
-func init() {
-{{if .viper}}	cobra.OnInitialize(initConfig){{end}}
-
+func init() { {{if .viper}}
+	cobra.OnInitialize(initConfig)
+{{end}}
 	// Here you will define your flags and configuration settings.
 	// Cobra supports persistent flags, which, if defined here,
 	// will be global for your application.{{ if .viper }}
diff --git a/cobra/cmd/root.go b/cobra/cmd/root.go
index 716a59a..1c5e690 100644
--- a/cobra/cmd/root.go
+++ b/cobra/cmd/root.go
@@ -44,16 +44,15 @@ func init() {
 
 	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
 	rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
-	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project (can provide `license` in config)")
+	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
 	rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
 	viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
 	viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
 	viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
 	viper.SetDefault("license", "apache")
 
-	rootCmd.AddCommand(initCmd)
 	rootCmd.AddCommand(addCmd)
-
+	rootCmd.AddCommand(initCmd)
 }
 
 func initViper() {
diff --git a/command.go b/command.go
index e85bf51..4f65d77 100644
--- a/command.go
+++ b/command.go
@@ -59,6 +59,8 @@ type Command struct {
 	// but accepted if entered manually.
 	ArgAliases []string
 
+	// Expected arguments
+	Args PositionalArgs
 	// BashCompletionFunction is custom functions used by the bash autocompletion generator.
 	BashCompletionFunction string
 
@@ -513,31 +515,27 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
 	}
 
 	commandFound, a := innerfind(c, args)
-	argsWOflags := stripFlags(a, commandFound)
-
-	// no subcommand, always take args
-	if !commandFound.HasSubCommands() {
-		return commandFound, a, nil
+	if commandFound.Args == nil {
+		return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound))
 	}
+	return commandFound, a, nil
+}
 
-	// root command with subcommands, do subcommand checking
-	if commandFound == c && len(argsWOflags) > 0 {
-		suggestionsString := ""
-		if !c.DisableSuggestions {
-			if c.SuggestionsMinimumDistance <= 0 {
-				c.SuggestionsMinimumDistance = 2
-			}
-			if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 {
-				suggestionsString += "\n\nDid you mean this?\n"
-				for _, s := range suggestions {
-					suggestionsString += fmt.Sprintf("\t%v\n", s)
-				}
-			}
+func (c *Command) findSuggestions(arg string) string {
+	if c.DisableSuggestions {
+		return ""
+	}
+	if c.SuggestionsMinimumDistance <= 0 {
+		c.SuggestionsMinimumDistance = 2
+	}
+	suggestionsString := ""
+	if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 {
+		suggestionsString += "\n\nDid you mean this?\n"
+		for _, s := range suggestions {
+			suggestionsString += fmt.Sprintf("\t%v\n", s)
 		}
-		return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestionsString)
 	}
-
-	return commandFound, a, nil
+	return suggestionsString
 }
 
 // SuggestionsFor provides suggestions for the typedName.
@@ -624,6 +622,10 @@ func (c *Command) execute(a []string) (err error) {
 		argWoFlags = a
 	}
 
+	if err := c.ValidateArgs(argWoFlags); err != nil {
+		return err
+	}
+
 	for p := c; p != nil; p = p.Parent() {
 		if p.PersistentPreRunE != nil {
 			if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
@@ -747,6 +749,13 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
 	return cmd, err
 }
 
+func (c *Command) ValidateArgs(args []string) error {
+	if c.Args == nil {
+		return nil
+	}
+	return c.Args(c, args)
+}
+
 // InitDefaultHelpFlag adds default help flag to c.
 // It is called automatically by executing the c or by calling help and usage.
 // If c already has help flag, it will do nothing.
@@ -767,28 +776,28 @@ func (c *Command) InitDefaultHelpFlag() {
 // It is called automatically by executing the c or by calling help and usage.
 // If c already has help command or c has no subcommands, it will do nothing.
 func (c *Command) InitDefaultHelpCmd() {
-	if c.helpCommand != nil || !c.HasSubCommands() {
+	if !c.HasSubCommands() {
 		return
 	}
 
-	c.helpCommand = &Command{
-		Use:   "help [command]",
-		Short: "Help about any command",
-		Long: `Help provides help for any command in the application.
-    Simply type ` + c.Name() + ` help [path to command] for full details.`,
-		PersistentPreRun:  func(cmd *Command, args []string) {},
-		PersistentPostRun: func(cmd *Command, args []string) {},
+	if c.helpCommand == nil {
+		c.helpCommand = &Command{
+			Use:   "help [command]",
+			Short: "Help about any command",
+			Long: `Help provides help for any command in the application.
+Simply type ` + c.Name() + ` help [path to command] for full details.`,
 
-		Run: func(c *Command, args []string) {
-			cmd, _, e := c.Root().Find(args)
-			if cmd == nil || e != nil {
-				c.Printf("Unknown help topic %#q\n", args)
-				c.Root().Usage()
-			} else {
-				cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown
-				cmd.Help()
-			}
-		},
+			Run: func(c *Command, args []string) {
+				cmd, _, e := c.Root().Find(args)
+				if cmd == nil || e != nil {
+					c.Printf("Unknown help topic %#q\n", args)
+					c.Root().Usage()
+				} else {
+					cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown
+					cmd.Help()
+				}
+			},
+		}
 	}
 	c.RemoveCommand(c.helpCommand)
 	c.AddCommand(c.helpCommand)
@@ -1249,13 +1258,20 @@ func (c *Command) persistentFlag(name string) (flag *flag.Flag) {
 }
 
 // ParseFlags parses persistent flag tree and local flags.
-func (c *Command) ParseFlags(args []string) (err error) {
+func (c *Command) ParseFlags(args []string) error {
 	if c.DisableFlagParsing {
 		return nil
 	}
+
+	beforeErrorBufLen := c.flagErrorBuf.Len()
 	c.mergePersistentFlags()
-	err = c.Flags().Parse(args)
-	return
+	err := c.Flags().Parse(args)
+	// Print warnings if they occurred (e.g. deprecated flag messages).
+	if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil {
+		c.Print(c.flagErrorBuf.String())
+	}
+
+	return err
 }
 
 // Parent returns a commands parent command.
diff --git a/command_win.go b/command_win.go
index 4b0eaa1..edec728 100644
--- a/command_win.go
+++ b/command_win.go
@@ -11,14 +11,8 @@ import (
 
 var preExecHookFn = preExecHook
 
-// enables an information splash screen on Windows if the CLI is started from explorer.exe.
-var MousetrapHelpText string = `This is a command line tool
-
-You need to open cmd.exe and run it from there.
-`
-
 func preExecHook(c *Command) {
-	if mousetrap.StartedByExplorer() {
+	if MousetrapHelpText != "" && mousetrap.StartedByExplorer() {
 		c.Print(MousetrapHelpText)
 		time.Sleep(5 * time.Second)
 		os.Exit(1)


Test patch:
diff --git a/bash_completions_test.go b/bash_completions_test.go
index 7511376..071a6a2 100644
--- a/bash_completions_test.go
+++ b/bash_completions_test.go
@@ -117,6 +117,8 @@ func TestBashCompletions(t *testing.T) {
 	// check for filename extension flags
 	check(t, str, `flags_completion+=("_filedir")`)
 	// check for filename extension flags
+	check(t, str, `must_have_one_noun+=("three")`)
+	// check for filename extention flags
 	check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
 	// check for custom flags
 	check(t, str, `flags_completion+=("__complete_custom")`)
diff --git a/cobra/cmd/testdata/root.go.golden b/cobra/cmd/testdata/root.go.golden
index 13e9a77..ecc8760 100644
--- a/cobra/cmd/testdata/root.go.golden
+++ b/cobra/cmd/testdata/root.go.golden
@@ -39,7 +39,7 @@ to quickly create a Cobra application.`,
 	//	Run: func(cmd *cobra.Command, args []string) { },
 }
 
-// Execute adds all child commands to the root command sets flags appropriately.
+// Execute adds all child commands to the root command and sets flags appropriately.
 // This is called by main.main(). It only needs to happen once to the rootCmd.
 func Execute() {
 	if err := RootCmd.Execute(); err != nil {
@@ -48,7 +48,7 @@ func Execute() {
 	}
 }
 
-func init() {
+func init() { 
 	cobra.OnInitialize(initConfig)
 
 	// Here you will define your flags and configuration settings.
diff --git a/cobra_test.go b/cobra_test.go
index 576c97d..1706eae 100644
--- a/cobra_test.go
+++ b/cobra_test.go
@@ -36,6 +36,7 @@ var cmdHidden = &Command{
 
 var cmdPrint = &Command{
 	Use:   "print [string to print]",
+	Args:  MinimumNArgs(1),
 	Short: "Print anything to the screen",
 	Long:  `an absolutely utterly useless command for testing.`,
 	Run: func(cmd *Command, args []string) {
@@ -75,6 +76,7 @@ var cmdDeprecated = &Command{
 	Deprecated: "Please use echo instead",
 	Run: func(cmd *Command, args []string) {
 	},
+	Args: NoArgs,
 }
 
 var cmdTimes = &Command{
@@ -88,6 +90,8 @@ var cmdTimes = &Command{
 	Run: func(cmd *Command, args []string) {
 		tt = args
 	},
+	Args:      OnlyValidArgs,
+	ValidArgs: []string{"one", "two", "three", "four"},
 }
 
 var cmdRootNoRun = &Command{
@@ -105,6 +109,16 @@ var cmdRootSameName = &Command{
 	Long:  "The root description for help",
 }
 
+var cmdRootTakesArgs = &Command{
+	Use:   "root-with-args [random args]",
+	Short: "The root can run it's own function and takes args!",
+	Long:  "The root description for help, and some args",
+	Run: func(cmd *Command, args []string) {
+		tr = args
+	},
+	Args: ArbitraryArgs,
+}
+
 var cmdRootWithRun = &Command{
 	Use:   "cobra-test",
 	Short: "The root can run its own function",
@@ -458,6 +472,63 @@ func TestUsage(t *testing.T) {
 	checkResultOmits(t, x, cmdCustomFlags.Use+" [flags]")
 }
 
+func TestRootTakesNoArgs(t *testing.T) {
+	c := initializeWithSameName()
+	c.AddCommand(cmdPrint, cmdEcho)
+	result := simpleTester(c, "illegal")
+
+	if result.Error == nil {
+		t.Fatal("Expected an error")
+	}
+
+	expectedError := `unknown command "illegal" for "print"`
+	if !strings.Contains(result.Error.Error(), expectedError) {
+		t.Errorf("exptected %v, got %v", expectedError, result.Error.Error())
+	}
+}
+
+func TestRootTakesArgs(t *testing.T) {
+	c := cmdRootTakesArgs
+	result := simpleTester(c, "legal")
+
+	if result.Error != nil {
+		t.Errorf("expected no error, but got %v", result.Error)
+	}
+}
+
+func TestSubCmdTakesNoArgs(t *testing.T) {
+	result := fullSetupTest("deprecated", "illegal")
+
+	if result.Error == nil {
+		t.Fatal("Expected an error")
+	}
+
+	expectedError := `unknown command "illegal" for "cobra-test deprecated"`
+	if !strings.Contains(result.Error.Error(), expectedError) {
+		t.Errorf("expected %v, got %v", expectedError, result.Error.Error())
+	}
+}
+
+func TestSubCmdTakesArgs(t *testing.T) {
+	noRRSetupTest("echo", "times", "one", "two")
+	if strings.Join(tt, " ") != "one two" {
+		t.Error("Command didn't parse correctly")
+	}
+}
+
+func TestCmdOnlyValidArgs(t *testing.T) {
+	result := noRRSetupTest("echo", "times", "one", "two", "five")
+
+	if result.Error == nil {
+		t.Fatal("Expected an error")
+	}
+
+	expectedError := `invalid argument "five"`
+	if !strings.Contains(result.Error.Error(), expectedError) {
+		t.Errorf("expected %v, got %v", expectedError, result.Error.Error())
+	}
+}
+
 func TestFlagLong(t *testing.T) {
 	noRRSetupTest("echo", "--intone=13", "something", "--", "here")
 
@@ -672,9 +743,9 @@ func TestPersistentFlags(t *testing.T) {
 	}
 
 	// persistentFlag should act like normal flag on its own command
-	fullSetupTest("echo", "times", "-s", "again", "-c", "-p", "test", "here")
+	fullSetupTest("echo", "times", "-s", "again", "-c", "-p", "one", "two")
 
-	if strings.Join(tt, " ") != "test here" {
+	if strings.Join(tt, " ") != "one two" {
 		t.Errorf("flags didn't leave proper args remaining. %s given", tt)
 	}
 
diff --git a/command_test.go b/command_test.go
index 978bacc..aa6658f 100644
--- a/command_test.go
+++ b/command_test.go
@@ -120,7 +120,6 @@ func TestStripFlags(t *testing.T) {
 }
 
 func TestDisableFlagParsing(t *testing.T) {
-	as := []string{"-v", "-race", "-file", "foo.go"}
 	targs := []string{}
 	cmdPrint := &Command{
 		DisableFlagParsing: true,
@@ -128,14 +127,14 @@ func TestDisableFlagParsing(t *testing.T) {
 			targs = args
 		},
 	}
-	osargs := []string{"cmd"}
-	os.Args = append(osargs, as...)
+	args := []string{"cmd", "-v", "-race", "-file", "foo.go"}
+	cmdPrint.SetArgs(args)
 	err := cmdPrint.Execute()
 	if err != nil {
 		t.Error(err)
 	}
-	if !reflect.DeepEqual(as, targs) {
-		t.Errorf("expected: %v, got: %v", as, targs)
+	if !reflect.DeepEqual(args, targs) {
+		t.Errorf("expected: %v, got: %v", args, targs)
 	}
 }
 
@@ -298,3 +297,53 @@ func TestMergeCommandLineToFlags(t *testing.T) {
 	// Reset pflag.CommandLine flagset.
 	pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
 }
+
+// TestUseDeprecatedFlags checks,
+// if cobra.Execute() prints a message, if a deprecated flag is used.
+// Related to https://github.com/spf13/cobra/issues/463.
+func TestUseDeprecatedFlags(t *testing.T) {
+	c := &Command{Use: "c", Run: func(*Command, []string) {}}
+	output := new(bytes.Buffer)
+	c.SetOutput(output)
+	c.Flags().BoolP("deprecated", "d", false, "deprecated flag")
+	c.Flags().MarkDeprecated("deprecated", "This flag is deprecated")
+
+	c.SetArgs([]string{"c", "-d"})
+	if err := c.Execute(); err != nil {
+		t.Error("Unexpected error:", err)
+	}
+	if !strings.Contains(output.String(), "This flag is deprecated") {
+		t.Errorf("Expected to contain deprecated message, but got %q", output.String())
+	}
+}
+
+// TestSetHelpCommand checks, if SetHelpCommand works correctly.
+func TestSetHelpCommand(t *testing.T) {
+	c := &Command{Use: "c", Run: func(*Command, []string) {}}
+	output := new(bytes.Buffer)
+	c.SetOutput(output)
+	c.SetArgs([]string{"help"})
+
+	// Help will not be shown, if c has no subcommands.
+	c.AddCommand(&Command{
+		Use: "empty",
+		Run: func(cmd *Command, args []string) {},
+	})
+
+	correctMessage := "WORKS"
+	c.SetHelpCommand(&Command{
+		Use:   "help [command]",
+		Short: "Help about any command",
+		Long: `Help provides help for any command in the application.
+	Simply type ` + c.Name() + ` help [path to command] for full details.`,
+		Run: func(c *Command, args []string) { c.Print(correctMessage) },
+	})
+
+	if err := c.Execute(); err != nil {
+		t.Error("Unexpected error:", err)
+	}
+
+	if output.String() != correctMessage {
+		t.Errorf("Expected to contain %q message, but got %q", correctMessage, output.String())
+	}
+}