From 7319f042e4ef05856815f00ee070f567816e98ed Mon Sep 17 00:00:00 2001 From: Gregor Noczinski Date: Sat, 23 Jan 2016 12:47:24 +0100 Subject: [PATCH 1/2] * Added ability to customize usage error messages --- app.go | 30 +++++++++++++++++------- app_test.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ command.go | 17 ++++++++++---- command_test.go | 27 ++++++++++++++++++++++ 4 files changed, 123 insertions(+), 12 deletions(-) diff --git a/app.go b/app.go index 6884920..be35114 100644 --- a/app.go +++ b/app.go @@ -44,6 +44,10 @@ type App struct { Action func(context *Context) // Execute this function if the proper command cannot be found CommandNotFound func(context *Context, command string) + // Execute this function if an usage error occurs. This is useful for displaying customized usage error messages. + // This function is able to manipulate the original error in another. + // If this function is not set the "Incorrect usage" is displayed and the execution is interrupted. + OnUsageError func(context *Context, err error, isSubcommand bool) error // Compilation date Compiled time.Time // List of all authors who contributed @@ -132,10 +136,15 @@ func (a *App) Run(arguments []string) (err error) { } if err != nil { - fmt.Fprintln(a.Writer, "Incorrect Usage.") - fmt.Fprintln(a.Writer) - ShowAppHelp(context) - return err + if a.OnUsageError != nil { + err := a.OnUsageError(context, err, false) + return err + } else { + fmt.Fprintln(a.Writer, "Incorrect Usage.") + fmt.Fprintln(a.Writer) + ShowAppHelp(context) + return err + } } if !a.HideHelp && checkHelp(context) { @@ -242,10 +251,15 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } if err != nil { - fmt.Fprintln(a.Writer, "Incorrect Usage.") - fmt.Fprintln(a.Writer) - ShowSubcommandHelp(context) - return err + if a.OnUsageError != nil { + err = a.OnUsageError(context, err, true) + return err + } else { + fmt.Fprintln(a.Writer, "Incorrect Usage.") + fmt.Fprintln(a.Writer) + ShowSubcommandHelp(context) + return err + } } if len(a.Commands) > 0 { diff --git a/app_test.go b/app_test.go index 9a09405..fa8e2b1 100644 --- a/app_test.go +++ b/app_test.go @@ -9,6 +9,7 @@ import ( "os" "strings" "testing" +"errors" ) func ExampleApp_Run() { @@ -965,3 +966,63 @@ func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) { t.Errorf("expected text of error from After method, but got none in \"%v\"", err) } } + +func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) { + app := NewApp() + app.Flags = []Flag{ + IntFlag{Name: "flag"}, + } + app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { + if isSubcommand { + t.Errorf("Expect no subcommand") + } + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + } + app.Commands = []Command{ + Command{ + Name: "bar", + }, + } + + err := app.Run([]string{"foo", "--flag=wrong"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { + t.Errorf("Expect an intercepted error, but got \"%v\"", err) + } +} + +func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) { + app := NewApp() + app.Flags = []Flag{ + IntFlag{Name: "flag"}, + } + app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { + if isSubcommand { + t.Errorf("Expect subcommand") + } + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + } + app.Commands = []Command{ + Command{ + Name: "bar", + }, + } + + err := app.Run([]string{"foo", "--flag=wrong", "bar"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { + t.Errorf("Expect an intercepted error, but got \"%v\"", err) + } +} diff --git a/command.go b/command.go index e42178e..e448e2a 100644 --- a/command.go +++ b/command.go @@ -30,6 +30,10 @@ type Command struct { After func(context *Context) error // The function to call when this command is invoked Action func(context *Context) + // Execute this function if an usage error occurs. This is useful for displaying customized usage error messages. + // This function is able to manipulate the original error in another. + // If this function is not set the "Incorrect usage" is displayed and the execution is interrupted. + OnUsageError func(context *Context, err error) error // List of child commands Subcommands []Command // List of flags to parse @@ -110,10 +114,15 @@ func (c Command) Run(ctx *Context) (err error) { } if err != nil { - fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.") - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) - return err + if c.OnUsageError != nil { + err := c.OnUsageError(ctx, err) + return err + } else { + fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.") + fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) + return err + } } nerr := normalizeFlags(c.Flags, set) diff --git a/command_test.go b/command_test.go index 50bd875..87ede75 100644 --- a/command_test.go +++ b/command_test.go @@ -68,3 +68,30 @@ func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { t.Errorf("expected text of error from After method, but got none in \"%v\"", err) } } + +func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) { + app := NewApp() + app.Commands = []Command{ + Command{ + Name: "bar", + Flags: []Flag{ + IntFlag{Name: "flag"}, + }, + OnUsageError: func(c *Context, err error) error { + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + }, + }, + } + + err := app.Run([]string{"foo", "bar", "--flag=wrong"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { + t.Errorf("Expect an intercepted error, but got \"%v\"", err) + } +} From cb7a7c56eea7f9210e93e75ac149b90c357b7f97 Mon Sep 17 00:00:00 2001 From: Gregor Noczinski Date: Sat, 23 Jan 2016 14:50:25 +0100 Subject: [PATCH 2/2] * Fixed typos --- app.go | 6 +++--- command.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app.go b/app.go index be35114..d4d278f 100644 --- a/app.go +++ b/app.go @@ -44,9 +44,9 @@ type App struct { Action func(context *Context) // Execute this function if the proper command cannot be found CommandNotFound func(context *Context, command string) - // Execute this function if an usage error occurs. This is useful for displaying customized usage error messages. - // This function is able to manipulate the original error in another. - // If this function is not set the "Incorrect usage" is displayed and the execution is interrupted. + // Execute this function, if an usage error occurs. This is useful for displaying customized usage error messages. + // This function is able to replace the original error messages. + // If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted. OnUsageError func(context *Context, err error, isSubcommand bool) error // Compilation date Compiled time.Time diff --git a/command.go b/command.go index e448e2a..b2d797f 100644 --- a/command.go +++ b/command.go @@ -30,9 +30,9 @@ type Command struct { After func(context *Context) error // The function to call when this command is invoked Action func(context *Context) - // Execute this function if an usage error occurs. This is useful for displaying customized usage error messages. - // This function is able to manipulate the original error in another. - // If this function is not set the "Incorrect usage" is displayed and the execution is interrupted. + // Execute this function, if an usage error occurs. This is useful for displaying customized usage error messages. + // This function is able to replace the original error messages. + // If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted. OnUsageError func(context *Context, err error) error // List of child commands Subcommands []Command