From 59bb8be6ad5c61abe3d9231a4a2ad2065140292b Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 24 Jun 2019 08:29:37 +0100 Subject: [PATCH 1/5] Fix stderr printing functions Follow-up of #822 --- command.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/command.go b/command.go index 42e500de5..5238f1345 100644 --- a/command.go +++ b/command.go @@ -1150,12 +1150,12 @@ func (c *Command) PrintErr(i ...interface{}) { // 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...)) + c.PrintErr(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...)) + c.PrintErr(fmt.Sprintf(format, i...)) } // CommandPath returns the full path to this command. From 0da6ddb27b5488d2b6785736355c9e25c3ca1c5f Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 26 Jun 2019 10:08:12 +0100 Subject: [PATCH 2/5] Errors go to stderr as per POSIX --- command.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/command.go b/command.go index 5238f1345..7794b1aa0 100644 --- a/command.go +++ b/command.go @@ -348,7 +348,7 @@ func (c *Command) UsageFunc() (f func(*Command) error) { c.mergePersistentFlags() err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) if err != nil { - c.Println(err) + c.PrintErrln(err) } return err } @@ -374,7 +374,7 @@ func (c *Command) HelpFunc() func(*Command, []string) { c.mergePersistentFlags() err := tmpl(c.OutOrStderr(), c.HelpTemplate(), c) if err != nil { - c.Println(err) + c.PrintErrln(err) } } } @@ -903,8 +903,8 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { c = cmd } if !c.SilenceErrors { - c.Println("Error:", err.Error()) - c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) + c.PrintErrln("Error:", err.Error()) + c.PrintErr(fmt.Sprintf("Run '%v --help' for usage.\n", c.CommandPath())) } return c, err } @@ -934,7 +934,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { // If root command has SilentErrors flagged, // all subcommands should respect it if !cmd.SilenceErrors && !c.SilenceErrors { - c.Println("Error:", err.Error()) + c.PrintErrln("Error:", err.Error()) } // If root command has SilentUsage flagged, From d7b65d7b7309405f7276466fddd6772b5917ef69 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sun, 12 Apr 2020 09:55:26 +0100 Subject: [PATCH 3/5] use PrintErrf() instead of extra call to Sprintf() --- command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command.go b/command.go index 7794b1aa0..6d9d3d8e2 100644 --- a/command.go +++ b/command.go @@ -904,7 +904,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { } if !c.SilenceErrors { c.PrintErrln("Error:", err.Error()) - c.PrintErr(fmt.Sprintf("Run '%v --help' for usage.\n", c.CommandPath())) + c.PrintErrf("Run '%v --help' for usage.\n", c.CommandPath()) } return c, err } From bf23a831eb6e006bef93ec00edf33ab16055b8e8 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Sun, 12 Apr 2020 09:57:15 +0100 Subject: [PATCH 4/5] Error messages should always be printed to os.Stderr. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 649e2e2f7..b02667f8b 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ var rootCmd = &cobra.Command{ func Execute() { if err := rootCmd.Execute(); err != nil { - fmt.Println(err) + fmt.Fprintln(os.Stderr, err) os.Exit(1) } } From b23cee0b5e2b652d416f80387752360049246253 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 8 Sep 2020 13:25:21 +0100 Subject: [PATCH 5/5] add test case for Print* redirection Thanks: @bukowa for the patch. --- command_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/command_test.go b/command_test.go index 16cc41b4c..3a47a81b3 100644 --- a/command_test.go +++ b/command_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "io/ioutil" "os" "reflect" "strings" @@ -1636,6 +1637,47 @@ func TestUsageStringRedirected(t *testing.T) { } } +func TestCommandPrintRedirection(t *testing.T) { + errBuff, outBuff := bytes.NewBuffer(nil), bytes.NewBuffer(nil) + root := &Command{ + Run: func(cmd *Command, args []string) { + + cmd.PrintErr("PrintErr") + cmd.PrintErrln("PrintErr", "line") + cmd.PrintErrf("PrintEr%s", "r") + + cmd.Print("Print") + cmd.Println("Print", "line") + cmd.Printf("Prin%s", "t") + }, + } + + root.SetErr(errBuff) + root.SetOut(outBuff) + + if err := root.Execute(); err != nil { + t.Error(err) + } + + gotErrBytes, err := ioutil.ReadAll(errBuff) + if err != nil { + t.Error(err) + } + + gotOutBytes, err := ioutil.ReadAll(outBuff) + if err != nil { + t.Error(err) + } + + if wantErr := []byte("PrintErrPrintErr line\nPrintErr"); !bytes.Equal(gotErrBytes, wantErr) { + t.Errorf("got: '%s' want: '%s'", gotErrBytes, wantErr) + } + + if wantOut := []byte("PrintPrint line\nPrint"); !bytes.Equal(gotOutBytes, wantOut) { + t.Errorf("got: '%s' want: '%s'", gotOutBytes, wantOut) + } +} + func TestFlagErrorFunc(t *testing.T) { c := &Command{Use: "c", Run: emptyRun}