diff --git a/flag.go b/flag.go index ced8440a..fd49a788 100644 --- a/flag.go +++ b/flag.go @@ -567,7 +567,7 @@ func (f *FlagSet) Set(name, value string) error { } if flag.Deprecated != "" { - _, _ = fmt.Fprintf(f.Output(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) + _, _ = fmt.Fprintf(f.Output(), "Flag --%s has been deprecated, %s\n", name, flag.Deprecated) } return nil } @@ -1110,7 +1110,9 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin return } - err = fn(flag, value) + // Pass the name the user actually typed so a deprecation message reports + // it rather than the canonical name a NormalizeFunc may have mapped it to. + err = fn(flag, name, value) if err != nil { err = f.fail(err) } @@ -1200,7 +1202,9 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse _, _ = fmt.Fprintf(f.Output(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) } - err = fn(flag, value) + // A shorthand has no alias to report, so a deprecation message keeps the + // canonical long name. + err = fn(flag, flag.Name, value) if err != nil { err = f.fail(err) } @@ -1294,8 +1298,8 @@ func (f *FlagSet) Parse(arguments []string) error { return nil } - set := func(flag *Flag, value string) error { - return f.Set(flag.Name, value) + set := func(flag *Flag, name, value string) error { + return f.Set(name, value) } err := f.parseArgs(arguments, set) @@ -1316,7 +1320,7 @@ func (f *FlagSet) Parse(arguments []string) error { return nil } -type parseFunc func(flag *Flag, value string) error +type parseFunc func(flag *Flag, name, value string) error // ParseAll parses flag definitions from the argument list, which should not // include the command name. The arguments for fn are flag and value. Must be @@ -1327,7 +1331,11 @@ func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) f.parsed = true f.args = make([]string, 0, len(arguments)) - err := f.parseArgs(arguments, fn) + set := func(flag *Flag, name, value string) error { + return fn(flag, value) + } + + err := f.parseArgs(arguments, set) if err != nil { switch f.errorHandling { case ContinueOnError: diff --git a/flag_test.go b/flag_test.go index 82fcd48a..509a8c70 100644 --- a/flag_test.go +++ b/flag_test.go @@ -1401,6 +1401,33 @@ func TestDeprecatedFlagUsageNormalized(t *testing.T) { } } +func TestDeprecatedFlagUsageAlias(t *testing.T) { + // When a NormalizeFunc aliases one flag name to another, using the alias + // to set a deprecated flag should report the name the user actually typed, + // not the canonical name. See https://github.com/spf13/pflag/issues/279. + f := NewFlagSet("bob", ContinueOnError) + f.String("src", "", "src directory or file") + f.SetNormalizeFunc(func(_ *FlagSet, name string) NormalizedName { + if name == "dir" { + name = "src" + } + return NormalizedName(name) + }) + _ = f.MarkDeprecated("src", "use --src") + + out, err := parseReturnStderr(t, f, []string{"--dir=x"}) + if err != nil { + t.Fatal("expected no error; got ", err) + } + + if !strings.Contains(out, "Flag --dir has been deprecated") { + t.Errorf("expected the deprecation message to name the flag the user typed (--dir); got: %q", out) + } + if strings.Contains(out, "Flag --src has been deprecated") { + t.Errorf("deprecation message should not name the canonical flag (--src); got: %q", out) + } +} + // Name normalization function should be called only once on flag addition func TestMultipleNormalizeFlagNameInvocations(t *testing.T) { normalizeFlagNameInvocations = 0