* Added ability to customize usage error messages

This commit is contained in:
Gregor Noczinski 2016-01-23 12:47:24 +01:00
parent f9cc3001e0
commit 7319f042e4
4 changed files with 123 additions and 12 deletions

30
app.go
View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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)
}
}