From c48a82964028acd0f19ee17257789f7c9f5afc78 Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Tue, 25 Apr 2017 09:29:43 -0700 Subject: [PATCH 01/11] Allow custom exit err handlers --- app.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/app.go b/app.go index 51fc45d..5d7ed8b 100644 --- a/app.go +++ b/app.go @@ -83,6 +83,8 @@ type App struct { Writer io.Writer // ErrWriter writes error output ErrWriter io.Writer + // Execute this function to handle ExitErrors + ExitErrHandler ExitErrHandlerFunc // Other custom info Metadata map[string]interface{} // Carries a function which returns app specific info. @@ -207,7 +209,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(err) return err } fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) @@ -241,7 +243,7 @@ func (a *App) Run(arguments []string) (err error) { beforeErr := a.Before(context) if beforeErr != nil { ShowAppHelp(context) - HandleExitCoder(beforeErr) + a.handleExitCoder(beforeErr) err = beforeErr return err } @@ -263,7 +265,7 @@ func (a *App) Run(arguments []string) (err error) { // Run default Action err = HandleAction(a.Action, context) - HandleExitCoder(err) + a.handleExitCoder(err) return err } @@ -330,7 +332,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(err) return err } fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) @@ -352,7 +354,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { defer func() { afterErr := a.After(context) if afterErr != nil { - HandleExitCoder(err) + a.handleExitCoder(err) if err != nil { err = NewMultiError(err, afterErr) } else { @@ -365,7 +367,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if a.Before != nil { beforeErr := a.Before(context) if beforeErr != nil { - HandleExitCoder(beforeErr) + a.handleExitCoder(beforeErr) err = beforeErr return err } @@ -383,7 +385,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { // Run default Action err = HandleAction(a.Action, context) - HandleExitCoder(err) + a.handleExitCoder(err) return err } @@ -464,6 +466,14 @@ func (a *App) appendFlag(flag Flag) { } } +func (a *App) handleExitCoder(err error) { + if a.ExitErrHandler != nil { + a.ExitErrHandler(err) + } else { + HandleExitCoder(err) + } +} + // Author represents someone who has contributed to a cli project. type Author struct { Name string // The Authors name From 538742687bbd979a7b4f975468af76ce5cffb972 Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Tue, 25 Apr 2017 09:31:53 -0700 Subject: [PATCH 02/11] Add ExitErrHandlerFunc type --- funcs.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/funcs.go b/funcs.go index cba5e6c..4737faf 100644 --- a/funcs.go +++ b/funcs.go @@ -26,3 +26,7 @@ type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) 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 + +// ExitErrHandlerFunc is executed if provided in order to handle ExitError values +// returned by Actions and Before/After functions. +type ExitErrHandlerFunc func(error) From 827da610b4bff0ffbc06cd2d92eddae552f7d1a2 Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Tue, 25 Apr 2017 09:33:54 -0700 Subject: [PATCH 03/11] Add a bit more documentation --- app.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app.go b/app.go index 5d7ed8b..4138f32 100644 --- a/app.go +++ b/app.go @@ -83,7 +83,8 @@ type App struct { Writer io.Writer // ErrWriter writes error output ErrWriter io.Writer - // Execute this function to handle ExitErrors + // 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{} From 80b09a4d1117ad69430582685e59dfe560caa948 Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Tue, 25 Apr 2017 11:20:41 -0700 Subject: [PATCH 04/11] Fix how to do defaults in app.go --- app.go | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/app.go b/app.go index 4138f32..f1a8f27 100644 --- a/app.go +++ b/app.go @@ -121,6 +121,7 @@ func NewApp() *App { Action: helpCommand.Action, Compiled: compileTime(), Writer: os.Stdout, + ExitErrHandler: HandleExitCoder, } } @@ -210,7 +211,7 @@ func (a *App) Run(arguments []string) (err error) { if err != nil { if a.OnUsageError != nil { err := a.OnUsageError(context, err, false) - a.handleExitCoder(err) + a.ExitErrHandler(err) return err } fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) @@ -244,7 +245,7 @@ func (a *App) Run(arguments []string) (err error) { beforeErr := a.Before(context) if beforeErr != nil { ShowAppHelp(context) - a.handleExitCoder(beforeErr) + a.ExitErrHandler(beforeErr) err = beforeErr return err } @@ -266,7 +267,7 @@ func (a *App) Run(arguments []string) (err error) { // Run default Action err = HandleAction(a.Action, context) - a.handleExitCoder(err) + a.ExitErrHandler(err) return err } @@ -333,7 +334,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if err != nil { if a.OnUsageError != nil { err = a.OnUsageError(context, err, true) - a.handleExitCoder(err) + a.ExitErrHandler(err) return err } fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) @@ -355,7 +356,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { defer func() { afterErr := a.After(context) if afterErr != nil { - a.handleExitCoder(err) + a.ExitErrHandler(err) if err != nil { err = NewMultiError(err, afterErr) } else { @@ -368,7 +369,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if a.Before != nil { beforeErr := a.Before(context) if beforeErr != nil { - a.handleExitCoder(beforeErr) + a.ExitErrHandler(beforeErr) err = beforeErr return err } @@ -386,7 +387,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { // Run default Action err = HandleAction(a.Action, context) - a.handleExitCoder(err) + a.ExitErrHandler(err) return err } @@ -467,14 +468,6 @@ func (a *App) appendFlag(flag Flag) { } } -func (a *App) handleExitCoder(err error) { - if a.ExitErrHandler != nil { - a.ExitErrHandler(err) - } else { - HandleExitCoder(err) - } -} - // Author represents someone who has contributed to a cli project. type Author struct { Name string // The Authors name From ceee6408d5cbbb9f113157d0a62b1ffed1f2b510 Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Tue, 25 Apr 2017 13:02:05 -0700 Subject: [PATCH 05/11] Revert "Fix how to do defaults in app.go" This reverts commit 8906567dc2ad52fd31c50cf02fa606505a1323ba. --- app.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/app.go b/app.go index f1a8f27..e9ed7ab 100644 --- a/app.go +++ b/app.go @@ -121,7 +121,6 @@ func NewApp() *App { Action: helpCommand.Action, Compiled: compileTime(), Writer: os.Stdout, - ExitErrHandler: HandleExitCoder, } } @@ -211,7 +210,7 @@ func (a *App) Run(arguments []string) (err error) { if err != nil { if a.OnUsageError != nil { err := a.OnUsageError(context, err, false) - a.ExitErrHandler(err) + a.handleExitCoder(err) return err } fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) @@ -244,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) - a.ExitErrHandler(beforeErr) + a.handleExitCoder(beforeErr) err = beforeErr return err } @@ -267,7 +267,7 @@ func (a *App) Run(arguments []string) (err error) { // Run default Action err = HandleAction(a.Action, context) - a.ExitErrHandler(err) + a.handleExitCoder(err) return err } @@ -334,7 +334,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if err != nil { if a.OnUsageError != nil { err = a.OnUsageError(context, err, true) - a.ExitErrHandler(err) + a.handleExitCoder(err) return err } fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) @@ -356,7 +356,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { defer func() { afterErr := a.After(context) if afterErr != nil { - a.ExitErrHandler(err) + a.handleExitCoder(err) if err != nil { err = NewMultiError(err, afterErr) } else { @@ -369,7 +369,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if a.Before != nil { beforeErr := a.Before(context) if beforeErr != nil { - a.ExitErrHandler(beforeErr) + a.handleExitCoder(beforeErr) err = beforeErr return err } @@ -387,7 +387,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { // Run default Action err = HandleAction(a.Action, context) - a.ExitErrHandler(err) + a.handleExitCoder(err) return err } @@ -468,6 +468,14 @@ func (a *App) appendFlag(flag Flag) { } } +func (a *App) handleExitCoder(err error) { + if a.ExitErrHandler != nil { + a.ExitErrHandler(err) + } else { + HandleExitCoder(err) + } +} + // Author represents someone who has contributed to a cli project. type Author struct { Name string // The Authors name From 9d61cbad0260bc7f2a72b07142a0120072e3800a Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Tue, 25 Apr 2017 12:45:08 -0700 Subject: [PATCH 06/11] Updated command.go to use App handleExitCoder --- command.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/command.go b/command.go index 23de294..fffa02f 100644 --- a/command.go +++ b/command.go @@ -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(err) return err } fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) @@ -184,7 +184,7 @@ func (c Command) Run(ctx *Context) (err error) { defer func() { afterErr := c.After(context) if afterErr != nil { - HandleExitCoder(err) + ctx.App.handleExitCoder(err) if err != nil { err = NewMultiError(err, afterErr) } else { @@ -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(err) return err } } @@ -210,7 +210,7 @@ func (c Command) Run(ctx *Context) (err error) { err = HandleAction(c.Action, context) if err != nil { - HandleExitCoder(err) + ctx.App.handleExitCoder(err) } return err } From 530df59178874f8d792d2d9cfd745464076f1eda Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Wed, 28 Jun 2017 09:52:12 -0700 Subject: [PATCH 07/11] Pass context into handleExitCoder --- app.go | 18 +++++++++--------- command.go | 8 ++++---- funcs.go | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app.go b/app.go index e9ed7ab..48de351 100644 --- a/app.go +++ b/app.go @@ -210,7 +210,7 @@ func (a *App) Run(arguments []string) (err error) { if err != nil { if a.OnUsageError != nil { err := a.OnUsageError(context, err, false) - a.handleExitCoder(err) + a.handleExitCoder(context, err) return err } fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) @@ -245,7 +245,7 @@ func (a *App) Run(arguments []string) (err error) { if beforeErr != nil { fmt.Fprintf(a.Writer, "%v\n\n", beforeErr) ShowAppHelp(context) - a.handleExitCoder(beforeErr) + a.handleExitCoder(context, beforeErr) err = beforeErr return err } @@ -267,7 +267,7 @@ func (a *App) Run(arguments []string) (err error) { // Run default Action err = HandleAction(a.Action, context) - a.handleExitCoder(err) + a.handleExitCoder(context, err) return err } @@ -334,7 +334,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if err != nil { if a.OnUsageError != nil { err = a.OnUsageError(context, err, true) - a.handleExitCoder(err) + a.handleExitCoder(context, err) return err } fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) @@ -356,7 +356,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { defer func() { afterErr := a.After(context) if afterErr != nil { - a.handleExitCoder(err) + a.handleExitCoder(context, err) if err != nil { err = NewMultiError(err, afterErr) } else { @@ -369,7 +369,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if a.Before != nil { beforeErr := a.Before(context) if beforeErr != nil { - a.handleExitCoder(beforeErr) + a.handleExitCoder(context, beforeErr) err = beforeErr return err } @@ -387,7 +387,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { // Run default Action err = HandleAction(a.Action, context) - a.handleExitCoder(err) + a.handleExitCoder(context, err) return err } @@ -468,9 +468,9 @@ func (a *App) appendFlag(flag Flag) { } } -func (a *App) handleExitCoder(err error) { +func (a *App) handleExitCoder(context *Context, error) { if a.ExitErrHandler != nil { - a.ExitErrHandler(err) + a.ExitErrHandler(context, err) } else { HandleExitCoder(err) } diff --git a/command.go b/command.go index fffa02f..502fc9f 100644 --- a/command.go +++ b/command.go @@ -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) - context.App.handleExitCoder(err) + context.App.handleExitCoder(context, err) return err } fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) @@ -184,7 +184,7 @@ func (c Command) Run(ctx *Context) (err error) { defer func() { afterErr := c.After(context) if afterErr != nil { - ctx.App.handleExitCoder(err) + context.App.handleExitCoder(context, err) if err != nil { err = NewMultiError(err, afterErr) } else { @@ -198,7 +198,7 @@ func (c Command) Run(ctx *Context) (err error) { err = c.Before(context) if err != nil { ShowCommandHelp(context, c.Name) - context.App.handleExitCoder(err) + context.App.handleExitCoder(context, err) return err } } @@ -210,7 +210,7 @@ func (c Command) Run(ctx *Context) (err error) { err = HandleAction(c.Action, context) if err != nil { - ctx.App.handleExitCoder(err) + context.App.handleExitCoder(context, err) } return err } diff --git a/funcs.go b/funcs.go index 4737faf..42023e2 100644 --- a/funcs.go +++ b/funcs.go @@ -29,4 +29,4 @@ type FlagStringFunc func(Flag) string // ExitErrHandlerFunc is executed if provided in order to handle ExitError values // returned by Actions and Before/After functions. -type ExitErrHandlerFunc func(error) +type ExitErrHandlerFunc func(context *Context, error) From 172bb92059ed885c8b4249230f3ccbe9e3e1272b Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Wed, 28 Jun 2017 10:07:25 -0700 Subject: [PATCH 08/11] fix named parameter issue --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index 48de351..1876b5c 100644 --- a/app.go +++ b/app.go @@ -468,7 +468,7 @@ func (a *App) appendFlag(flag Flag) { } } -func (a *App) handleExitCoder(context *Context, error) { +func (a *App) handleExitCoder(context *Context, err error) { if a.ExitErrHandler != nil { a.ExitErrHandler(context, err) } else { From 71bdf81f5a65dc253482cb727c2ae973ae3b3830 Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Wed, 28 Jun 2017 10:10:11 -0700 Subject: [PATCH 09/11] sigh... fix one more named parameter issue --- funcs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funcs.go b/funcs.go index 42023e2..2274415 100644 --- a/funcs.go +++ b/funcs.go @@ -29,4 +29,4 @@ type FlagStringFunc func(Flag) string // ExitErrHandlerFunc is executed if provided in order to handle ExitError values // returned by Actions and Before/After functions. -type ExitErrHandlerFunc func(context *Context, error) +type ExitErrHandlerFunc func(context *Context, err error) From 58450552ee1bada60f4175897aff8d69f7c904a1 Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Wed, 28 Jun 2017 12:52:50 -0700 Subject: [PATCH 10/11] Add Test --- app_test.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/app_test.go b/app_test.go index e14ddaf..63e28c7 100644 --- a/app_test.go +++ b/app_test.go @@ -1661,6 +1661,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, errors.New("Default Behavior Error")) + + 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, errors.New("Default Behavior Error")) + + 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) }() From 5d528e2052b3e7a49293d6aa0fac245047ea61e3 Mon Sep 17 00:00:00 2001 From: Tyler Davis Date: Wed, 28 Jun 2017 13:04:09 -0700 Subject: [PATCH 11/11] use exit errors in uts --- app_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app_test.go b/app_test.go index 63e28c7..9ff6246 100644 --- a/app_test.go +++ b/app_test.go @@ -1669,7 +1669,7 @@ func TestHandleExitCoder_Default(t *testing.T) { } ctx := NewContext(app, fs, nil) - app.handleExitCoder(ctx, errors.New("Default Behavior Error")) + app.handleExitCoder(ctx, NewExitError("Default Behavior Error", 42)) output := fakeErrWriter.String() if !strings.Contains(output, "Default") { @@ -1689,7 +1689,7 @@ func TestHandleExitCoder_Custom(t *testing.T) { } ctx := NewContext(app, fs, nil) - app.handleExitCoder(ctx, errors.New("Default Behavior Error")) + app.handleExitCoder(ctx, NewExitError("Default Behavior Error", 42)) output := fakeErrWriter.String() if !strings.Contains(output, "Custom") {