Skip to content

Commit

Permalink
Merge pull request #628 from phinnaeus/master
Browse files Browse the repository at this point in the history
Allow custom ExitError handler function
  • Loading branch information
jszwedko authored Oct 14, 2017
2 parents 2997500 + 40263f4 commit 7bc6a0a
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
26 changes: 19 additions & 7 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ type App struct {
Writer io.Writer
// ErrWriter writes error output
ErrWriter io.Writer
// Execute this function to handle ExitErrors. If not provided, HandleExitCoder is provided to
// function as a default, so this is optional.
ExitErrHandler ExitErrHandlerFunc
// Other custom info
Metadata map[string]interface{}
// Carries a function which returns app specific info.
Expand Down Expand Up @@ -207,7 +210,7 @@ func (a *App) Run(arguments []string) (err error) {
if err != nil {
if a.OnUsageError != nil {
err := a.OnUsageError(context, err, false)
HandleExitCoder(err)
a.handleExitCoder(context, err)
return err
}
fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
Expand Down Expand Up @@ -240,8 +243,9 @@ func (a *App) Run(arguments []string) (err error) {
if a.Before != nil {
beforeErr := a.Before(context)
if beforeErr != nil {
fmt.Fprintf(a.Writer, "%v\n\n", beforeErr)
ShowAppHelp(context)
HandleExitCoder(beforeErr)
a.handleExitCoder(context, beforeErr)
err = beforeErr
return err
}
Expand All @@ -263,7 +267,7 @@ func (a *App) Run(arguments []string) (err error) {
// Run default Action
err = HandleAction(a.Action, context)

HandleExitCoder(err)
a.handleExitCoder(context, err)
return err
}

Expand Down Expand Up @@ -330,7 +334,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
if err != nil {
if a.OnUsageError != nil {
err = a.OnUsageError(context, err, true)
HandleExitCoder(err)
a.handleExitCoder(context, err)
return err
}
fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
Expand All @@ -352,7 +356,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
defer func() {
afterErr := a.After(context)
if afterErr != nil {
HandleExitCoder(err)
a.handleExitCoder(context, err)
if err != nil {
err = NewMultiError(err, afterErr)
} else {
Expand All @@ -365,7 +369,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
if a.Before != nil {
beforeErr := a.Before(context)
if beforeErr != nil {
HandleExitCoder(beforeErr)
a.handleExitCoder(context, beforeErr)
err = beforeErr
return err
}
Expand All @@ -383,7 +387,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
// Run default Action
err = HandleAction(a.Action, context)

HandleExitCoder(err)
a.handleExitCoder(context, err)
return err
}

Expand Down Expand Up @@ -464,6 +468,14 @@ func (a *App) appendFlag(flag Flag) {
}
}

func (a *App) handleExitCoder(context *Context, err error) {
if a.ExitErrHandler != nil {
a.ExitErrHandler(context, err)
} else {
HandleExitCoder(err)
}
}

// Author represents someone who has contributed to a cli project.
type Author struct {
Name string // The Authors name
Expand Down
36 changes: 36 additions & 0 deletions app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,42 @@ func TestHandleAction_WithInvalidFuncReturnSignature(t *testing.T) {
}
}

func TestHandleExitCoder_Default(t *testing.T) {
app := NewApp()
fs, err := flagSet(app.Name, app.Flags)
if err != nil {
t.Errorf("error creating FlagSet: %s", err)
}

ctx := NewContext(app, fs, nil)
app.handleExitCoder(ctx, NewExitError("Default Behavior Error", 42))

output := fakeErrWriter.String()
if !strings.Contains(output, "Default") {
t.Fatalf("Expected Default Behavior from Error Handler but got: %s", output)
}
}

func TestHandleExitCoder_Custom(t *testing.T) {
app := NewApp()
fs, err := flagSet(app.Name, app.Flags)
if err != nil {
t.Errorf("error creating FlagSet: %s", err)
}

app.ExitErrHandler = func(_ *Context, _ error) {
fmt.Fprintln(ErrWriter, "I'm a Custom error handler, I print what I want!")
}

ctx := NewContext(app, fs, nil)
app.handleExitCoder(ctx, NewExitError("Default Behavior Error", 42))

output := fakeErrWriter.String()
if !strings.Contains(output, "Custom") {
t.Fatalf("Expected Custom Behavior from Error Handler but got: %s", output)
}
}

func TestHandleAction_WithUnknownPanic(t *testing.T) {
defer func() { refute(t, recover(), nil) }()

Expand Down
8 changes: 4 additions & 4 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (c Command) Run(ctx *Context) (err error) {
if err != nil {
if c.OnUsageError != nil {
err := c.OnUsageError(context, err, false)
HandleExitCoder(err)
context.App.handleExitCoder(context, err)
return err
}
fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error())
Expand All @@ -184,7 +184,7 @@ func (c Command) Run(ctx *Context) (err error) {
defer func() {
afterErr := c.After(context)
if afterErr != nil {
HandleExitCoder(err)
context.App.handleExitCoder(context, err)
if err != nil {
err = NewMultiError(err, afterErr)
} else {
Expand All @@ -198,7 +198,7 @@ func (c Command) Run(ctx *Context) (err error) {
err = c.Before(context)
if err != nil {
ShowCommandHelp(context, c.Name)
HandleExitCoder(err)
context.App.handleExitCoder(context, err)
return err
}
}
Expand All @@ -210,7 +210,7 @@ func (c Command) Run(ctx *Context) (err error) {
err = HandleAction(c.Action, context)

if err != nil {
HandleExitCoder(err)
context.App.handleExitCoder(context, err)
}
return err
}
Expand Down
5 changes: 5 additions & 0 deletions funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ type CommandNotFoundFunc func(*Context, string)
// is displayed and the execution is interrupted.
type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error

// ExitErrHandlerFunc is executed if provided in order to handle ExitError values
// returned by Actions and Before/After functions.
type ExitErrHandlerFunc func(context *Context, err error)

// FlagStringFunc is used by the help generation to display a flag, which is
// expected to be a single line.
type FlagStringFunc func(Flag) string
Expand All @@ -34,3 +38,4 @@ type FlagNamePrefixFunc func(fullName, placeholder string) string
// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help
// with the environment variable details.
type FlagEnvHintFunc func(envVar, str string) string

0 comments on commit 7bc6a0a

Please sign in to comment.