diff --git a/.gitignore b/.gitignore index 3b053c59e..b2b848e77 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,8 @@ Session.vim tags *.exe - +cobra cobra.test -.idea/* +.idea/ +*.iml diff --git a/cobra.go b/cobra.go index 6505c070b..d01becc8f 100644 --- a/cobra.go +++ b/cobra.go @@ -52,7 +52,7 @@ var EnableCommandSorting = true // 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. +var MousetrapHelpText = `This is a command line tool. You need to open cmd.exe and run it from there. ` @@ -61,7 +61,7 @@ You need to open cmd.exe and run it from there. // if the CLI is started from explorer.exe. Set to 0 to wait for the return key to be pressed. // To disable the mousetrap, just set MousetrapHelpText to blank string (""). // Works only on Microsoft Windows. -var MousetrapDisplayDuration time.Duration = 5 * time.Second +var MousetrapDisplayDuration = 5 * time.Second // AddTemplateFunc adds a template function that's available to Usage and Help // template generation. diff --git a/cobra/cmd/init.go b/cobra/cmd/init.go index 63397d119..dcf5ada4f 100644 --- a/cobra/cmd/init.go +++ b/cobra/cmd/init.go @@ -15,10 +15,11 @@ package cmd import ( "fmt" - "github.com/spf13/cobra" - "github.com/spf13/viper" "os" "path" + + "github.com/spf13/cobra" + "github.com/spf13/viper" ) var ( diff --git a/cobra/cmd/project.go b/cobra/cmd/project.go index dd2f7ea2f..a53893ccd 100644 --- a/cobra/cmd/project.go +++ b/cobra/cmd/project.go @@ -2,9 +2,10 @@ package cmd import ( "fmt" - "github.com/spf13/cobra/cobra/tpl" "os" "text/template" + + "github.com/spf13/cobra/cobra/tpl" ) // Project contains name, license and paths to projects. @@ -25,7 +26,6 @@ type Command struct { } func (p *Project) Create() error { - // check if AbsolutePath exists if _, err := os.Stat(p.AbsolutePath); os.IsNotExist(err) { // create directory diff --git a/cobra/cmd/root.go b/cobra/cmd/root.go index 624c717c1..97f404bbb 100644 --- a/cobra/cmd/root.go +++ b/cobra/cmd/root.go @@ -36,8 +36,8 @@ to quickly create a Cobra application.`, ) // Execute executes the root command. -func Execute() { - rootCmd.Execute() +func Execute() error { + return rootCmd.Execute() } func init() { diff --git a/cobra/main.go b/cobra/main.go index c3a9d9cb0..eeaf9824e 100644 --- a/cobra/main.go +++ b/cobra/main.go @@ -13,8 +13,14 @@ package main -import "github.com/spf13/cobra/cobra/cmd" +import ( + "os" + + "github.com/spf13/cobra/cobra/cmd" +) func main() { - cmd.Execute() + if err := cmd.Execute(); err != nil { + os.Exit(1) + } } diff --git a/command.go b/command.go index c7e898303..42e500de5 100644 --- a/command.go +++ b/command.go @@ -17,6 +17,7 @@ package cobra import ( "bytes" + "errors" "fmt" "io" "os" @@ -27,6 +28,8 @@ import ( flag "github.com/spf13/pflag" ) +var ErrSubCommandRequired = errors.New("subcommand is required") + // FParseErrWhitelist configures Flag parse errors to be ignored type FParseErrWhitelist flag.ParseErrorsWhitelist @@ -228,7 +231,7 @@ func (c *Command) SetErr(newErr io.Writer) { c.errWriter = newErr } -// SetOut sets the source for input data +// SetIn sets the source for input data // If newIn is nil, os.Stdin is used. func (c *Command) SetIn(newIn io.Reader) { c.inReader = newIn @@ -297,7 +300,7 @@ func (c *Command) ErrOrStderr() io.Writer { return c.getErr(os.Stderr) } -// ErrOrStderr returns output to stderr +// InOrStdin returns output to stderr func (c *Command) InOrStdin() io.Reader { return c.getIn(os.Stdin) } @@ -369,7 +372,7 @@ func (c *Command) HelpFunc() func(*Command, []string) { } return func(c *Command, a []string) { c.mergePersistentFlags() - err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) + err := tmpl(c.OutOrStderr(), c.HelpTemplate(), c) if err != nil { c.Println(err) } @@ -786,7 +789,7 @@ func (c *Command) execute(a []string) (err error) { } if !c.Runnable() { - return flag.ErrHelp + return ErrSubCommandRequired } c.preRun() @@ -920,6 +923,14 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { return cmd, nil } + // If command wasn't runnable, show full help, but do return the error. + // This will result in apps by default returning a non-success exit code, but also gives them the option to + // handle specially. + if err == ErrSubCommandRequired { + cmd.HelpFunc()(cmd, args) + return cmd, err + } + // If root command has SilentErrors flagged, // all subcommands should respect it if !cmd.SilenceErrors && !c.SilenceErrors { diff --git a/command_test.go b/command_test.go index 2fa2003cb..b26bd4abe 100644 --- a/command_test.go +++ b/command_test.go @@ -836,8 +836,8 @@ func TestHelpExecutedOnNonRunnableChild(t *testing.T) { rootCmd.AddCommand(childCmd) output, err := executeCommand(rootCmd, "child") - if err != nil { - t.Errorf("Unexpected error: %v", err) + if err != ErrSubCommandRequired { + t.Errorf("Expected error") } checkStringContains(t, output, childCmd.Long)