From 53fd438f2d03dcc1452ad22caa90808fb00b2805 Mon Sep 17 00:00:00 2001 From: gdm85 Date: Wed, 19 Dec 2018 20:22:25 +0100 Subject: [PATCH 1/2] Add support for IsSpecified Removes Init method to standardize on NewFlagSet --- export_test.go | 1 + flag.go | 26 ++++++++++++-------------- flag_test.go | 28 ++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/export_test.go b/export_test.go index 9318fee0..1d6f1e47 100644 --- a/export_test.go +++ b/export_test.go @@ -19,6 +19,7 @@ func ResetForTesting(usage func()) { name: os.Args[0], errorHandling: ContinueOnError, output: ioutil.Discard, + actual: map[string]*Flag{}, } Usage = usage } diff --git a/flag.go b/flag.go index 9d1e0ca5..f0dc431e 100644 --- a/flag.go +++ b/flag.go @@ -215,6 +215,17 @@ func Lookup(name string) *Flag { return CommandLine.formal[name] } +// IsSpecified returns true if the named flag was specified via command-line flags. +func (f *FlagSet) IsSpecified(name string) bool { + _, ok := f.actual[name] + return ok +} + +// IsSpecified returns true if the named flag was specified via command-line flags. +func IsSpecified(name string) bool { + return CommandLine.IsSpecified(name) +} + // Set sets the value of the named flag. func (f *FlagSet) Set(name, value string) error { flag, ok := f.formal[name] @@ -225,9 +236,6 @@ func (f *FlagSet) Set(name, value string) error { if err != nil { return err } - if f.actual == nil { - f.actual = make(map[string]*Flag) - } f.actual[name] = flag return nil } @@ -465,9 +473,6 @@ func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error { return f.failf("invalid argument %q for %s: %v", value, origArg, err) } // mark as visited for Visit() - if f.actual == nil { - f.actual = make(map[string]*Flag) - } f.actual[flag.Name] = flag return nil @@ -606,6 +611,7 @@ func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { name: name, errorHandling: errorHandling, interspersed: true, + actual: map[string]*Flag{}, } return f } @@ -614,11 +620,3 @@ func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { func (f *FlagSet) SetInterspersed(interspersed bool) { f.interspersed = interspersed } - -// Init sets the name and error handling property for a flag set. -// By default, the zero FlagSet uses an empty name and the -// ContinueOnError error handling policy. -func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { - f.name = name - f.errorHandling = errorHandling -} diff --git a/flag_test.go b/flag_test.go index 82f7fae7..5cbb5c55 100644 --- a/flag_test.go +++ b/flag_test.go @@ -242,8 +242,7 @@ func (f *flagVar) Set(value string) error { } func TestUserDefined(t *testing.T) { - var flags FlagSet - flags.Init("test", ContinueOnError) + flags := NewFlagSet("test", ContinueOnError) var v flagVar flags.VarP(&v, "v", "v", "usage") if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil { @@ -259,10 +258,9 @@ func TestUserDefined(t *testing.T) { } func TestSetOutput(t *testing.T) { - var flags FlagSet + flags := NewFlagSet("test", ContinueOnError) var buf bytes.Buffer flags.SetOutput(&buf) - flags.Init("test", ContinueOnError) flags.Parse([]string{"--unknown"}) if out := buf.String(); !strings.Contains(out, "--unknown") { t.Logf("expected output mentioning unknown; got %q", out) @@ -348,3 +346,25 @@ func TestNoInterspersed(t *testing.T) { t.Fatal("expected interspersed options/non-options to fail") } } + +func TestIsSpecified(t *testing.T) { + f := NewFlagSet("test", ContinueOnError) + f.SetInterspersed(false) + f.Bool("alpha", true, "always true") + f.Bool("beta", false, "always false") + err := f.Parse([]string{"--beta"}) + if err != nil { + t.Fatal("expected no error; got ", err) + } + args := f.Args() + if len(args) != 0 { + t.Fatal("expected no extra args") + } + + if !f.IsSpecified("beta") { + t.Fatal("expected beta to be specified") + } + if f.IsSpecified("alpha") { + t.Fatal("expected alpha to not be specified") + } +} From fd67019e6e2ef927757041c77f973740263cc8ba Mon Sep 17 00:00:00 2001 From: gdm85 Date: Sun, 12 Oct 2025 08:50:02 +0200 Subject: [PATCH 2/2] fix: port to recent Go --- README.md | 14 ++-- example_test.go | 2 +- flag.go | 185 ++++++++++++++++++++++++++---------------------- go.mod | 3 + 4 files changed, 109 insertions(+), 95 deletions(-) create mode 100644 go.mod diff --git a/README.md b/README.md index d9b189f8..27554dff 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -[![Build Status](https://travis-ci.org/ogier/pflag.png?branch=master)](https://travis-ci.org/ogier/pflag) - ## Description pflag is a drop-in replacement for Go's flag package, implementing @@ -20,11 +18,11 @@ pflag is available using the standard `go get` command. Install by running: - go get github.com/ogier/pflag + go get github.com/gdm85/pflag Run tests by running: - go test github.com/ogier/pflag + go test github.com/gdm85/pflag ## Usage @@ -33,7 +31,7 @@ pflag under the name "flag" then all code should continue to function with no changes. ``` go -import flag "github.com/ogier/pflag" +import flag "github.com/gdm85/pflag" ``` There is one exception to this: if you directly instantiate the Flag struct @@ -150,8 +148,8 @@ Duration flags accept any input valid for time.ParseDuration. You can see the full reference documentation of the pflag package [at godoc.org][3], or through go's standard documentation system by running `godoc -http=:6060` and browsing to -[http://localhost:6060/pkg/github.com/ogier/pflag][2] after +[http://localhost:6060/pkg/github.com/gdm85/pflag][2] after installation. -[2]: http://localhost:6060/pkg/github.com/ogier/pflag -[3]: http://godoc.org/github.com/ogier/pflag +[2]: http://localhost:6060/pkg/github.com/gdm85/pflag +[3]: http://godoc.org/github.com/gdm85/pflag diff --git a/example_test.go b/example_test.go index 03ebeaad..5c853a90 100644 --- a/example_test.go +++ b/example_test.go @@ -11,7 +11,7 @@ import ( "strings" "time" - flag "github.com/ogier/pflag" + flag "github.com/gdm85/pflag" ) // Example 1: A single string flag called "species" with default value "gopher". diff --git a/flag.go b/flag.go index f0dc431e..ea621345 100644 --- a/flag.go +++ b/flag.go @@ -3,98 +3,111 @@ // license that can be found in the LICENSE file. /* - pflag is a drop-in replacement for Go's flag package, implementing - POSIX/GNU-style --flags. +pflag is a drop-in replacement for Go's flag package, implementing +POSIX/GNU-style --flags. - pflag is compatible with the GNU extensions to the POSIX recommendations - for command-line options. See - http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html +pflag is compatible with the GNU extensions to the POSIX recommendations +for command-line options. See +http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html - Usage: +Usage: - pflag is a drop-in replacement of Go's native flag package. If you import - pflag under the name "flag" then all code should continue to function - with no changes. +pflag is a drop-in replacement of Go's native flag package. If you import +pflag under the name "flag" then all code should continue to function +with no changes. - import flag "github.com/ogier/pflag" + import flag "github.com/gdm85/pflag" - There is one exception to this: if you directly instantiate the Flag struct - there is one more field "Shorthand" that you will need to set. - Most code never instantiates this struct directly, and instead uses - functions such as String(), BoolVar(), and Var(), and is therefore - unaffected. +There is one exception to this: if you directly instantiate the Flag struct +there is one more field "Shorthand" that you will need to set. +Most code never instantiates this struct directly, and instead uses +functions such as String(), BoolVar(), and Var(), and is therefore +unaffected. - Define flags using flag.String(), Bool(), Int(), etc. +Define flags using flag.String(), Bool(), Int(), etc. - This declares an integer flag, -flagname, stored in the pointer ip, with type *int. - var ip = flag.Int("flagname", 1234, "help message for flagname") - If you like, you can bind the flag to a variable using the Var() functions. - var flagvar int - func init() { - flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") - } - Or you can create custom flags that satisfy the Value interface (with - pointer receivers) and couple them to flag parsing by - flag.Var(&flagVal, "name", "help message for flagname") - For such flags, the default value is just the initial value of the variable. - - After all flags are defined, call - flag.Parse() - to parse the command line into the defined flags. - - Flags may then be used directly. If you're using the flags themselves, - they are all pointers; if you bind to variables, they're values. - fmt.Println("ip has value ", *ip) - fmt.Println("flagvar has value ", flagvar) - - After parsing, the arguments after the flag are available as the - slice flag.Args() or individually as flag.Arg(i). - The arguments are indexed from 0 through flag.NArg()-1. - - The pflag package also defines some new functions that are not in flag, - that give one-letter shorthands for flags. You can use these by appending - 'P' to the name of any function that defines a flag. - var ip = flag.IntP("flagname", "f", 1234, "help message") - var flagvar bool - func init() { - flag.BoolVarP("boolname", "b", true, "help message") - } - flag.VarP(&flagVar, "varname", "v", 1234, "help message") - Shorthand letters can be used with single dashes on the command line. - Boolean shorthand flags can be combined with other shorthand flags. - - Command line flag syntax: - --flag // boolean flags only - --flag=x - - Unlike the flag package, a single dash before an option means something - different than a double dash. Single dashes signify a series of shorthand - letters for flags. All but the last shorthand letter must be boolean flags. - // boolean flags - -f - -abc - // non-boolean flags - -n 1234 - -Ifile - // mixed - -abcs "hello" - -abcn1234 - - Flag parsing stops after the terminator "--". Unlike the flag package, - flags can be interspersed with arguments anywhere on the command line - before this terminator. - - Integer flags accept 1234, 0664, 0x1234 and may be negative. - Boolean flags (in their long form) accept 1, 0, t, f, true, false, - TRUE, FALSE, True, False. - Duration flags accept any input valid for time.ParseDuration. - - The default set of command-line flags is controlled by - top-level functions. The FlagSet type allows one to define - independent sets of flags, such as to implement subcommands - in a command-line interface. The methods of FlagSet are - analogous to the top-level functions for the command-line - flag set. +This declares an integer flag, -flagname, stored in the pointer ip, with type *int. + + var ip = flag.Int("flagname", 1234, "help message for flagname") + +If you like, you can bind the flag to a variable using the Var() functions. + + var flagvar int + func init() { + flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") + } + +Or you can create custom flags that satisfy the Value interface (with +pointer receivers) and couple them to flag parsing by + + flag.Var(&flagVal, "name", "help message for flagname") + +For such flags, the default value is just the initial value of the variable. + +After all flags are defined, call + + flag.Parse() + +to parse the command line into the defined flags. + +Flags may then be used directly. If you're using the flags themselves, +they are all pointers; if you bind to variables, they're values. + + fmt.Println("ip has value ", *ip) + fmt.Println("flagvar has value ", flagvar) + +After parsing, the arguments after the flag are available as the +slice flag.Args() or individually as flag.Arg(i). +The arguments are indexed from 0 through flag.NArg()-1. + +The pflag package also defines some new functions that are not in flag, +that give one-letter shorthands for flags. You can use these by appending +'P' to the name of any function that defines a flag. + + var ip = flag.IntP("flagname", "f", 1234, "help message") + var flagvar bool + func init() { + flag.BoolVarP("boolname", "b", true, "help message") + } + flag.VarP(&flagVar, "varname", "v", 1234, "help message") + +Shorthand letters can be used with single dashes on the command line. +Boolean shorthand flags can be combined with other shorthand flags. + +Command line flag syntax: + + --flag // boolean flags only + --flag=x + +Unlike the flag package, a single dash before an option means something +different than a double dash. Single dashes signify a series of shorthand +letters for flags. All but the last shorthand letter must be boolean flags. + + // boolean flags + -f + -abc + // non-boolean flags + -n 1234 + -Ifile + // mixed + -abcs "hello" + -abcn1234 + +Flag parsing stops after the terminator "--". Unlike the flag package, +flags can be interspersed with arguments anywhere on the command line +before this terminator. + +Integer flags accept 1234, 0664, 0x1234 and may be negative. +Boolean flags (in their long form) accept 1, 0, t, f, true, false, +TRUE, FALSE, True, False. +Duration flags accept any input valid for time.ParseDuration. + +The default set of command-line flags is controlled by +top-level functions. The FlagSet type allows one to define +independent sets of flags, such as to implement subcommands +in a command-line interface. The methods of FlagSet are +analogous to the top-level functions for the command-line +flag set. */ package pflag @@ -611,7 +624,7 @@ func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { name: name, errorHandling: errorHandling, interspersed: true, - actual: map[string]*Flag{}, + actual: map[string]*Flag{}, } return f } diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..6dde1cb0 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/gdm85/pflag + +go 1.24.0