Added exit code support
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
This commit is contained in:
parent
9c0db3f4ac
commit
49c1229409
54
app.go
54
app.go
@ -8,6 +8,11 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// Set to 125 which is the highest number not used in most shells
|
||||
DefaultExitCode int = 0
|
||||
)
|
||||
|
||||
// App is the main structure of a cli application. It is recomended that
|
||||
// an app be created with the cli.NewApp() function
|
||||
type App struct {
|
||||
@ -77,7 +82,7 @@ func NewApp() *App {
|
||||
}
|
||||
|
||||
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
|
||||
func (a *App) Run(arguments []string) (err error) {
|
||||
func (a *App) Run(arguments []string) (ec int, err error) {
|
||||
if a.Author != "" || a.Email != "" {
|
||||
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
|
||||
}
|
||||
@ -108,7 +113,7 @@ func (a *App) Run(arguments []string) (err error) {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
context := NewContext(a, set, nil)
|
||||
ShowAppHelp(context)
|
||||
return nerr
|
||||
return DefaultExitCode, nerr
|
||||
}
|
||||
context := NewContext(a, set, nil)
|
||||
|
||||
@ -116,24 +121,24 @@ func (a *App) Run(arguments []string) (err error) {
|
||||
fmt.Fprintln(a.Writer, "Incorrect Usage.")
|
||||
fmt.Fprintln(a.Writer)
|
||||
ShowAppHelp(context)
|
||||
return err
|
||||
return DefaultExitCode, err
|
||||
}
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if checkHelp(context) {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if checkVersion(context) {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
afterErr := a.After(context)
|
||||
afterEc, afterErr := a.After(context)
|
||||
if afterErr != nil {
|
||||
if err != nil {
|
||||
err = NewMultiError(err, afterErr)
|
||||
@ -141,13 +146,14 @@ func (a *App) Run(arguments []string) (err error) {
|
||||
err = afterErr
|
||||
}
|
||||
}
|
||||
ec = afterEc
|
||||
}()
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
ec, err = a.Before(context)
|
||||
if err != nil {
|
||||
return err
|
||||
return ec, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,20 +167,19 @@ func (a *App) Run(arguments []string) (err error) {
|
||||
}
|
||||
|
||||
// Run default Action
|
||||
a.Action(context)
|
||||
return nil
|
||||
return a.Action(context), nil
|
||||
}
|
||||
|
||||
// Another entry point to the cli app, takes care of passing arguments and error handling
|
||||
func (a *App) RunAndExitOnError() {
|
||||
if err := a.Run(os.Args); err != nil {
|
||||
if exitCode, err := a.Run(os.Args); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
func (a *App) RunAsSubcommand(ctx *Context) (ec int, err error) {
|
||||
// append help to commands
|
||||
if len(a.Commands) > 0 {
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
@ -205,33 +210,33 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
} else {
|
||||
ShowCommandHelp(ctx, context.Args().First())
|
||||
}
|
||||
return nerr
|
||||
return DefaultExitCode, nerr
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(a.Writer, "Incorrect Usage.")
|
||||
fmt.Fprintln(a.Writer)
|
||||
ShowSubcommandHelp(context)
|
||||
return err
|
||||
return DefaultExitCode, err
|
||||
}
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if len(a.Commands) > 0 {
|
||||
if checkSubcommandHelp(context) {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
} else {
|
||||
if checkCommandHelp(ctx, context.Args().First()) {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
afterErr := a.After(context)
|
||||
afterEc, afterErr := a.After(context)
|
||||
if afterErr != nil {
|
||||
if err != nil {
|
||||
err = NewMultiError(err, afterErr)
|
||||
@ -239,13 +244,14 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
err = afterErr
|
||||
}
|
||||
}
|
||||
ec = afterEc
|
||||
}()
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
ec, err = a.Before(context)
|
||||
if err != nil {
|
||||
return err
|
||||
return ec, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,9 +265,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
}
|
||||
|
||||
// Run default Action
|
||||
a.Action(context)
|
||||
|
||||
return nil
|
||||
return a.Action(context), nil
|
||||
}
|
||||
|
||||
// Returns the named command on App. Returns nil if the command does not exist
|
||||
|
15
command.go
15
command.go
@ -50,7 +50,7 @@ func (c Command) FullName() string {
|
||||
}
|
||||
|
||||
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (c Command) Run(ctx *Context) error {
|
||||
func (c Command) Run(ctx *Context) (int, error) {
|
||||
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
|
||||
return c.startApp(ctx)
|
||||
}
|
||||
@ -104,7 +104,7 @@ func (c Command) Run(ctx *Context) error {
|
||||
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
return err
|
||||
return DefaultExitCode, err
|
||||
}
|
||||
|
||||
nerr := normalizeFlags(c.Flags, set)
|
||||
@ -112,20 +112,19 @@ func (c Command) Run(ctx *Context) error {
|
||||
fmt.Fprintln(ctx.App.Writer, nerr)
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
return nerr
|
||||
return DefaultExitCode, nerr
|
||||
}
|
||||
context := NewContext(ctx.App, set, ctx)
|
||||
|
||||
if checkCommandCompletions(context, c.Name) {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if checkCommandHelp(context, c.Name) {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
context.Command = c
|
||||
c.Action(context)
|
||||
return nil
|
||||
return c.Action(context), nil
|
||||
}
|
||||
|
||||
func (c Command) Names() []string {
|
||||
@ -148,7 +147,7 @@ func (c Command) HasName(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c Command) startApp(ctx *Context) error {
|
||||
func (c Command) startApp(ctx *Context) (int, error) {
|
||||
app := NewApp()
|
||||
|
||||
// set the name and usage
|
||||
|
6
funcs.go
6
funcs.go
@ -5,14 +5,14 @@ type BashCompleteFn func(*Context)
|
||||
|
||||
// An action to execute before any subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no subcommands are run
|
||||
type BeforeFn func(*Context) error
|
||||
type BeforeFn func(*Context) (int, error)
|
||||
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
type AfterFn func(*Context) error
|
||||
type AfterFn func(*Context) (int, error)
|
||||
|
||||
// The action to execute when no subcommands are specified
|
||||
type ActionFn func(*Context)
|
||||
type ActionFn func(*Context) int
|
||||
|
||||
// Execute this function if the proper command cannot be found
|
||||
type CommandNotFoundFn func(*Context, string)
|
||||
|
6
help.go
6
help.go
@ -72,13 +72,14 @@ var helpCommand = Command{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
Action: func(c *Context) {
|
||||
Action: func(c *Context) int {
|
||||
args := c.Args()
|
||||
if args.Present() {
|
||||
ShowCommandHelp(c, args.First())
|
||||
} else {
|
||||
ShowAppHelp(c)
|
||||
}
|
||||
return 0
|
||||
},
|
||||
}
|
||||
|
||||
@ -86,13 +87,14 @@ var helpSubcommand = Command{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
Action: func(c *Context) {
|
||||
Action: func(c *Context) int {
|
||||
args := c.Args()
|
||||
if args.Present() {
|
||||
ShowCommandHelp(c, args.First())
|
||||
} else {
|
||||
ShowSubcommandHelp(c)
|
||||
}
|
||||
return 0
|
||||
},
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user