From 9cbd0787b186c3538b1d6e3001b15e9827e3cded Mon Sep 17 00:00:00 2001 From: Shang Jian Ding Date: Fri, 3 Apr 2020 00:13:08 +0000 Subject: [PATCH] flag: exit 0 when -h or -help invoked but undefined flag treats -h or -help as a special case to print a nice help message, but exit with a status code of 2. This update makes that status code 0. Fixes #37533 Change-Id: I7e0bd29944ce46607fb7cfc6740734f7444a151a GitHub-Last-Rev: 83f64d757bc3a9957c49caa5de74d05a96724771 GitHub-Pull-Request: golang/go#37530 Reviewed-on: https://go-review.googlesource.com/c/go/+/221427 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- flag/flag.go | 5 +++- flag/flag_test.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/flag/flag.go b/flag/flag.go index eb88c1f..286bba6 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -308,7 +308,7 @@ type ErrorHandling int // These constants cause FlagSet.Parse to behave as described if the parse fails. const ( ContinueOnError ErrorHandling = iota // Return a descriptive error. - ExitOnError // Call os.Exit(2). + ExitOnError // Call os.Exit(2) or for -h/-help Exit(0). PanicOnError // Call panic with a descriptive error. ) @@ -979,6 +979,9 @@ func (f *FlagSet) Parse(arguments []string) error { case ContinueOnError: return err case ExitOnError: + if err == ErrHelp { + os.Exit(0) + } os.Exit(2) case PanicOnError: panic(err) diff --git a/flag/flag_test.go b/flag/flag_test.go index 0d9491c..a7450f3 100644 --- a/flag/flag_test.go +++ b/flag/flag_test.go @@ -8,9 +8,11 @@ import ( "bytes" . "flag" "fmt" + "internal/testenv" "io" "io/ioutil" "os" + "os/exec" "sort" "strconv" "strings" @@ -544,3 +546,62 @@ func TestRangeError(t *testing.T) { } } } + +func TestExitCode(t *testing.T) { + testenv.MustHaveExec(t) + + magic := 123 + if os.Getenv("GO_CHILD_FLAG") != "" { + fs := NewFlagSet("test", ExitOnError) + if os.Getenv("GO_CHILD_FLAG_HANDLE") != "" { + var b bool + fs.BoolVar(&b, os.Getenv("GO_CHILD_FLAG_HANDLE"), false, "") + } + fs.Parse([]string{os.Getenv("GO_CHILD_FLAG")}) + os.Exit(magic) + } + + tests := []struct { + flag string + flagHandle string + expectExit int + }{ + { + flag: "-h", + expectExit: 0, + }, + { + flag: "-help", + expectExit: 0, + }, + { + flag: "-undefined", + expectExit: 2, + }, + { + flag: "-h", + flagHandle: "h", + expectExit: magic, + }, + { + flag: "-help", + flagHandle: "help", + expectExit: magic, + }, + } + + for _, test := range tests { + cmd := exec.Command(os.Args[0], "-test.run=TestExitCode") + cmd.Env = append( + os.Environ(), + "GO_CHILD_FLAG="+test.flag, + "GO_CHILD_FLAG_HANDLE="+test.flagHandle, + ) + cmd.Run() + got := cmd.ProcessState.ExitCode() + if got != test.expectExit { + t.Errorf("unexpected exit code for test case %+v \n: got %d, expect %d", + test, got, test.expectExit) + } + } +}