I use cobra to create CLI command tool. everything is looking OK except the error handling
what I want that if command was sent by mistake (wrong args or wrong input) return std.err instead of std.out
to simplify the secnario I've created this which demonstrate my use-case
package main
import (
"errors"
"fmt"
"os"
"github.com/spf13/cobra"
)
var (
RootCmd = &cobra.Command{
Use: "myApp",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("ROOT verbose = %d, args = %v\n", args)
},
}
provideCmd = &cobra.Command{
Use: "provide",
Run: nil,
}
appCmd = &cobra.Command{
Use: "apps",
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
if name != "myapp" {
err := errors.New("app name doesnt exist")
return err
}
return nil
},
SilenceUsage: true,
}
)
func init() {
// Add the application command to app command
provideCmd.AddCommand(appCmd)
// add provide command to root command
RootCmd.AddCommand(provideCmd)
}
func main() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
Now if I compile the binary and run exec.Command
against the binary everything is working as expected. but if I want to test the error scenario like mycli provide apps apps1
I want to see that returned in std.err
and not at std.out
When I execute mycli provide apps myapp
everything should be OK
but if I run mycli provide apps myapp2
I want to get std.err and not std.out , which is not the case here ...what am I missing here ?
Your sample already prints the error both to stdout
and stderr
.
By default the cobra
package prints any errors it encounters to stderr
, unless you specifically change that.
So running
./main provide apps something 2> ./stderr.txt
creates a text file with the following content (this is what cobra writes to stderr
without your intervention):
Error: app name doesnt exist
And running ./main provide apps something > ./stdout.txt
- creates a text file with the following content (you printed that yourself with fmt.Println(err)
, the second line from the bottom in your code):
app name doesnt exist
Which means default behaviour prints errors both to stdout
and stderr
.
As Devin has advised you, changing the last line to os.Stderr.WriteString(err)
or
fmt.Fprintln(os.Stderr, err)
(the one I would use) will make your project to print everything to stderr
only, which means printing errors twice:
Error: app name doesnt exist
app name doesnt exist
It might be useful to know that cobra allows you some control of error printing behaviour. For example, you can tell a cobra command which stream to print to:
command.SetOutput(os.Stdout) // Defaults to os.Stderr
you could also prevent printing of errors:
command.SilenceErrors = true
or prevent printing of usage text:
command.SilenceUsage = true