summaryrefslogtreecommitdiffstats
path: root/src/cmd/go/internal/cmdflag
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/go/internal/cmdflag')
-rw-r--r--src/cmd/go/internal/cmdflag/flag.go122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/cmd/go/internal/cmdflag/flag.go b/src/cmd/go/internal/cmdflag/flag.go
new file mode 100644
index 0000000..86e33ea
--- /dev/null
+++ b/src/cmd/go/internal/cmdflag/flag.go
@@ -0,0 +1,122 @@
+// Copyright 2017 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 cmdflag handles flag processing common to several go tools.
+package cmdflag
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "strings"
+)
+
+// The flag handling part of go commands such as test is large and distracting.
+// We can't use the standard flag package because some of the flags from
+// our command line are for us, and some are for the binary we're running,
+// and some are for both.
+
+// ErrFlagTerminator indicates the distinguished token "--", which causes the
+// flag package to treat all subsequent arguments as non-flags.
+var ErrFlagTerminator = errors.New("flag terminator")
+
+// A FlagNotDefinedError indicates a flag-like argument that does not correspond
+// to any registered flag in a FlagSet.
+type FlagNotDefinedError struct {
+ RawArg string // the original argument, like --foo or -foo=value
+ Name string
+ HasValue bool // is this the -foo=value or --foo=value form?
+ Value string // only provided if HasValue is true
+}
+
+func (e FlagNotDefinedError) Error() string {
+ return fmt.Sprintf("flag provided but not defined: -%s", e.Name)
+}
+
+// A NonFlagError indicates an argument that is not a syntactically-valid flag.
+type NonFlagError struct {
+ RawArg string
+}
+
+func (e NonFlagError) Error() string {
+ return fmt.Sprintf("not a flag: %q", e.RawArg)
+}
+
+// ParseOne sees if args[0] is present in the given flag set and if so,
+// sets its value and returns the flag along with the remaining (unused) arguments.
+//
+// ParseOne always returns either a non-nil Flag or a non-nil error,
+// and always consumes at least one argument (even on error).
+//
+// Unlike (*flag.FlagSet).Parse, ParseOne does not log its own errors.
+func ParseOne(fs *flag.FlagSet, args []string) (f *flag.Flag, remainingArgs []string, err error) {
+ // This function is loosely derived from (*flag.FlagSet).parseOne.
+
+ raw, args := args[0], args[1:]
+ arg := raw
+ if strings.HasPrefix(arg, "--") {
+ if arg == "--" {
+ return nil, args, ErrFlagTerminator
+ }
+ arg = arg[1:] // reduce two minuses to one
+ }
+
+ switch arg {
+ case "-?", "-h", "-help":
+ return nil, args, flag.ErrHelp
+ }
+ if len(arg) < 2 || arg[0] != '-' || arg[1] == '-' || arg[1] == '=' {
+ return nil, args, NonFlagError{RawArg: raw}
+ }
+
+ name, value, hasValue := strings.Cut(arg[1:], "=")
+
+ f = fs.Lookup(name)
+ if f == nil {
+ return nil, args, FlagNotDefinedError{
+ RawArg: raw,
+ Name: name,
+ HasValue: hasValue,
+ Value: value,
+ }
+ }
+
+ // Use fs.Set instead of f.Value.Set below so that any subsequent call to
+ // fs.Visit will correctly visit the flags that have been set.
+
+ failf := func(format string, a ...any) (*flag.Flag, []string, error) {
+ return f, args, fmt.Errorf(format, a...)
+ }
+
+ if fv, ok := f.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
+ if hasValue {
+ if err := fs.Set(name, value); err != nil {
+ return failf("invalid boolean value %q for -%s: %v", value, name, err)
+ }
+ } else {
+ if err := fs.Set(name, "true"); err != nil {
+ return failf("invalid boolean flag %s: %v", name, err)
+ }
+ }
+ } else {
+ // It must have a value, which might be the next argument.
+ if !hasValue && len(args) > 0 {
+ // value is the next arg
+ hasValue = true
+ value, args = args[0], args[1:]
+ }
+ if !hasValue {
+ return failf("flag needs an argument: -%s", name)
+ }
+ if err := fs.Set(name, value); err != nil {
+ return failf("invalid value %q for flag -%s: %v", value, name, err)
+ }
+ }
+
+ return f, args, nil
+}
+
+type boolFlag interface {
+ IsBoolFlag() bool
+}