414c91d
From 81378bbcd8a1005f72b1e8d7579e5dd7b2d612ab Mon Sep 17 00:00:00 2001
414c91d
From: Ryan McKern <344926+mckern@users.noreply.github.com>
414c91d
Date: Mon, 4 May 2020 07:38:53 -0700
414c91d
Subject: [PATCH] Add exported functions to preserve `pkg/flag` compatibility
414c91d
 (#220)
414c91d
414c91d
* Rename out() to Output()
414c91d
414c91d
This brings behavior inline with go's flag library, and allows for
414c91d
printing output directly to whatever the current FlagSet is using for
414c91d
output. This change will make it easier to correctly emit output to
414c91d
stdout or stderr (e.g. a user has requested a help screen, which
414c91d
should emit to stdout since it's the desired outcome).
414c91d
414c91d
* improve compat. with pkg/flag by adding Name()
414c91d
414c91d
pkg/flag has a public `Name()` function, which returns the name of the
414c91d
flag set when called. This commit adds that function, as well as a
414c91d
test for it.
414c91d
414c91d
* Streamline testing Name()
414c91d
414c91d
Testing `Name()` will move into its own explicit test, instead of
414c91d
running inline during `TestAddFlagSet()`.
414c91d
414c91d
Co-authored-by: Chloe Kudryavtsev <toast@toast.cafe>
414c91d
414c91d
Co-authored-by: Chloe Kudryavtsev <toast@toast.cafe>
414c91d
---
414c91d
 flag.go      | 29 ++++++++++++++++++-----------
414c91d
 flag_test.go | 21 +++++++++++++++++++++
414c91d
 2 files changed, 39 insertions(+), 11 deletions(-)
414c91d
414c91d
diff --git a/flag.go b/flag.go
414c91d
index 24a5036..7c058de 100644
414c91d
--- a/flag.go
414c91d
+++ b/flag.go
414c91d
@@ -160,7 +160,7 @@ type FlagSet struct {
414c91d
 	args              []string // arguments after flags
414c91d
 	argsLenAtDash     int      // len(args) when a '--' was located when parsing, or -1 if no --
414c91d
 	errorHandling     ErrorHandling
414c91d
-	output            io.Writer // nil means stderr; use out() accessor
414c91d
+	output            io.Writer // nil means stderr; use Output() accessor
414c91d
 	interspersed      bool      // allow interspersed option/non-option args
414c91d
 	normalizeNameFunc func(f *FlagSet, name string) NormalizedName
414c91d
 
414c91d
@@ -255,13 +255,20 @@ func (f *FlagSet) normalizeFlagName(name string) NormalizedName {
414c91d
 	return n(f, name)
414c91d
 }
414c91d
 
414c91d
-func (f *FlagSet) out() io.Writer {
414c91d
+// Output returns the destination for usage and error messages. os.Stderr is returned if
414c91d
+// output was not set or was set to nil.
414c91d
+func (f *FlagSet) Output() io.Writer {
414c91d
 	if f.output == nil {
414c91d
 		return os.Stderr
414c91d
 	}
414c91d
 	return f.output
414c91d
 }
414c91d
 
414c91d
+// Name returns the name of the flag set.
414c91d
+func (f *FlagSet) Name() string {
414c91d
+	return f.name
414c91d
+}
414c91d
+
414c91d
 // SetOutput sets the destination for usage and error messages.
414c91d
 // If output is nil, os.Stderr is used.
414c91d
 func (f *FlagSet) SetOutput(output io.Writer) {
414c91d
@@ -358,7 +365,7 @@ func (f *FlagSet) ShorthandLookup(name string) *Flag {
414c91d
 	}
414c91d
 	if len(name) > 1 {
414c91d
 		msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name)
414c91d
-		fmt.Fprintf(f.out(), msg)
414c91d
+		fmt.Fprintf(f.Output(), msg)
414c91d
 		panic(msg)
414c91d
 	}
414c91d
 	c := name[0]
414c91d
@@ -482,7 +489,7 @@ func (f *FlagSet) Set(name, value string) error {
414c91d
 	}
414c91d
 
414c91d
 	if flag.Deprecated != "" {
414c91d
-		fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
414c91d
+		fmt.Fprintf(f.Output(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
414c91d
 	}
414c91d
 	return nil
414c91d
 }
414c91d
@@ -523,7 +530,7 @@ func Set(name, value string) error {
414c91d
 // otherwise, the default values of all defined flags in the set.
414c91d
 func (f *FlagSet) PrintDefaults() {
414c91d
 	usages := f.FlagUsages()
414c91d
-	fmt.Fprint(f.out(), usages)
414c91d
+	fmt.Fprint(f.Output(), usages)
414c91d
 }
414c91d
 
414c91d
 // defaultIsZeroValue returns true if the default value for this flag represents
414c91d
@@ -758,7 +765,7 @@ func PrintDefaults() {
414c91d
 
414c91d
 // defaultUsage is the default function to print a usage message.
414c91d
 func defaultUsage(f *FlagSet) {
414c91d
-	fmt.Fprintf(f.out(), "Usage of %s:\n", f.name)
414c91d
+	fmt.Fprintf(f.Output(), "Usage of %s:\n", f.name)
414c91d
 	f.PrintDefaults()
414c91d
 }
414c91d
 
414c91d
@@ -844,7 +851,7 @@ func (f *FlagSet) AddFlag(flag *Flag) {
414c91d
 	_, alreadyThere := f.formal[normalizedFlagName]
414c91d
 	if alreadyThere {
414c91d
 		msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name)
414c91d
-		fmt.Fprintln(f.out(), msg)
414c91d
+		fmt.Fprintln(f.Output(), msg)
414c91d
 		panic(msg) // Happens only if flags are declared with identical names
414c91d
 	}
414c91d
 	if f.formal == nil {
414c91d
@@ -860,7 +867,7 @@ func (f *FlagSet) AddFlag(flag *Flag) {
414c91d
 	}
414c91d
 	if len(flag.Shorthand) > 1 {
414c91d
 		msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand)
414c91d
-		fmt.Fprintf(f.out(), msg)
414c91d
+		fmt.Fprintf(f.Output(), msg)
414c91d
 		panic(msg)
414c91d
 	}
414c91d
 	if f.shorthands == nil {
414c91d
@@ -870,7 +877,7 @@ func (f *FlagSet) AddFlag(flag *Flag) {
414c91d
 	used, alreadyThere := f.shorthands[c]
414c91d
 	if alreadyThere {
414c91d
 		msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name)
414c91d
-		fmt.Fprintf(f.out(), msg)
414c91d
+		fmt.Fprintf(f.Output(), msg)
414c91d
 		panic(msg)
414c91d
 	}
414c91d
 	f.shorthands[c] = flag
414c91d
@@ -909,7 +916,7 @@ func VarP(value Value, name, shorthand, usage string) {
414c91d
 func (f *FlagSet) failf(format string, a ...interface{}) error {
414c91d
 	err := fmt.Errorf(format, a...)
414c91d
 	if f.errorHandling != ContinueOnError {
414c91d
-		fmt.Fprintln(f.out(), err)
414c91d
+		fmt.Fprintln(f.Output(), err)
414c91d
 		f.usage()
414c91d
 	}
414c91d
 	return err
414c91d
@@ -1060,7 +1067,7 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse
414c91d
 	}
414c91d
 
414c91d
 	if flag.ShorthandDeprecated != "" {
414c91d
-		fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
414c91d
+		fmt.Fprintf(f.Output(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
414c91d
 	}
414c91d
 
414c91d
 	err = fn(flag, value)
414c91d
diff --git a/flag_test.go b/flag_test.go
414c91d
index 7d02dbc..58a5d25 100644
414c91d
--- a/flag_test.go
414c91d
+++ b/flag_test.go
414c91d
@@ -159,6 +159,16 @@ func TestAnnotation(t *testing.T) {
414c91d
 	}
414c91d
 }
414c91d
 
414c91d
+func TestName(t *testing.T) {
414c91d
+	flagSetName := "bob"
414c91d
+	f := NewFlagSet(flagSetName, ContinueOnError)
414c91d
+
414c91d
+	givenName := f.Name()
414c91d
+	if givenName != flagSetName {
414c91d
+		t.Errorf("Unexpected result when retrieving a FlagSet's name: expected %s, but found %s", flagSetName, givenName)
414c91d
+	}
414c91d
+}
414c91d
+
414c91d
 func testParse(f *FlagSet, t *testing.T) {
414c91d
 	if f.Parsed() {
414c91d
 		t.Error("f.Parse() = true before Parse")
414c91d
@@ -854,6 +864,17 @@ func TestSetOutput(t *testing.T) {
414c91d
 	}
414c91d
 }
414c91d
 
414c91d
+func TestOutput(t *testing.T) {
414c91d
+	var flags FlagSet
414c91d
+	var buf bytes.Buffer
414c91d
+	expect := "an example string"
414c91d
+	flags.SetOutput(&buf)
414c91d
+	fmt.Fprint(flags.Output(), expect)
414c91d
+	if out := buf.String(); !strings.Contains(out, expect) {
414c91d
+		t.Errorf("expected output %q; got %q", expect, out)
414c91d
+	}
414c91d
+}
414c91d
+
414c91d
 // This tests that one can reset the flags. This still works but not well, and is
414c91d
 // superseded by FlagSet.
414c91d
 func TestChangingArgs(t *testing.T) {