GO: Run cli command with wrong args

2.3k Views Asked by At

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 ?

https://play.golang.org/p/B00z4eZ7Sj-

1

There are 1 best solutions below

0
On BEST ANSWER

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