1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package pflag 6 7import ( 8 goflag "flag" 9 "reflect" 10 "strings" 11) 12 13// flagValueWrapper implements pflag.Value around a flag.Value. The main 14// difference here is the addition of the Type method that returns a string 15// name of the type. As this is generally unknown, we approximate that with 16// reflection. 17type flagValueWrapper struct { 18 inner goflag.Value 19 flagType string 20} 21 22// We are just copying the boolFlag interface out of goflag as that is what 23// they use to decide if a flag should get "true" when no arg is given. 24type goBoolFlag interface { 25 goflag.Value 26 IsBoolFlag() bool 27} 28 29func wrapFlagValue(v goflag.Value) Value { 30 // If the flag.Value happens to also be a pflag.Value, just use it directly. 31 if pv, ok := v.(Value); ok { 32 return pv 33 } 34 35 pv := &flagValueWrapper{ 36 inner: v, 37 } 38 39 t := reflect.TypeOf(v) 40 if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr { 41 t = t.Elem() 42 } 43 44 pv.flagType = strings.TrimSuffix(t.Name(), "Value") 45 return pv 46} 47 48func (v *flagValueWrapper) String() string { 49 return v.inner.String() 50} 51 52func (v *flagValueWrapper) Set(s string) error { 53 return v.inner.Set(s) 54} 55 56func (v *flagValueWrapper) Type() string { 57 return v.flagType 58} 59 60// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag 61// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei 62// with both `-v` and `--v` in flags. If the golang flag was more than a single 63// character (ex: `verbose`) it will only be accessible via `--verbose` 64func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { 65 // Remember the default value as a string; it won't change. 66 flag := &Flag{ 67 Name: goflag.Name, 68 Usage: goflag.Usage, 69 Value: wrapFlagValue(goflag.Value), 70 // Looks like golang flags don't set DefValue correctly :-( 71 //DefValue: goflag.DefValue, 72 DefValue: goflag.Value.String(), 73 } 74 // Ex: if the golang flag was -v, allow both -v and --v to work 75 if len(flag.Name) == 1 { 76 flag.Shorthand = flag.Name 77 } 78 if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { 79 flag.NoOptDefVal = "true" 80 } 81 return flag 82} 83 84// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet 85func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { 86 if f.Lookup(goflag.Name) != nil { 87 return 88 } 89 newflag := PFlagFromGoFlag(goflag) 90 f.AddFlag(newflag) 91} 92 93// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet 94func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { 95 if newSet == nil { 96 return 97 } 98 newSet.VisitAll(func(goflag *goflag.Flag) { 99 f.AddGoFlag(goflag) 100 }) 101 if f.addedGoFlagSets == nil { 102 f.addedGoFlagSets = make([]*goflag.FlagSet, 0) 103 } 104 f.addedGoFlagSets = append(f.addedGoFlagSets, newSet) 105} 106