Add support for setting a function to handle flag parsing errors.

The default pflag error is to only print the bad flag. This enables an application
to include a usage message or other details about the error.

Signed-off-by: Daniel Nephin <dnephin@gmail.com>
This commit is contained in:
Daniel Nephin 2016-05-25 14:27:02 -07:00
parent 9c28e4bbd7
commit 67feb8173c
3 changed files with 55 additions and 7 deletions

View file

@ -113,6 +113,7 @@ type Command struct {
output *io.Writer // out writer if set in SetOutput(w) output *io.Writer // out writer if set in SetOutput(w)
usageFunc func(*Command) error // Usage can be defined by application usageFunc func(*Command) error // Usage can be defined by application
usageTemplate string // Can be defined by Application usageTemplate string // Can be defined by Application
flagErrorFunc func(*Command, error) error
helpTemplate string // Can be defined by Application helpTemplate string // Can be defined by Application
helpFunc func(*Command, []string) // Help can be defined by application helpFunc func(*Command, []string) // Help can be defined by application
helpCommand *Command // The help command helpCommand *Command // The help command
@ -150,7 +151,13 @@ func (c *Command) SetUsageTemplate(s string) {
c.usageTemplate = s c.usageTemplate = s
} }
// Can be defined by Application. // SetFlagErrorFunc sets a function to generate an error when flag parsing
// fails
func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) {
c.flagErrorFunc = f
}
// Can be defined by Application
func (c *Command) SetHelpFunc(f func(*Command, []string)) { func (c *Command) SetHelpFunc(f func(*Command, []string)) {
c.helpFunc = f c.helpFunc = f
} }
@ -257,6 +264,22 @@ func (c *Command) UsageString() string {
return bb.String() return bb.String()
} }
// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this
// command or a parent, or it returns a function which returns the original
// error.
func (c *Command) FlagErrorFunc() (f func(*Command, error) error) {
if c.flagErrorFunc != nil {
return c.flagErrorFunc
}
if c.HasParent() {
return c.parent.FlagErrorFunc()
}
return func(c *Command, err error) error {
return err
}
}
var minUsagePadding = 25 var minUsagePadding = 25
func (c *Command) UsagePadding() int { func (c *Command) UsagePadding() int {
@ -553,7 +576,7 @@ func (c *Command) execute(a []string) (err error) {
err = c.ParseFlags(a) err = c.ParseFlags(a)
if err != nil { if err != nil {
return err return c.FlagErrorFunc()(c, err)
} }
// If help is called, regardless of other flags, return we want help // If help is called, regardless of other flags, return we want help
// Also say we need help if the command isn't runnable. // Also say we need help if the command isn't runnable.

View file

@ -1,6 +1,8 @@
package cobra package cobra
import ( import (
"bytes"
"fmt"
"os" "os"
"reflect" "reflect"
"testing" "testing"
@ -174,3 +176,27 @@ func TestEnableCommandSortingIsDisabled(t *testing.T) {
EnableCommandSorting = true EnableCommandSorting = true
} }
func TestFlagErrorFunc(t *testing.T) {
cmd := &Command{
Use: "print",
RunE: func(cmd *Command, args []string) error {
return nil
},
}
expectedFmt := "This is expected: %s"
cmd.SetFlagErrorFunc(func(c *Command, err error) error {
return fmt.Errorf(expectedFmt, err)
})
cmd.SetArgs([]string{"--bogus-flag"})
cmd.SetOutput(new(bytes.Buffer))
err := cmd.Execute()
expected := fmt.Sprintf(expectedFmt, "unknown flag: --bogus-flag")
if err.Error() != expected {
t.Errorf("expected %v, got %v", expected, err.Error())
}
}

View file

@ -101,4 +101,3 @@ linkHandler := func(name string) string {
return "/commands/" + strings.ToLower(base) + "/" return "/commands/" + strings.ToLower(base) + "/"
} }
``` ```