Update spf13/pflag dep

This commit is contained in:
Tim Hockin 2015-04-27 14:55:31 -07:00
parent 39c5bf363b
commit 22db9fb176
3 changed files with 133 additions and 38 deletions

2
Godeps/Godeps.json generated
View File

@ -385,7 +385,7 @@
}, },
{ {
"ImportPath": "github.com/spf13/pflag", "ImportPath": "github.com/spf13/pflag",
"Rev": "18d831e92d67eafd1b0db8af9ffddbd04f7ae1f4" "Rev": "60d4c375939ff7ba397a84117d5281256abb298f"
}, },
{ {
"ImportPath": "github.com/stretchr/objx", "ImportPath": "github.com/stretchr/objx",

View File

@ -120,6 +120,10 @@ const (
PanicOnError PanicOnError
) )
// normalizedName is a flag name that has been normalized according to rules
// for the FlagSet (e.g. making '-' and '_' equivalent).
type normalizedName string
// A FlagSet represents a set of defined flags. // A FlagSet represents a set of defined flags.
type FlagSet struct { type FlagSet struct {
// Usage is the function called when an error occurs while parsing flags. // Usage is the function called when an error occurs while parsing flags.
@ -129,14 +133,15 @@ type FlagSet struct {
name string name string
parsed bool parsed bool
actual map[string]*Flag actual map[normalizedName]*Flag
formal map[string]*Flag formal map[normalizedName]*Flag
shorthands map[byte]*Flag shorthands map[byte]*Flag
args []string // arguments after flags args []string // arguments after flags
exitOnError bool // does the program exit if there's an error? exitOnError bool // does the program exit if there's an error?
errorHandling ErrorHandling errorHandling ErrorHandling
output io.Writer // nil means stderr; use out() accessor output io.Writer // nil means stderr; use out() accessor
interspersed bool // allow interspersed option/non-option args interspersed bool // allow interspersed option/non-option args
wordSeparators []string
} }
// A Flag represents the state of a flag. // A Flag represents the state of a flag.
@ -159,21 +164,30 @@ type Value interface {
} }
// sortFlags returns the flags as a slice in lexicographical sorted order. // sortFlags returns the flags as a slice in lexicographical sorted order.
func sortFlags(flags map[string]*Flag) []*Flag { func sortFlags(flags map[normalizedName]*Flag) []*Flag {
list := make(sort.StringSlice, len(flags)) list := make(sort.StringSlice, len(flags))
i := 0 i := 0
for _, f := range flags { for k := range flags {
list[i] = f.Name list[i] = string(k)
i++ i++
} }
list.Sort() list.Sort()
result := make([]*Flag, len(list)) result := make([]*Flag, len(list))
for i, name := range list { for i, name := range list {
result[i] = flags[name] result[i] = flags[normalizedName(name)]
} }
return result return result
} }
func (f *FlagSet) normalizeFlagName(name string) normalizedName {
result := name
for _, sep := range f.wordSeparators {
result = strings.Replace(result, sep, "-", -1)
}
// Type convert to indicate normalization has been done.
return normalizedName(result)
}
func (f *FlagSet) out() io.Writer { func (f *FlagSet) out() io.Writer {
if f.output == nil { if f.output == nil {
return os.Stderr return os.Stderr
@ -221,18 +235,24 @@ func Visit(fn func(*Flag)) {
// Lookup returns the Flag structure of the named flag, returning nil if none exists. // Lookup returns the Flag structure of the named flag, returning nil if none exists.
func (f *FlagSet) Lookup(name string) *Flag { func (f *FlagSet) Lookup(name string) *Flag {
return f.lookup(f.normalizeFlagName(name))
}
// lookup returns the Flag structure of the named flag, returning nil if none exists.
func (f *FlagSet) lookup(name normalizedName) *Flag {
return f.formal[name] return f.formal[name]
} }
// Lookup returns the Flag structure of the named command-line flag, // Lookup returns the Flag structure of the named command-line flag,
// returning nil if none exists. // returning nil if none exists.
func Lookup(name string) *Flag { func Lookup(name string) *Flag {
return CommandLine.formal[name] return CommandLine.Lookup(name)
} }
// Set sets the value of the named flag. // Set sets the value of the named flag.
func (f *FlagSet) Set(name, value string) error { func (f *FlagSet) Set(name, value string) error {
flag, ok := f.formal[name] normalName := f.normalizeFlagName(name)
flag, ok := f.formal[normalName]
if !ok { if !ok {
return fmt.Errorf("no such flag -%v", name) return fmt.Errorf("no such flag -%v", name)
} }
@ -241,10 +261,10 @@ func (f *FlagSet) Set(name, value string) error {
return err return err
} }
if f.actual == nil { if f.actual == nil {
f.actual = make(map[string]*Flag) f.actual = make(map[normalizedName]*Flag)
} }
f.actual[name] = flag f.actual[normalName] = flag
f.Lookup(name).Changed = true f.lookup(normalName).Changed = true
return nil return nil
} }
@ -359,21 +379,27 @@ func (f *FlagSet) Var(value Value, name string, usage string) {
// Like Var, but accepts a shorthand letter that can be used after a single dash. // Like Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
// Remember the default value as a string; it won't change. // Remember the default value as a string; it won't change.
flag := &Flag{name, shorthand, usage, value, value.String(), false, make(map[string][]string)} flag := &Flag{
Name: name,
Shorthand: shorthand,
Usage: usage,
Value: value,
DefValue: value.String(),
}
f.AddFlag(flag) f.AddFlag(flag)
} }
func (f *FlagSet) AddFlag(flag *Flag) { func (f *FlagSet) AddFlag(flag *Flag) {
_, alreadythere := f.formal[flag.Name] _, alreadythere := f.formal[f.normalizeFlagName(flag.Name)]
if alreadythere { if alreadythere {
msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name) msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name)
fmt.Fprintln(f.out(), msg) fmt.Fprintln(f.out(), msg)
panic(msg) // Happens only if flags are declared with identical names panic(msg) // Happens only if flags are declared with identical names
} }
if f.formal == nil { if f.formal == nil {
f.formal = make(map[string]*Flag) f.formal = make(map[normalizedName]*Flag)
} }
f.formal[flag.Name] = flag f.formal[f.normalizeFlagName(flag.Name)] = flag
if len(flag.Shorthand) == 0 { if len(flag.Shorthand) == 0 {
return return
@ -436,9 +462,9 @@ func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error {
} }
// mark as visited for Visit() // mark as visited for Visit()
if f.actual == nil { if f.actual == nil {
f.actual = make(map[string]*Flag) f.actual = make(map[normalizedName]*Flag)
} }
f.actual[flag.Name] = flag f.actual[f.normalizeFlagName(flag.Name)] = flag
flag.Changed = true flag.Changed = true
return nil return nil
} }
@ -457,7 +483,7 @@ func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error)
split := strings.SplitN(name, "=", 2) split := strings.SplitN(name, "=", 2)
name = split[0] name = split[0]
m := f.formal m := f.formal
flag, alreadythere := m[name] // BUG flag, alreadythere := m[f.normalizeFlagName(name)] // BUG
if !alreadythere { if !alreadythere {
if name == "help" { // special case for nice help message. if name == "help" { // special case for nice help message.
f.usage() f.usage()
@ -507,7 +533,8 @@ func (f *FlagSet) parseShortArg(s string, args []string) (a []string, err error)
continue continue
} }
if i < len(shorthands)-1 { if i < len(shorthands)-1 {
if e := f.setFlag(flag, shorthands[i+1:], s); e != nil { v := strings.TrimPrefix(shorthands[i+1:], "=")
if e := f.setFlag(flag, v, s); e != nil {
err = e err = e
return return
} }
@ -598,6 +625,19 @@ func SetInterspersed(interspersed bool) {
CommandLine.SetInterspersed(interspersed) CommandLine.SetInterspersed(interspersed)
} }
// SetWordSeparators sets a list of strings to be considerered as word
// separators and normalized for the pruposes of lookups. For example, if this
// is set to {"-", "_", "."} then --foo_bar, --foo-bar, and --foo.bar are
// considered equivalent flags. This must be called before flags are parsed,
// and may only be called once.
func (f *FlagSet) SetWordSeparators(separators []string) {
f.wordSeparators = separators
for k, v := range f.formal {
delete(f.formal, k)
f.formal[f.normalizeFlagName(string(k))] = v
}
}
// Parsed returns true if the command-line flags have been parsed. // Parsed returns true if the command-line flags have been parsed.
func Parsed() bool { func Parsed() bool {
return CommandLine.Parsed() return CommandLine.Parsed()

View File

@ -185,7 +185,8 @@ func TestShorthand(t *testing.T) {
boolaFlag := f.BoolP("boola", "a", false, "bool value") boolaFlag := f.BoolP("boola", "a", false, "bool value")
boolbFlag := f.BoolP("boolb", "b", false, "bool2 value") boolbFlag := f.BoolP("boolb", "b", false, "bool2 value")
boolcFlag := f.BoolP("boolc", "c", false, "bool3 value") boolcFlag := f.BoolP("boolc", "c", false, "bool3 value")
stringFlag := f.StringP("string", "s", "0", "string value") stringaFlag := f.StringP("stringa", "s", "0", "string value")
stringzFlag := f.StringP("stringz", "z", "0", "string value")
extra := "interspersed-argument" extra := "interspersed-argument"
notaflag := "--i-look-like-a-flag" notaflag := "--i-look-like-a-flag"
args := []string{ args := []string{
@ -193,6 +194,7 @@ func TestShorthand(t *testing.T) {
extra, extra,
"-cs", "-cs",
"hello", "hello",
"-z=something",
"--", "--",
notaflag, notaflag,
} }
@ -212,8 +214,11 @@ func TestShorthand(t *testing.T) {
if *boolcFlag != true { if *boolcFlag != true {
t.Error("boolc flag should be true, is ", *boolcFlag) t.Error("boolc flag should be true, is ", *boolcFlag)
} }
if *stringFlag != "hello" { if *stringaFlag != "hello" {
t.Error("string flag should be `hello`, is ", *stringFlag) t.Error("stringa flag should be `hello`, is ", *stringaFlag)
}
if *stringzFlag != "something" {
t.Error("stringz flag should be `something`, is ", *stringzFlag)
} }
if len(f.Args()) != 2 { if len(f.Args()) != 2 {
t.Error("expected one argument, got", len(f.Args())) t.Error("expected one argument, got", len(f.Args()))
@ -233,6 +238,56 @@ func TestFlagSetParse(t *testing.T) {
testParse(NewFlagSet("test", ContinueOnError), t) testParse(NewFlagSet("test", ContinueOnError), t)
} }
func testNormalizedNames(args []string, t *testing.T) {
f := NewFlagSet("normalized", ContinueOnError)
if f.Parsed() {
t.Error("f.Parse() = true before Parse")
}
withDashFlag := f.Bool("with-dash-flag", false, "bool value")
// Set this after some flags have been added and before others.
f.SetWordSeparators([]string{"-", "_"})
withUnderFlag := f.Bool("with_under_flag", false, "bool value")
withBothFlag := f.Bool("with-both_flag", false, "bool value")
if err := f.Parse(args); err != nil {
t.Fatal(err)
}
if !f.Parsed() {
t.Error("f.Parse() = false after Parse")
}
if *withDashFlag != true {
t.Error("withDashFlag flag should be true, is ", *withDashFlag)
}
if *withUnderFlag != true {
t.Error("withUnderFlag flag should be true, is ", *withUnderFlag)
}
if *withBothFlag != true {
t.Error("withBothFlag flag should be true, is ", *withBothFlag)
}
}
func TestNormalizedNames(t *testing.T) {
args := []string{
"--with-dash-flag",
"--with-under-flag",
"--with-both-flag",
}
testNormalizedNames(args, t)
args = []string{
"--with_dash_flag",
"--with_under_flag",
"--with_both_flag",
}
testNormalizedNames(args, t)
args = []string{
"--with-dash_flag",
"--with-under_flag",
"--with-both_flag",
}
testNormalizedNames(args, t)
}
// Declare a user-defined flag type. // Declare a user-defined flag type.
type flagVar []string type flagVar []string