aboutsummaryrefslogtreecommitdiff
path: root/src/flag
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2021-04-24 22:55:58 -0700
committerJoseph Tsai <joetsai@digital-static.net>2022-03-10 16:56:17 +0000
commit91daaabd56964d0cffae99825e4696f3f70a3857 (patch)
tree4ddd7dee7f7ea755d98d821cc1add1179772fcd6 /src/flag
parent2d026a4ea5b28680c1ed7660f720c4cb028c5b35 (diff)
downloadgo-91daaabd56964d0cffae99825e4696f3f70a3857.tar.gz
go-91daaabd56964d0cffae99825e4696f3f70a3857.zip
flag: add TextVar function
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>
Diffstat (limited to 'src/flag')
-rw-r--r--src/flag/example_textvar_test.go35
-rw-r--r--src/flag/flag.go56
2 files changed, 91 insertions, 0 deletions
diff --git a/src/flag/example_textvar_test.go b/src/flag/example_textvar_test.go
new file mode 100644
index 0000000000..8b8cbf6b6c
--- /dev/null
+++ b/src/flag/example_textvar_test.go
@@ -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>}
+}
diff --git a/src/flag/flag.go b/src/flag/flag.go
index 4e2af450c5..c27a144434 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -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.