]> Cypherpunks repositories - gostls13.git/commitdiff
flag: add TextVar function
authorJoe Tsai <joetsai@digital-static.net>
Sun, 25 Apr 2021 05:55:58 +0000 (22:55 -0700)
committerJoseph Tsai <joetsai@digital-static.net>
Thu, 10 Mar 2022 16:56:17 +0000 (16:56 +0000)
The TextVar function makes it easier to integrate the flag package
with any Go type that implements encoding.Text{Marshaler,Unmarshaler}.

Fixes #45754

Change-Id: Id23c37d59cf8c9699a7943a22ce27a45eb685c0f
Reviewed-on: https://go-review.googlesource.com/c/go/+/313329
Trust: Joseph Tsai <joetsai@digital-static.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Joseph Tsai <joetsai@digital-static.net>
TryBot-Result: Gopher Robot <gobot@golang.org>

api/next.txt
src/flag/example_textvar_test.go [new file with mode: 0644]
src/flag/flag.go
src/go/build/deps_test.go

index 148cbffbfeb6feb3b74198f769483bb5e01ba12f..a0f2bed8d1a909601da71920ae8edb06d256d46b 100644 (file)
@@ -3,5 +3,7 @@ pkg encoding/binary, type AppendByteOrder interface, AppendUint16([]uint8, uint1
 pkg encoding/binary, type AppendByteOrder interface, AppendUint32([]uint8, uint32) []uint8
 pkg encoding/binary, type AppendByteOrder interface, AppendUint64([]uint8, uint64) []uint8
 pkg encoding/binary, type AppendByteOrder interface, String() string
+pkg flag, func TextVar(encoding.TextUnmarshaler, string, encoding.TextMarshaler, string)
+pkg flag, method (*FlagSet) TextVar(encoding.TextUnmarshaler, string, encoding.TextMarshaler, string)
 pkg net/url, func JoinPath(string, ...string) (string, error)
 pkg net/url, method (*URL) JoinPath(...string) *URL
diff --git a/src/flag/example_textvar_test.go b/src/flag/example_textvar_test.go
new file mode 100644 (file)
index 0000000..8b8cbf6
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flag_test
+
+import (
+       "flag"
+       "fmt"
+       "net"
+       "os"
+)
+
+func ExampleTextVar() {
+       fs := flag.NewFlagSet("ExampleTextVar", flag.ContinueOnError)
+       fs.SetOutput(os.Stdout)
+       var ip net.IP
+       fs.TextVar(&ip, "ip", net.IPv4(192, 168, 0, 100), "`IP address` to parse")
+       fs.Parse([]string{"-ip", "127.0.0.1"})
+       fmt.Printf("{ip: %v}\n\n", ip)
+
+       // 256 is not a valid IPv4 component
+       ip = nil
+       fs.Parse([]string{"-ip", "256.0.0.1"})
+       fmt.Printf("{ip: %v}\n\n", ip)
+
+       // Output:
+       // {ip: 127.0.0.1}
+       //
+       // invalid value "256.0.0.1" for flag -ip: invalid IP address: 256.0.0.1
+       // Usage of ExampleTextVar:
+       //   -ip IP address
+       //      IP address to parse (default 192.168.0.100)
+       // {ip: <nil>}
+}
index 4e2af450c5065e6b7ce03feb0724f353a37556d7..c27a1444348f21b1a6ffd297afffb3b3c336fd04 100644 (file)
@@ -68,6 +68,7 @@
 package flag
 
 import (
+       "encoding"
        "errors"
        "fmt"
        "io"
@@ -278,6 +279,43 @@ func (d *durationValue) Get() any { return time.Duration(*d) }
 
 func (d *durationValue) String() string { return (*time.Duration)(d).String() }
 
+// -- encoding.TextUnmarshaler Value
+type textValue struct{ p encoding.TextUnmarshaler }
+
+func newTextValue(val encoding.TextMarshaler, p encoding.TextUnmarshaler) textValue {
+       ptrVal := reflect.ValueOf(p)
+       if ptrVal.Kind() != reflect.Ptr {
+               panic("variable value type must be a pointer")
+       }
+       defVal := reflect.ValueOf(val)
+       if defVal.Kind() == reflect.Ptr {
+               defVal = defVal.Elem()
+       }
+       if defVal.Type() != ptrVal.Type().Elem() {
+               panic(fmt.Sprintf("default type does not match variable type: %v != %v", defVal.Type(), ptrVal.Type().Elem()))
+       }
+       ptrVal.Elem().Set(defVal)
+       return textValue{p}
+}
+
+func (v textValue) Set(s string) error {
+       return v.p.UnmarshalText([]byte(s))
+}
+
+func (v textValue) Get() interface{} {
+       return v.p
+}
+
+func (v textValue) String() string {
+       if m, ok := v.p.(encoding.TextMarshaler); ok {
+               if b, err := m.MarshalText(); err == nil {
+                       return string(b)
+               }
+       }
+       return ""
+}
+
+// -- func Value
 type funcValue func(string) error
 
 func (f funcValue) Set(s string) error { return f(s) }
@@ -838,6 +876,24 @@ func Duration(name string, value time.Duration, usage string) *time.Duration {
        return CommandLine.Duration(name, value, usage)
 }
 
+// TextVar defines a flag with a specified name, default value, and usage string.
+// The argument p must be a pointer to a variable that will hold the value
+// of the flag, and p must implement encoding.TextUnmarshaler.
+// If the flag is used, the flag value will be passed to p's UnmarshalText method.
+// The type of the default value must be the same as the type of p.
+func (f *FlagSet) TextVar(p encoding.TextUnmarshaler, name string, value encoding.TextMarshaler, usage string) {
+       f.Var(newTextValue(value, p), name, usage)
+}
+
+// TextVar defines a flag with a specified name, default value, and usage string.
+// The argument p must be a pointer to a variable that will hold the value
+// of the flag, and p must implement encoding.TextUnmarshaler.
+// If the flag is used, the flag value will be passed to p's UnmarshalText method.
+// The type of the default value must be the same as the type of p.
+func TextVar(p encoding.TextUnmarshaler, name string, value encoding.TextMarshaler, usage string) {
+       CommandLine.Var(newTextValue(value, p), name, usage)
+}
+
 // Func defines a flag with the specified name and usage string.
 // Each time the flag is seen, fn is called with the value of the flag.
 // If fn returns a non-nil error, it will be treated as a flag value parsing error.
index 6ce872e2979a8d9198119e9d233687ddf82995e3..6b2c2933f82afb9d855acbf53f5c4434e4ce3cd7 100644 (file)
@@ -212,8 +212,7 @@ var depsRules = `
 
        # Misc packages needing only FMT.
        FMT
-       < flag,
-         html,
+       < html,
          mime/quotedprintable,
          net/internal/socktest,
          net/url,
@@ -230,6 +229,8 @@ var depsRules = `
        < encoding/binary
        < encoding/base32, encoding/base64;
 
+       FMT, encoding < flag;
+
        fmt !< encoding/base32, encoding/base64;
 
        FMT, encoding/base32, encoding/base64