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"
|
"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
|
// App is the main structure of a cli application. It is recomended that
|
||||||
// an app be created with the cli.NewApp() function
|
// an app be created with the cli.NewApp() function
|
||||||
type App struct {
|
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
|
// 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 != "" {
|
if a.Author != "" || a.Email != "" {
|
||||||
a.Authors = append(a.Authors, Author{Name: a.Author, Email: 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)
|
fmt.Fprintln(a.Writer, nerr)
|
||||||
context := NewContext(a, set, nil)
|
context := NewContext(a, set, nil)
|
||||||
ShowAppHelp(context)
|
ShowAppHelp(context)
|
||||||
return nerr
|
return DefaultExitCode, nerr
|
||||||
}
|
}
|
||||||
context := NewContext(a, set, nil)
|
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, "Incorrect Usage.")
|
||||||
fmt.Fprintln(a.Writer)
|
fmt.Fprintln(a.Writer)
|
||||||
ShowAppHelp(context)
|
ShowAppHelp(context)
|
||||||
return err
|
return DefaultExitCode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkCompletions(context) {
|
if checkCompletions(context) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkHelp(context) {
|
if checkHelp(context) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkVersion(context) {
|
if checkVersion(context) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.After != nil {
|
if a.After != nil {
|
||||||
defer func() {
|
defer func() {
|
||||||
afterErr := a.After(context)
|
afterEc, afterErr := a.After(context)
|
||||||
if afterErr != nil {
|
if afterErr != nil {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = NewMultiError(err, afterErr)
|
err = NewMultiError(err, afterErr)
|
||||||
@ -141,13 +146,14 @@ func (a *App) Run(arguments []string) (err error) {
|
|||||||
err = afterErr
|
err = afterErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ec = afterEc
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.Before != nil {
|
if a.Before != nil {
|
||||||
err := a.Before(context)
|
ec, err = a.Before(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return ec, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,20 +167,19 @@ func (a *App) Run(arguments []string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run default Action
|
// Run default Action
|
||||||
a.Action(context)
|
return a.Action(context), nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Another entry point to the cli app, takes care of passing arguments and error handling
|
// Another entry point to the cli app, takes care of passing arguments and error handling
|
||||||
func (a *App) RunAndExitOnError() {
|
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)
|
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
|
// 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
|
// append help to commands
|
||||||
if len(a.Commands) > 0 {
|
if len(a.Commands) > 0 {
|
||||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||||
@ -205,33 +210,33 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
} else {
|
} else {
|
||||||
ShowCommandHelp(ctx, context.Args().First())
|
ShowCommandHelp(ctx, context.Args().First())
|
||||||
}
|
}
|
||||||
return nerr
|
return DefaultExitCode, nerr
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(a.Writer, "Incorrect Usage.")
|
fmt.Fprintln(a.Writer, "Incorrect Usage.")
|
||||||
fmt.Fprintln(a.Writer)
|
fmt.Fprintln(a.Writer)
|
||||||
ShowSubcommandHelp(context)
|
ShowSubcommandHelp(context)
|
||||||
return err
|
return DefaultExitCode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkCompletions(context) {
|
if checkCompletions(context) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a.Commands) > 0 {
|
if len(a.Commands) > 0 {
|
||||||
if checkSubcommandHelp(context) {
|
if checkSubcommandHelp(context) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if checkCommandHelp(ctx, context.Args().First()) {
|
if checkCommandHelp(ctx, context.Args().First()) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.After != nil {
|
if a.After != nil {
|
||||||
defer func() {
|
defer func() {
|
||||||
afterErr := a.After(context)
|
afterEc, afterErr := a.After(context)
|
||||||
if afterErr != nil {
|
if afterErr != nil {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = NewMultiError(err, afterErr)
|
err = NewMultiError(err, afterErr)
|
||||||
@ -239,13 +244,14 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
err = afterErr
|
err = afterErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ec = afterEc
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.Before != nil {
|
if a.Before != nil {
|
||||||
err := a.Before(context)
|
ec, err = a.Before(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return ec, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,9 +265,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run default Action
|
// Run default Action
|
||||||
a.Action(context)
|
return a.Action(context), nil
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the named command on App. Returns nil if the command does not exist
|
// 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
|
// 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 {
|
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
|
||||||
return c.startApp(ctx)
|
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, "Incorrect Usage.")
|
||||||
fmt.Fprintln(ctx.App.Writer)
|
fmt.Fprintln(ctx.App.Writer)
|
||||||
ShowCommandHelp(ctx, c.Name)
|
ShowCommandHelp(ctx, c.Name)
|
||||||
return err
|
return DefaultExitCode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nerr := normalizeFlags(c.Flags, set)
|
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, nerr)
|
||||||
fmt.Fprintln(ctx.App.Writer)
|
fmt.Fprintln(ctx.App.Writer)
|
||||||
ShowCommandHelp(ctx, c.Name)
|
ShowCommandHelp(ctx, c.Name)
|
||||||
return nerr
|
return DefaultExitCode, nerr
|
||||||
}
|
}
|
||||||
context := NewContext(ctx.App, set, ctx)
|
context := NewContext(ctx.App, set, ctx)
|
||||||
|
|
||||||
if checkCommandCompletions(context, c.Name) {
|
if checkCommandCompletions(context, c.Name) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkCommandHelp(context, c.Name) {
|
if checkCommandHelp(context, c.Name) {
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
context.Command = c
|
context.Command = c
|
||||||
c.Action(context)
|
return c.Action(context), nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Command) Names() []string {
|
func (c Command) Names() []string {
|
||||||
@ -148,7 +147,7 @@ func (c Command) HasName(name string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Command) startApp(ctx *Context) error {
|
func (c Command) startApp(ctx *Context) (int, error) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
|
|
||||||
// set the name and usage
|
// 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
|
// 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
|
// 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
|
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||||
// It is run even if Action() panics
|
// 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
|
// 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
|
// Execute this function if the proper command cannot be found
|
||||||
type CommandNotFoundFn func(*Context, string)
|
type CommandNotFoundFn func(*Context, string)
|
||||||
|
6
help.go
6
help.go
@ -72,13 +72,14 @@ var helpCommand = Command{
|
|||||||
Name: "help",
|
Name: "help",
|
||||||
Aliases: []string{"h"},
|
Aliases: []string{"h"},
|
||||||
Usage: "Shows a list of commands or help for one command",
|
Usage: "Shows a list of commands or help for one command",
|
||||||
Action: func(c *Context) {
|
Action: func(c *Context) int {
|
||||||
args := c.Args()
|
args := c.Args()
|
||||||
if args.Present() {
|
if args.Present() {
|
||||||
ShowCommandHelp(c, args.First())
|
ShowCommandHelp(c, args.First())
|
||||||
} else {
|
} else {
|
||||||
ShowAppHelp(c)
|
ShowAppHelp(c)
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,13 +87,14 @@ var helpSubcommand = Command{
|
|||||||
Name: "help",
|
Name: "help",
|
||||||
Aliases: []string{"h"},
|
Aliases: []string{"h"},
|
||||||
Usage: "Shows a list of commands or help for one command",
|
Usage: "Shows a list of commands or help for one command",
|
||||||
Action: func(c *Context) {
|
Action: func(c *Context) int {
|
||||||
args := c.Args()
|
args := c.Args()
|
||||||
if args.Present() {
|
if args.Present() {
|
||||||
ShowCommandHelp(c, args.First())
|
ShowCommandHelp(c, args.First())
|
||||||
} else {
|
} else {
|
||||||
ShowSubcommandHelp(c)
|
ShowSubcommandHelp(c)
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user