From daf3ced8286e9bfa79a26c624737375979885a88 Mon Sep 17 00:00:00 2001
From: Juan Leni <lenijuan@gmail.com>
Date: Mon, 11 Feb 2019 07:10:59 +0100
Subject: [PATCH 1/7] Extending redirection to stdout, stderr, stdin

---
 command.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 61 insertions(+), 8 deletions(-)

diff --git a/command.go b/command.go
index b257f91b6..a00367d36 100644
--- a/command.go
+++ b/command.go
@@ -177,8 +177,6 @@ type Command struct {
 	// that we can use on every pflag set and children commands
 	globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName
 
-	// output is an output writer defined by user.
-	output io.Writer
 	// usageFunc is usage func defined by user.
 	usageFunc func(*Command) error
 	// usageTemplate is usage template defined by user.
@@ -195,6 +193,13 @@ type Command struct {
 	helpCommand *Command
 	// versionTemplate is the version template defined by user.
 	versionTemplate string
+
+	// inReader is a reader defined by the user that replaces stdin
+	inReader io.Reader
+	// outWriter is a writer defined by the user that replaces stdout
+	outWriter io.Writer
+	// errWriter is a writer defined by the user that replaces stderr
+	errWriter io.Writer
 }
 
 // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
@@ -206,7 +211,25 @@ func (c *Command) SetArgs(a []string) {
 // SetOutput sets the destination for usage and error messages.
 // If output is nil, os.Stderr is used.
 func (c *Command) SetOutput(output io.Writer) {
-	c.output = output
+	c.outWriter = output
+}
+
+// SetOut sets the destination for usage messages.
+// If newOut is nil, os.Stdout is used.
+func (c *Command) SetOut(newOut io.Writer) {
+	c.outWriter =  newOut
+}
+
+// SetErr sets the destination for error messages.
+// If newErr is nil, os.Stderr is used.
+func (c *Command) SetErr(newErr io.Writer)  {
+	c.errWriter = newErr
+}
+
+// SetOut sets the source for input data
+// If newIn is nil, os.Stdin is used.
+func (c *Command) SetIn(newIn io.Reader) {
+	c.inReader = newIn
 }
 
 // SetUsageFunc sets usage function. Usage can be defined by application.
@@ -267,9 +290,19 @@ func (c *Command) OutOrStderr() io.Writer {
 	return c.getOut(os.Stderr)
 }
 
+// ErrOrStderr returns output to stderr
+func (c *Command) ErrOrStderr() io.Writer {
+	return c.getErr(os.Stderr)
+}
+
+// ErrOrStderr returns output to stderr
+func (c *Command) InOrStdin() io.Reader {
+	return c.getIn(os.Stdin)
+}
+
 func (c *Command) getOut(def io.Writer) io.Writer {
-	if c.output != nil {
-		return c.output
+	if c.outWriter != nil {
+		return c.outWriter
 	}
 	if c.HasParent() {
 		return c.parent.getOut(def)
@@ -277,6 +310,26 @@ func (c *Command) getOut(def io.Writer) io.Writer {
 	return def
 }
 
+func (c *Command) getErr(def io.Writer) io.Writer {
+	if c.errWriter != nil {
+		return c.errWriter
+	}
+	if c.HasParent() {
+		return c.parent.getErr(def)
+	}
+	return def
+}
+
+func (c *Command) getIn(def io.Reader) io.Reader {
+	if c.inReader != nil {
+		return c.inReader
+	}
+	if c.HasParent() {
+		return c.parent.getIn(def)
+	}
+	return def
+}
+
 // UsageFunc returns either the function set by SetUsageFunc for this command
 // or a parent, or it returns a default usage function.
 func (c *Command) UsageFunc() (f func(*Command) error) {
@@ -331,11 +384,11 @@ func (c *Command) Help() error {
 
 // UsageString return usage string.
 func (c *Command) UsageString() string {
-	tmpOutput := c.output
+	tmpOutput := c.outWriter
 	bb := new(bytes.Buffer)
-	c.SetOutput(bb)
+	c.outWriter = bb
 	c.Usage()
-	c.output = tmpOutput
+	c.outWriter = tmpOutput
 	return bb.String()
 }
 

From d4fdebeba208e0114985f0e0a097c93fd267ec2e Mon Sep 17 00:00:00 2001
From: Juan Leni <lenijuan@gmail.com>
Date: Mon, 11 Feb 2019 08:22:54 +0100
Subject: [PATCH 2/7] Fixed linter issues

---
 command.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/command.go b/command.go
index a00367d36..58cc87322 100644
--- a/command.go
+++ b/command.go
@@ -217,12 +217,12 @@ func (c *Command) SetOutput(output io.Writer) {
 // SetOut sets the destination for usage messages.
 // If newOut is nil, os.Stdout is used.
 func (c *Command) SetOut(newOut io.Writer) {
-	c.outWriter =  newOut
+	c.outWriter = newOut
 }
 
 // SetErr sets the destination for error messages.
 // If newErr is nil, os.Stderr is used.
-func (c *Command) SetErr(newErr io.Writer)  {
+func (c *Command) SetErr(newErr io.Writer) {
 	c.errWriter = newErr
 }
 

From 3b830e63629a7ddbbb9a449eaa6c7cf479650c6b Mon Sep 17 00:00:00 2001
From: Juan Leni <lenijuan@gmail.com>
Date: Mon, 11 Feb 2019 16:06:55 +0100
Subject: [PATCH 3/7] Allow for explicit output to err/stderr

---
 command.go | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/command.go b/command.go
index 58cc87322..3e97687a2 100644
--- a/command.go
+++ b/command.go
@@ -1121,6 +1121,21 @@ func (c *Command) Printf(format string, i ...interface{}) {
 	c.Print(fmt.Sprintf(format, i...))
 }
 
+// PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set.
+func (c *Command) PrintErr(i ...interface{}) {
+	fmt.Fprint(c.ErrOrStderr(), i...)
+}
+
+// PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set.
+func (c *Command) PrintErrln(i ...interface{}) {
+	c.Print(fmt.Sprintln(i...))
+}
+
+// PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set.
+func (c *Command) PrintErrf(format string, i ...interface{}) {
+	c.Print(fmt.Sprintf(format, i...))
+}
+
 // CommandPath returns the full path to this command.
 func (c *Command) CommandPath() string {
 	if c.HasParent() {

From 0bc69e72916c8841976f4954b45e73e36a0be934 Mon Sep 17 00:00:00 2001
From: Juan Leni <lenijuan@gmail.com>
Date: Wed, 13 Feb 2019 06:32:16 +0100
Subject: [PATCH 4/7] Deprecate and maintain backwards compatibility

---
 command.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/command.go b/command.go
index 3e97687a2..6dbb3e8c8 100644
--- a/command.go
+++ b/command.go
@@ -210,8 +210,10 @@ func (c *Command) SetArgs(a []string) {
 
 // SetOutput sets the destination for usage and error messages.
 // If output is nil, os.Stderr is used.
+// Deprecated: Use SetOut and/or SetErr instead
 func (c *Command) SetOutput(output io.Writer) {
 	c.outWriter = output
+	c.errWriter = output
 }
 
 // SetOut sets the destination for usage messages.

From 2bd35aa49d5ae32382592ebbad54a00300f2fe14 Mon Sep 17 00:00:00 2001
From: Alessio Treglia <quadrispro@ubuntu.com>
Date: Tue, 30 Apr 2019 18:41:56 +0100
Subject: [PATCH 5/7] Add tests

---
 command_test.go | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/command_test.go b/command_test.go
index 6e483a3ec..4f1d36907 100644
--- a/command_test.go
+++ b/command_test.go
@@ -1381,6 +1381,30 @@ func TestSetOutput(t *testing.T) {
 	}
 }
 
+func TestSetOut(t *testing.T) {
+	c := &Command{}
+	c.SetOut(nil)
+	if out := c.OutOrStdout(); out != os.Stdout {
+		t.Errorf("Expected setting output to nil to revert back to stdout")
+	}
+}
+
+func TestSetErr(t *testing.T) {
+	c := &Command{}
+	c.SetErr(nil)
+	if out := c.ErrOrStderr(); out != os.Stderr {
+		t.Errorf("Expected setting error to nil to revert back to stderr")
+	}
+}
+
+func TestSetIn(t *testing.T) {
+	c := &Command{}
+	c.SetIn(nil)
+	if out := c.InOrStdin(); out != os.Stdin {
+		t.Errorf("Expected setting input to nil to revert back to stdin")
+	}
+}
+
 func TestFlagErrorFunc(t *testing.T) {
 	c := &Command{Use: "c", Run: emptyRun}
 

From 4d52f3f7182e5b71c85e1621c6343a3df395478f Mon Sep 17 00:00:00 2001
From: Juan Leni <lenijuan@gmail.com>
Date: Wed, 15 May 2019 18:49:16 +0200
Subject: [PATCH 6/7] considering stderr in UsageString

---
 command.go      | 11 ++++++++++-
 command_test.go | 16 ++++++++++++++++
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/command.go b/command.go
index 6dbb3e8c8..c7e898303 100644
--- a/command.go
+++ b/command.go
@@ -384,13 +384,22 @@ func (c *Command) Help() error {
 	return nil
 }
 
-// UsageString return usage string.
+// UsageString returns usage string.
 func (c *Command) UsageString() string {
+	// Storing normal writers
 	tmpOutput := c.outWriter
+	tmpErr := c.errWriter
+
 	bb := new(bytes.Buffer)
 	c.outWriter = bb
+	c.errWriter = bb
+
 	c.Usage()
+
+	// Setting things back to normal
 	c.outWriter = tmpOutput
+	c.errWriter = tmpErr
+
 	return bb.String()
 }
 
diff --git a/command_test.go b/command_test.go
index 4f1d36907..258f20a25 100644
--- a/command_test.go
+++ b/command_test.go
@@ -1405,6 +1405,22 @@ func TestSetIn(t *testing.T) {
 	}
 }
 
+func TestUsageStringRedirected(t *testing.T) {
+	c := &Command{}
+
+	c.usageFunc = func(cmd *Command) error {
+		cmd.Print("[stdout1]")
+		cmd.PrintErr("[stderr2]")
+		cmd.Print("[stdout3]")
+		return nil;
+	}
+
+	expected := "[stdout1][stderr2][stdout3]"
+	if 	got := c.UsageString(); got != expected {
+		t.Errorf("Expected usage string to consider both stdout and stderr")
+	}
+}
+
 func TestFlagErrorFunc(t *testing.T) {
 	c := &Command{Use: "c", Run: emptyRun}
 

From 558b01866a1ed3abd3fb6106edeef8f1b012f0f8 Mon Sep 17 00:00:00 2001
From: Juan Leni <lenijuan@gmail.com>
Date: Wed, 15 May 2019 18:53:39 +0200
Subject: [PATCH 7/7] fixing linter issues

---
 command_test.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/command_test.go b/command_test.go
index 258f20a25..2fa2003cb 100644
--- a/command_test.go
+++ b/command_test.go
@@ -1412,11 +1412,11 @@ func TestUsageStringRedirected(t *testing.T) {
 		cmd.Print("[stdout1]")
 		cmd.PrintErr("[stderr2]")
 		cmd.Print("[stdout3]")
-		return nil;
+		return nil
 	}
 
 	expected := "[stdout1][stderr2][stdout3]"
-	if 	got := c.UsageString(); got != expected {
+	if got := c.UsageString(); got != expected {
 		t.Errorf("Expected usage string to consider both stdout and stderr")
 	}
 }