Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional exit code support #361

Merged
merged 27 commits into from
Apr 30, 2016
Merged

Optional exit code support #361

merged 27 commits into from
Apr 30, 2016

Conversation

meatballhat
Copy link
Member

@meatballhat meatballhat commented Apr 25, 2016

This began as a merge resolution of #266 with some whitespace formatting fixes in README, exposed definition of default "success" and "error" exit codes, and style change from .*Fn$ to .*Func$ func type names. Based on discussion below, the patch is evolving:

  • switch from int in return signature to optional custom error type
  • does it blend?

See changes to CHANGELOG.md for more details.

Closes #266

txgruppi and others added 6 commits July 28, 2015 20:02
The function used by BashComplete, Before, After, Action and
CommandNotFound have their won type.

This makes easier to change/update the API
Now the exit code can be returned by BeforeFn, ActionFn and AfterFn.

The `os.Exit` function is not called by this packaged

This closes #66 and closes #164
@meatballhat meatballhat self-assigned this Apr 25, 2016
@codegangsta codegangsta added the status/claimed someone has claimed this issue label Apr 25, 2016
@meatballhat meatballhat added this to the v2.0.0 milestone Apr 25, 2016
@meatballhat meatballhat added the kind/feature describes a code enhancement / feature request label Apr 25, 2016
}
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
err := command.Run(c)
command := &cli.Command{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@jszwedko
Copy link
Contributor

@meatballhat overall 👍, I like the idea of allowing the centralization of error handling.

Did you also consider this approach in comparison to having Actions return an err? I don't have a strong opinion yet, but I was just curious if you had any thoughts.

@meatballhat
Copy link
Member Author

tbh I feel weird about Action returning an int, and the switch to multi-returns in general. I'd rather keep single-return error signatures everywhere and provide a helper func to allow folks to bubble up their own exit code, but only if they want to, e.g.:

// ...
app.Action = func(ctx *cli.Context) error {
    // ... bleep bloop
    return cli.NewExitError("invalid blooping", 3)
}

... which we would handle internally a la:

err := app.Action(ctx)
if exitErr, ok := err.(*ExitError); ok {
    // do stuff maybe
    os.Exit(exitErr.Code)
}
// else don't os.Exit...

whaddya think?

@jszwedko
Copy link
Contributor

I am a big fan of this approach over the int

@meatballhat meatballhat changed the title Merging #266 to add exit code support Optional exit code support Apr 26, 2016
@meatballhat
Copy link
Member Author

@txgruppi Please jump in and let us know your thoughts! 😻

@txgruppi
Copy link
Member

@meatballhat I like the idea of having an error that can bubble up the exit code. 😄

@meatballhat
Copy link
Member Author

@txgruppi @jszwedko what are your thoughts on using reflection to ease migration such that folks can continue to use Action = func(ctx *cli.Context) { } but will get a deprecation warning? I'm thinking about anyone who's using this library without version pinning tools.

@txgruppi
Copy link
Member

@meatballhat for sure it will be great, I believe the great majority of the users don't use any type of versioning for Go packages. Sadly I am one of them 😞

I'm not sure about performance costs of using reflection but I believe it doesn't apply to this package

@meatballhat
Copy link
Member Author

@txgruppi yep, I have a few projects kicking around that don't version pin 😺 I seriously doubt this will have any performance impact 🔬

@jszwedko
Copy link
Contributor

jszwedko commented Apr 28, 2016

@meatballhat nice, I really like the use of reflection to support backwards compatibility (still reviewing to leave inline notes).

Action func(context *Context)
Action interface{}
// TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind
// of deprecation period has passed, maybe?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@jszwedko
Copy link
Contributor

I left one comment that may need action taken, but otherwise this is great. I like that you were able to preserve backwards compatibility (at the cost of type safety, but I think it is acceptable in this case). We can remove support for the deprecated signature in the future.

The only other way I can think of preserving backwards compatibility is to add another field on the struct, but I think this would introduce a more complexity into the code (thus causing bugs) so I think your approach is appropriate.

// ActionFunc or LegacyActionFunc, the func is run!
func HandleAction(action interface{}, context *Context) error {
if reflect.TypeOf(action).Kind() != reflect.Func {
panic("given Action must be a func")
Copy link
Member

@txgruppi txgruppi Apr 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be a returned error?

@@ -404,16 +417,16 @@ func HandleAction(action interface{}, context *Context) error {
if len(vals) == 0 {
fmt.Fprintln(os.Stderr,
"DEPRECATED Action signature. Must be `cli.ActionFunc`")
return nil
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda like return nil here -- return err visually implies to me that it it is not nil.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aaah, nvm, I think I see now that this would end up being a real error if there is a panic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, maybe, now I've confused myself. Is there a case where this wouldn't return nil?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this branch will only allow nil, yep. I think I was being overly zealous with the defer impl above.

@@ -14,11 +14,13 @@ import (
var (
appActionDeprecationURL = "https://github.com/codegangsta/cli/blob/master/CHANGELOG.md#deprecated-cli-app-action-signature"

contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

@jszwedko
Copy link
Contributor

:shipit:

@meatballhat meatballhat merged commit 663fc0b into master Apr 30, 2016
@meatballhat meatballhat deleted the txgruppi-develop branch April 30, 2016 12:14
@codegangsta codegangsta removed the status/claimed someone has claimed this issue label Apr 30, 2016
jszwedko added a commit that referenced this pull request Feb 4, 2017
Doing so limits the ability for users to have only some of their errors
cause the application to terminate while allowing others to bubble up.

This was originally an adjustment to #361 in #496 to fix #495, but, in
hindsight, I believe that the better approach is to recommend the use of
`RunAndExitOnError` for this use case (which is undeprecated here).

Fixes #565 #594
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature describes a code enhancement / feature request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants