Added Before method to command and app

This commit is contained in:
Dario Castañé 2014-11-18 23:44:21 +01:00
parent 229729fae6
commit 44efc2952d
3 changed files with 91 additions and 6 deletions

23
app.go
View File

@ -31,6 +31,9 @@ type App struct {
// 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
Before func(context *Context) error Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run regardless of Because() result
After func(context *Context) error
// The action to execute when no subcommands are specified // The action to execute when no subcommands are specified
Action func(context *Context) Action func(context *Context)
// Execute this function if the proper command cannot be found // Execute this function if the proper command cannot be found
@ -66,7 +69,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) error { func (a *App) Run(arguments []string) (err error) {
// append help to commands // append help to commands
if a.Command(helpCommand.Name) == nil && !a.HideHelp { if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand) a.Commands = append(a.Commands, helpCommand)
@ -85,7 +88,7 @@ func (a *App) Run(arguments []string) error {
// parse flags // parse flags
set := flagSet(a.Name, a.Flags) set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard) set.SetOutput(ioutil.Discard)
err := set.Parse(arguments[1:]) err = set.Parse(arguments[1:])
nerr := normalizeFlags(a.Flags, set) nerr := normalizeFlags(a.Flags, set)
if nerr != nil { if nerr != nil {
fmt.Println(nerr) fmt.Println(nerr)
@ -115,6 +118,12 @@ func (a *App) Run(arguments []string) error {
return nil return nil
} }
if a.After != nil {
defer func() {
err = a.After(context)
}()
}
if a.Before != nil { if a.Before != nil {
err := a.Before(context) err := a.Before(context)
if err != nil { if err != nil {
@ -145,7 +154,7 @@ func (a *App) RunAndExitOnError() {
} }
// 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) error { func (a *App) RunAsSubcommand(ctx *Context) (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 {
@ -162,7 +171,7 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
// parse flags // parse flags
set := flagSet(a.Name, a.Flags) set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard) set.SetOutput(ioutil.Discard)
err := set.Parse(ctx.Args().Tail()) err = set.Parse(ctx.Args().Tail())
nerr := normalizeFlags(a.Flags, set) nerr := normalizeFlags(a.Flags, set)
context := NewContext(a, set, ctx.globalSet) context := NewContext(a, set, ctx.globalSet)
@ -197,6 +206,12 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
} }
} }
if a.After != nil {
defer func() {
err = a.After(context)
}()
}
if a.Before != nil { if a.Before != nil {
err := a.Before(context) err := a.Before(context)
if err != nil { if err != nil {

View File

@ -5,7 +5,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/codegangsta/cli" "github.com/imdario/cli"
) )
func ExampleApp() { func ExampleApp() {
@ -331,6 +331,72 @@ func TestApp_BeforeFunc(t *testing.T) {
} }
func TestApp_AfterFunc(t *testing.T) {
afterRun, subcommandRun := false, false
afterError := fmt.Errorf("fail")
var err error
app := cli.NewApp()
app.After = func(c *cli.Context) error {
afterRun = true
s := c.String("opt")
if s == "fail" {
return afterError
}
return nil
}
app.Commands = []cli.Command{
cli.Command{
Name: "sub",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "opt"},
}
// run with the After() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
afterRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != afterError {
t.Errorf("Run error expected, but not received")
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
}
func TestAppHelpPrinter(t *testing.T) { func TestAppHelpPrinter(t *testing.T) {
oldPrinter := cli.HelpPrinter oldPrinter := cli.HelpPrinter
defer func() { defer func() {

View File

@ -21,6 +21,9 @@ type Command struct {
// An action to execute before any sub-subcommands are run, but after the context is ready // An action to execute before any sub-subcommands are run, but after the context is ready
// If a non-nil error is returned, no sub-subcommands are run // If a non-nil error is returned, no sub-subcommands are run
Before func(context *Context) error Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run regardless of Because() result
After func(context *Context) error
// The function to call when this command is invoked // The function to call when this command is invoked
Action func(context *Context) Action func(context *Context)
// List of child commands // List of child commands
@ -36,7 +39,7 @@ type Command struct {
// 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) error {
if len(c.Subcommands) > 0 || c.Before != nil { if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
return c.startApp(ctx) return c.startApp(ctx)
} }
@ -134,6 +137,7 @@ func (c Command) startApp(ctx *Context) error {
// set the actions // set the actions
app.Before = c.Before app.Before = c.Before
app.After = c.After
if c.Action != nil { if c.Action != nil {
app.Action = c.Action app.Action = c.Action
} else { } else {