Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct pattern for exiting a command with a non zero return code #2124

Open
tomqwpl opened this issue Mar 14, 2024 · 2 comments
Open

Correct pattern for exiting a command with a non zero return code #2124

tomqwpl opened this issue Mar 14, 2024 · 2 comments

Comments

@tomqwpl
Copy link

tomqwpl commented Mar 14, 2024

I'm trying to establish what the correct pattern is for exiting a command with a non zero return code.

I can use RunE, but the normal effect of that is that the "usage" is printed out, since there's no distinction between an error from validating the args (where you would want usage to result) and an error from the operation of your command. You can SilenceUsage, but then you get no usage help on invalid args either, so that doesn't feel like the right way.

The examples generated by the CLI all use Run instead of RunE. The implication would appear to be that I have to manually os.Exit(1) if I want my command to "fail" and return a non zero return code. But that feels wrong, it's going to skip all of the post run actions etc.

Looking at a couple of examples, it seems like managing an exit code outside of cobra seems to be a solution used in a few places, so letting the command run to completion and then once cobra has returned calling os.Exit() with the value that's stored in some global variable somewhere.

What's the idiomatic usage here?

Thanks

@tomqwpl
Copy link
Author

tomqwpl commented Mar 14, 2024

This almost gives me what I want:

var rootCmd = &cobra.Command{
	SilenceErrors:     true,
	SilenceUsage:      true,
}

func init() {
	rootCmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error {
		return fmt.Errorf("%w\n\n%s", err, c.UsageString())
	})
}

func main() {
	err := rootCmd.Execute()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

The SetFlagErrorFunc allows a hook when the error is caused by bad flags, but that doesn't get fired for invalid arguments other than flags (so validation done by the "Args" field in Command). Then use RunE, so you can return an error from the command and it will cause a non zero return code.

This has always somewhat surprised me in cobra. I'd have thought that the normal desired behaviour would be "invalid flags or args or command name, print error then usage, errors from the command, just print error". I've always slightly struggled to get that behaviour.

@nirs
Copy link
Contributor

nirs commented May 3, 2024

I'm using Run: and terminate on errors with log.Fatal() or os.Exit(). If the error is not a usage error, why print usage messages?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants