From a7c40c36a3a425dd1d28cbc97a3340aafb494d19 Mon Sep 17 00:00:00 2001 From: Hugo Hromic Date: Sat, 29 Jun 2024 15:42:05 +0100 Subject: [PATCH] Use standard exit status code for usage errors * The stdlib `flags` package and most command line utilities use status code `2`. --- parse.go | 2 +- parse_test.go | 6 +++--- usage.go | 8 ++++---- usage_test.go | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/parse.go b/parse.go index 98c21cd..2bed8bf 100644 --- a/parse.go +++ b/parse.go @@ -90,7 +90,7 @@ func mustParse(config Config, dest ...interface{}) *Parser { p, err := NewParser(config, dest...) if err != nil { fmt.Fprintln(config.Out, err) - config.Exit(-1) + config.Exit(2) return nil } diff --git a/parse_test.go b/parse_test.go index 07af7ed..5bc781c 100644 --- a/parse_test.go +++ b/parse_test.go @@ -703,7 +703,7 @@ func TestMustParseError(t *testing.T) { os.Args = []string{"example"} parser := MustParse(&args) assert.Nil(t, parser) - assert.Equal(t, -1, exitCode) + assert.Equal(t, 2, exitCode) assert.Contains(t, stdout.String(), "default values are not supported for slice or map fields") } @@ -921,7 +921,7 @@ func TestParserMustParse(t *testing.T) { }{ {name: "help", args: struct{}{}, cmdLine: []string{"--help"}, code: 0, output: "display this help and exit"}, {name: "version", args: versioned{}, cmdLine: []string{"--version"}, code: 0, output: "example 3.2.1"}, - {name: "invalid", args: struct{}{}, cmdLine: []string{"invalid"}, code: -1, output: ""}, + {name: "invalid", args: struct{}{}, cmdLine: []string{"invalid"}, code: 2, output: ""}, } for _, tt := range tests { @@ -1571,7 +1571,7 @@ func TestMustParseInvalidParser(t *testing.T) { } parser := mustParse(Config{Out: &stdout, Exit: exit}, &args) assert.Nil(t, parser) - assert.Equal(t, -1, exitCode) + assert.Equal(t, 2, exitCode) } func TestMustParsePrintsHelp(t *testing.T) { diff --git a/usage.go b/usage.go index 6b578a5..f5e4b38 100644 --- a/usage.go +++ b/usage.go @@ -9,13 +9,13 @@ import ( // the width of the left column const colWidth = 25 -// Fail prints usage information to stderr and exits with non-zero status +// Fail prints usage information to p.Config.Out and exits with status code 2. func (p *Parser) Fail(msg string) { p.FailSubcommand(msg) } -// FailSubcommand prints usage information for a specified subcommand to stderr, -// then exits with non-zero status. To write usage information for a top-level +// FailSubcommand prints usage information for a specified subcommand to p.Config.Out, +// then exits with status code 2. To write usage information for a top-level // subcommand, provide just the name of that subcommand. To write usage // information for a subcommand that is nested under another subcommand, provide // a sequence of subcommand names starting with the top-level subcommand and so @@ -27,7 +27,7 @@ func (p *Parser) FailSubcommand(msg string, subcommand ...string) error { } fmt.Fprintln(p.config.Out, "error:", msg) - p.config.Exit(-1) + p.config.Exit(2) return nil } diff --git a/usage_test.go b/usage_test.go index b2bcab1..71324eb 100644 --- a/usage_test.go +++ b/usage_test.go @@ -738,7 +738,7 @@ error: something went wrong p.Fail("something went wrong") assert.Equal(t, expectedStdout[1:], stdout.String()) - assert.Equal(t, -1, exitCode) + assert.Equal(t, 2, exitCode) } func TestFailSubcommand(t *testing.T) { @@ -761,7 +761,7 @@ error: something went wrong require.NoError(t, err) assert.Equal(t, expectedStdout[1:], stdout.String()) - assert.Equal(t, -1, exitCode) + assert.Equal(t, 2, exitCode) } type lengthOf struct {