- Add exported functions to preserve pkg/flag compatibility
- Add IPNetSlice and unit tests
full diff: https://github.com/spf13/pflag/compare/v1.0.5...v1.0.6
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -91,7 +91,7 @@ require ( |
| 91 | 91 |
github.com/rootless-containers/rootlesskit/v2 v2.3.2 |
| 92 | 92 |
github.com/sirupsen/logrus v1.9.3 |
| 93 | 93 |
github.com/spf13/cobra v1.8.1 |
| 94 |
- github.com/spf13/pflag v1.0.5 |
|
| 94 |
+ github.com/spf13/pflag v1.0.6 |
|
| 95 | 95 |
github.com/tonistiigi/go-archvariant v1.0.0 |
| 96 | 96 |
github.com/vbatts/tar-split v0.11.6 |
| 97 | 97 |
github.com/vishvananda/netlink v1.3.1-0.20240922070040-084abd93d350 |
| ... | ... |
@@ -503,8 +503,9 @@ github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQr |
| 503 | 503 |
github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI= |
| 504 | 504 |
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= |
| 505 | 505 |
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= |
| 506 |
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= |
|
| 507 | 506 |
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= |
| 507 |
+github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= |
|
| 508 |
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= |
|
| 508 | 509 |
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
| 509 | 510 |
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
| 510 | 511 |
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= |
| ... | ... |
@@ -160,7 +160,7 @@ type FlagSet struct {
|
| 160 | 160 |
args []string // arguments after flags |
| 161 | 161 |
argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- |
| 162 | 162 |
errorHandling ErrorHandling |
| 163 |
- output io.Writer // nil means stderr; use out() accessor |
|
| 163 |
+ output io.Writer // nil means stderr; use Output() accessor |
|
| 164 | 164 |
interspersed bool // allow interspersed option/non-option args |
| 165 | 165 |
normalizeNameFunc func(f *FlagSet, name string) NormalizedName |
| 166 | 166 |
|
| ... | ... |
@@ -255,13 +255,20 @@ func (f *FlagSet) normalizeFlagName(name string) NormalizedName {
|
| 255 | 255 |
return n(f, name) |
| 256 | 256 |
} |
| 257 | 257 |
|
| 258 |
-func (f *FlagSet) out() io.Writer {
|
|
| 258 |
+// Output returns the destination for usage and error messages. os.Stderr is returned if |
|
| 259 |
+// output was not set or was set to nil. |
|
| 260 |
+func (f *FlagSet) Output() io.Writer {
|
|
| 259 | 261 |
if f.output == nil {
|
| 260 | 262 |
return os.Stderr |
| 261 | 263 |
} |
| 262 | 264 |
return f.output |
| 263 | 265 |
} |
| 264 | 266 |
|
| 267 |
+// Name returns the name of the flag set. |
|
| 268 |
+func (f *FlagSet) Name() string {
|
|
| 269 |
+ return f.name |
|
| 270 |
+} |
|
| 271 |
+ |
|
| 265 | 272 |
// SetOutput sets the destination for usage and error messages. |
| 266 | 273 |
// If output is nil, os.Stderr is used. |
| 267 | 274 |
func (f *FlagSet) SetOutput(output io.Writer) {
|
| ... | ... |
@@ -358,7 +365,7 @@ func (f *FlagSet) ShorthandLookup(name string) *Flag {
|
| 358 | 358 |
} |
| 359 | 359 |
if len(name) > 1 {
|
| 360 | 360 |
msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name)
|
| 361 |
- fmt.Fprintf(f.out(), msg) |
|
| 361 |
+ fmt.Fprintf(f.Output(), msg) |
|
| 362 | 362 |
panic(msg) |
| 363 | 363 |
} |
| 364 | 364 |
c := name[0] |
| ... | ... |
@@ -482,7 +489,7 @@ func (f *FlagSet) Set(name, value string) error {
|
| 482 | 482 |
} |
| 483 | 483 |
|
| 484 | 484 |
if flag.Deprecated != "" {
|
| 485 |
- fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) |
|
| 485 |
+ fmt.Fprintf(f.Output(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) |
|
| 486 | 486 |
} |
| 487 | 487 |
return nil |
| 488 | 488 |
} |
| ... | ... |
@@ -523,7 +530,7 @@ func Set(name, value string) error {
|
| 523 | 523 |
// otherwise, the default values of all defined flags in the set. |
| 524 | 524 |
func (f *FlagSet) PrintDefaults() {
|
| 525 | 525 |
usages := f.FlagUsages() |
| 526 |
- fmt.Fprint(f.out(), usages) |
|
| 526 |
+ fmt.Fprint(f.Output(), usages) |
|
| 527 | 527 |
} |
| 528 | 528 |
|
| 529 | 529 |
// defaultIsZeroValue returns true if the default value for this flag represents |
| ... | ... |
@@ -758,7 +765,7 @@ func PrintDefaults() {
|
| 758 | 758 |
|
| 759 | 759 |
// defaultUsage is the default function to print a usage message. |
| 760 | 760 |
func defaultUsage(f *FlagSet) {
|
| 761 |
- fmt.Fprintf(f.out(), "Usage of %s:\n", f.name) |
|
| 761 |
+ fmt.Fprintf(f.Output(), "Usage of %s:\n", f.name) |
|
| 762 | 762 |
f.PrintDefaults() |
| 763 | 763 |
} |
| 764 | 764 |
|
| ... | ... |
@@ -844,7 +851,7 @@ func (f *FlagSet) AddFlag(flag *Flag) {
|
| 844 | 844 |
_, alreadyThere := f.formal[normalizedFlagName] |
| 845 | 845 |
if alreadyThere {
|
| 846 | 846 |
msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name)
|
| 847 |
- fmt.Fprintln(f.out(), msg) |
|
| 847 |
+ fmt.Fprintln(f.Output(), msg) |
|
| 848 | 848 |
panic(msg) // Happens only if flags are declared with identical names |
| 849 | 849 |
} |
| 850 | 850 |
if f.formal == nil {
|
| ... | ... |
@@ -860,7 +867,7 @@ func (f *FlagSet) AddFlag(flag *Flag) {
|
| 860 | 860 |
} |
| 861 | 861 |
if len(flag.Shorthand) > 1 {
|
| 862 | 862 |
msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand)
|
| 863 |
- fmt.Fprintf(f.out(), msg) |
|
| 863 |
+ fmt.Fprintf(f.Output(), msg) |
|
| 864 | 864 |
panic(msg) |
| 865 | 865 |
} |
| 866 | 866 |
if f.shorthands == nil {
|
| ... | ... |
@@ -870,7 +877,7 @@ func (f *FlagSet) AddFlag(flag *Flag) {
|
| 870 | 870 |
used, alreadyThere := f.shorthands[c] |
| 871 | 871 |
if alreadyThere {
|
| 872 | 872 |
msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name)
|
| 873 |
- fmt.Fprintf(f.out(), msg) |
|
| 873 |
+ fmt.Fprintf(f.Output(), msg) |
|
| 874 | 874 |
panic(msg) |
| 875 | 875 |
} |
| 876 | 876 |
f.shorthands[c] = flag |
| ... | ... |
@@ -909,7 +916,7 @@ func VarP(value Value, name, shorthand, usage string) {
|
| 909 | 909 |
func (f *FlagSet) failf(format string, a ...interface{}) error {
|
| 910 | 910 |
err := fmt.Errorf(format, a...) |
| 911 | 911 |
if f.errorHandling != ContinueOnError {
|
| 912 |
- fmt.Fprintln(f.out(), err) |
|
| 912 |
+ fmt.Fprintln(f.Output(), err) |
|
| 913 | 913 |
f.usage() |
| 914 | 914 |
} |
| 915 | 915 |
return err |
| ... | ... |
@@ -1060,7 +1067,7 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse |
| 1060 | 1060 |
} |
| 1061 | 1061 |
|
| 1062 | 1062 |
if flag.ShorthandDeprecated != "" {
|
| 1063 |
- fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) |
|
| 1063 |
+ fmt.Fprintf(f.Output(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) |
|
| 1064 | 1064 |
} |
| 1065 | 1065 |
|
| 1066 | 1066 |
err = fn(flag, value) |
| ... | ... |
@@ -16,6 +16,9 @@ func newIPValue(val net.IP, p *net.IP) *ipValue {
|
| 16 | 16 |
|
| 17 | 17 |
func (i *ipValue) String() string { return net.IP(*i).String() }
|
| 18 | 18 |
func (i *ipValue) Set(s string) error {
|
| 19 |
+ if s == "" {
|
|
| 20 |
+ return nil |
|
| 21 |
+ } |
|
| 19 | 22 |
ip := net.ParseIP(strings.TrimSpace(s)) |
| 20 | 23 |
if ip == nil {
|
| 21 | 24 |
return fmt.Errorf("failed to parse IP: %q", s)
|
| 22 | 25 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,147 @@ |
| 0 |
+package pflag |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "io" |
|
| 5 |
+ "net" |
|
| 6 |
+ "strings" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// -- ipNetSlice Value |
|
| 10 |
+type ipNetSliceValue struct {
|
|
| 11 |
+ value *[]net.IPNet |
|
| 12 |
+ changed bool |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 15 |
+func newIPNetSliceValue(val []net.IPNet, p *[]net.IPNet) *ipNetSliceValue {
|
|
| 16 |
+ ipnsv := new(ipNetSliceValue) |
|
| 17 |
+ ipnsv.value = p |
|
| 18 |
+ *ipnsv.value = val |
|
| 19 |
+ return ipnsv |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 22 |
+// Set converts, and assigns, the comma-separated IPNet argument string representation as the []net.IPNet value of this flag. |
|
| 23 |
+// If Set is called on a flag that already has a []net.IPNet assigned, the newly converted values will be appended. |
|
| 24 |
+func (s *ipNetSliceValue) Set(val string) error {
|
|
| 25 |
+ |
|
| 26 |
+ // remove all quote characters |
|
| 27 |
+ rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") |
|
| 28 |
+ |
|
| 29 |
+ // read flag arguments with CSV parser |
|
| 30 |
+ ipNetStrSlice, err := readAsCSV(rmQuote.Replace(val)) |
|
| 31 |
+ if err != nil && err != io.EOF {
|
|
| 32 |
+ return err |
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 35 |
+ // parse ip values into slice |
|
| 36 |
+ out := make([]net.IPNet, 0, len(ipNetStrSlice)) |
|
| 37 |
+ for _, ipNetStr := range ipNetStrSlice {
|
|
| 38 |
+ _, n, err := net.ParseCIDR(strings.TrimSpace(ipNetStr)) |
|
| 39 |
+ if err != nil {
|
|
| 40 |
+ return fmt.Errorf("invalid string being converted to CIDR: %s", ipNetStr)
|
|
| 41 |
+ } |
|
| 42 |
+ out = append(out, *n) |
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ if !s.changed {
|
|
| 46 |
+ *s.value = out |
|
| 47 |
+ } else {
|
|
| 48 |
+ *s.value = append(*s.value, out...) |
|
| 49 |
+ } |
|
| 50 |
+ |
|
| 51 |
+ s.changed = true |
|
| 52 |
+ |
|
| 53 |
+ return nil |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 56 |
+// Type returns a string that uniquely represents this flag's type. |
|
| 57 |
+func (s *ipNetSliceValue) Type() string {
|
|
| 58 |
+ return "ipNetSlice" |
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+// String defines a "native" format for this net.IPNet slice flag value. |
|
| 62 |
+func (s *ipNetSliceValue) String() string {
|
|
| 63 |
+ |
|
| 64 |
+ ipNetStrSlice := make([]string, len(*s.value)) |
|
| 65 |
+ for i, n := range *s.value {
|
|
| 66 |
+ ipNetStrSlice[i] = n.String() |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ out, _ := writeAsCSV(ipNetStrSlice) |
|
| 70 |
+ return "[" + out + "]" |
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+func ipNetSliceConv(val string) (interface{}, error) {
|
|
| 74 |
+ val = strings.Trim(val, "[]") |
|
| 75 |
+ // Emtpy string would cause a slice with one (empty) entry |
|
| 76 |
+ if len(val) == 0 {
|
|
| 77 |
+ return []net.IPNet{}, nil
|
|
| 78 |
+ } |
|
| 79 |
+ ss := strings.Split(val, ",") |
|
| 80 |
+ out := make([]net.IPNet, len(ss)) |
|
| 81 |
+ for i, sval := range ss {
|
|
| 82 |
+ _, n, err := net.ParseCIDR(strings.TrimSpace(sval)) |
|
| 83 |
+ if err != nil {
|
|
| 84 |
+ return nil, fmt.Errorf("invalid string being converted to CIDR: %s", sval)
|
|
| 85 |
+ } |
|
| 86 |
+ out[i] = *n |
|
| 87 |
+ } |
|
| 88 |
+ return out, nil |
|
| 89 |
+} |
|
| 90 |
+ |
|
| 91 |
+// GetIPNetSlice returns the []net.IPNet value of a flag with the given name |
|
| 92 |
+func (f *FlagSet) GetIPNetSlice(name string) ([]net.IPNet, error) {
|
|
| 93 |
+ val, err := f.getFlagType(name, "ipNetSlice", ipNetSliceConv) |
|
| 94 |
+ if err != nil {
|
|
| 95 |
+ return []net.IPNet{}, err
|
|
| 96 |
+ } |
|
| 97 |
+ return val.([]net.IPNet), nil |
|
| 98 |
+} |
|
| 99 |
+ |
|
| 100 |
+// IPNetSliceVar defines a ipNetSlice flag with specified name, default value, and usage string. |
|
| 101 |
+// The argument p points to a []net.IPNet variable in which to store the value of the flag. |
|
| 102 |
+func (f *FlagSet) IPNetSliceVar(p *[]net.IPNet, name string, value []net.IPNet, usage string) {
|
|
| 103 |
+ f.VarP(newIPNetSliceValue(value, p), name, "", usage) |
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+// IPNetSliceVarP is like IPNetSliceVar, but accepts a shorthand letter that can be used after a single dash. |
|
| 107 |
+func (f *FlagSet) IPNetSliceVarP(p *[]net.IPNet, name, shorthand string, value []net.IPNet, usage string) {
|
|
| 108 |
+ f.VarP(newIPNetSliceValue(value, p), name, shorthand, usage) |
|
| 109 |
+} |
|
| 110 |
+ |
|
| 111 |
+// IPNetSliceVar defines a []net.IPNet flag with specified name, default value, and usage string. |
|
| 112 |
+// The argument p points to a []net.IPNet variable in which to store the value of the flag. |
|
| 113 |
+func IPNetSliceVar(p *[]net.IPNet, name string, value []net.IPNet, usage string) {
|
|
| 114 |
+ CommandLine.VarP(newIPNetSliceValue(value, p), name, "", usage) |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+// IPNetSliceVarP is like IPNetSliceVar, but accepts a shorthand letter that can be used after a single dash. |
|
| 118 |
+func IPNetSliceVarP(p *[]net.IPNet, name, shorthand string, value []net.IPNet, usage string) {
|
|
| 119 |
+ CommandLine.VarP(newIPNetSliceValue(value, p), name, shorthand, usage) |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+// IPNetSlice defines a []net.IPNet flag with specified name, default value, and usage string. |
|
| 123 |
+// The return value is the address of a []net.IPNet variable that stores the value of that flag. |
|
| 124 |
+func (f *FlagSet) IPNetSlice(name string, value []net.IPNet, usage string) *[]net.IPNet {
|
|
| 125 |
+ p := []net.IPNet{}
|
|
| 126 |
+ f.IPNetSliceVarP(&p, name, "", value, usage) |
|
| 127 |
+ return &p |
|
| 128 |
+} |
|
| 129 |
+ |
|
| 130 |
+// IPNetSliceP is like IPNetSlice, but accepts a shorthand letter that can be used after a single dash. |
|
| 131 |
+func (f *FlagSet) IPNetSliceP(name, shorthand string, value []net.IPNet, usage string) *[]net.IPNet {
|
|
| 132 |
+ p := []net.IPNet{}
|
|
| 133 |
+ f.IPNetSliceVarP(&p, name, shorthand, value, usage) |
|
| 134 |
+ return &p |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+// IPNetSlice defines a []net.IPNet flag with specified name, default value, and usage string. |
|
| 138 |
+// The return value is the address of a []net.IP variable that stores the value of the flag. |
|
| 139 |
+func IPNetSlice(name string, value []net.IPNet, usage string) *[]net.IPNet {
|
|
| 140 |
+ return CommandLine.IPNetSliceP(name, "", value, usage) |
|
| 141 |
+} |
|
| 142 |
+ |
|
| 143 |
+// IPNetSliceP is like IPNetSlice, but accepts a shorthand letter that can be used after a single dash. |
|
| 144 |
+func IPNetSliceP(name, shorthand string, value []net.IPNet, usage string) *[]net.IPNet {
|
|
| 145 |
+ return CommandLine.IPNetSliceP(name, shorthand, value, usage) |
|
| 146 |
+} |
| ... | ... |
@@ -31,11 +31,7 @@ func (s *stringArrayValue) Append(val string) error {
|
| 31 | 31 |
func (s *stringArrayValue) Replace(val []string) error {
|
| 32 | 32 |
out := make([]string, len(val)) |
| 33 | 33 |
for i, d := range val {
|
| 34 |
- var err error |
|
| 35 | 34 |
out[i] = d |
| 36 |
- if err != nil {
|
|
| 37 |
- return err |
|
| 38 |
- } |
|
| 39 | 35 |
} |
| 40 | 36 |
*s.value = out |
| 41 | 37 |
return nil |
| ... | ... |
@@ -1107,7 +1107,7 @@ github.com/spdx/tools-golang/spdx/v2/v2_3 |
| 1107 | 1107 |
# github.com/spf13/cobra v1.8.1 |
| 1108 | 1108 |
## explicit; go 1.15 |
| 1109 | 1109 |
github.com/spf13/cobra |
| 1110 |
-# github.com/spf13/pflag v1.0.5 |
|
| 1110 |
+# github.com/spf13/pflag v1.0.6 |
|
| 1111 | 1111 |
## explicit; go 1.12 |
| 1112 | 1112 |
github.com/spf13/pflag |
| 1113 | 1113 |
# github.com/stretchr/testify v1.10.0 |