From 20e3e2233ee19de92a907660d9b4a36f62429eab Mon Sep 17 00:00:00 2001 From: Marco Molteni Date: Tue, 20 Feb 2024 08:09:23 +0100 Subject: [PATCH 1/2] run: preserve the error type from stdlib/flag At the end this is not really needed nor very useful, but I don't think it is counterproductive. --- command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command.go b/command.go index 41b435d..80a262d 100644 --- a/command.go +++ b/command.go @@ -128,7 +128,7 @@ func (c *Command) run(args []string) error { if c.app.errorHandler != nil { return c.app.errorHandler(c.commandPath, err) } - return fmt.Errorf("Error: %s\nSee '%s --help' for usage", err, c.commandPath) + return fmt.Errorf("Error: %w\nSee '%s --help' for usage", err, c.commandPath) } // Help takes precedence From 71389cafb0c173c969ab1902d3d56e30bede37de Mon Sep 17 00:00:00 2001 From: Marco Molteni Date: Tue, 20 Feb 2024 21:48:27 +0100 Subject: [PATCH 2/2] recognize -h as the short form of -help Before this commit: go run . -h Error: flag: help requested See 'foo --help' for usage exit status 1 After this commit: go run . -h foo - bar Available commands: ... Flags: -help Get help on the 'foo' command. exit status 0 --- command.go | 13 ++++---- go.mod | 2 ++ go.sum | 28 +++++++++++++++++ script_test.go | 47 +++++++++++++++++++++++++++++ testdata/help-flags.txt | 67 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 script_test.go create mode 100644 testdata/help-flags.txt diff --git a/command.go b/command.go index 80a262d..85be775 100644 --- a/command.go +++ b/command.go @@ -124,18 +124,19 @@ func (c *Command) run(args []string) error { // Parse flags err := c.parseFlags(args) + + // Help takes precedence + if errors.Is(err, flag.ErrHelp) || c.helpFlag { + c.PrintHelp() + return nil + } + if err != nil { if c.app.errorHandler != nil { return c.app.errorHandler(c.commandPath, err) } return fmt.Errorf("Error: %w\nSee '%s --help' for usage", err, c.commandPath) } - - // Help takes precedence - if c.helpFlag { - c.PrintHelp() - return nil - } } // Do we have an action? diff --git a/go.mod b/go.mod index 2d37390..bdf5ba5 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/leaanthony/clir go 1.12 + +require github.com/rogpeppe/go-internal v1.12.0 // indirect diff --git a/go.sum b/go.sum index e69de29..6b84e68 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,28 @@ +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/script_test.go b/script_test.go new file mode 100644 index 0000000..6720a24 --- /dev/null +++ b/script_test.go @@ -0,0 +1,47 @@ +package clir + +import ( + "fmt" + "os" + "testing" + + "github.com/rogpeppe/go-internal/testscript" +) + +// To understand where testscript comes from and what it does, see: +// - https://github.com/rogpeppe/go-internal/tree/master?tab=readme-ov-file#testscript +// - https://bitfieldconsulting.com/golang/test-scripts +func TestMain(m *testing.M) { + os.Exit(testscript.RunMain(m, map[string]func() int{ + "clir": Main, + })) +} + +func TestScript(t *testing.T) { + testscript.Run(t, testscript.Params{ + Dir: "testdata", + }) +} + +type Flags struct { + Bar int `flag:"bar" description:"How many bars"` +} + +func Main() int { + cli := NewCli("clir", "a clir executable for testscript", "") + flags := &Flags{} + cli.NewSubCommand("foo", "Foo the bar"). + AddFlags(flags). + Action(func() error { return foo(flags) }) + + if err := cli.Run(); err != nil { + fmt.Println("Error:", err) + return 1 + } + return 0 +} + +func foo(flags *Flags) error { + fmt.Println("this is Foo. Flags:", flags) + return nil +} diff --git a/testdata/help-flags.txt b/testdata/help-flags.txt new file mode 100644 index 0000000..4d61342 --- /dev/null +++ b/testdata/help-flags.txt @@ -0,0 +1,67 @@ +# +# no flags: print top-level help text +# +exec clir +cmp stdout top-level-help +! stderr . + +# +# -help flag: print top level help text +# +exec clir -help +cmp stdout top-level-help +! stderr . + +# Introduced by PR #22 +# -h flag: print top level help text +# +exec clir -h +cmp stdout top-level-help +! stderr . + +# +# known subcommand (foo): execute it +# +exec clir foo +cmp stdout foo-output +! stderr . + +# +# -help flag to known subcommand (foo): print specific help +# +exec clir foo -help +cmp stdout foo-help +! stderr . + +# Introduced by PR #22 +# -h flag to known subcommand (foo): print specific help +exec clir foo -h +cmp stdout foo-help +! stderr . + + +-- top-level-help -- +clir - a clir executable for testscript + +Available commands: + + foo Foo the bar + +Flags: + + -help + Get help on the 'clir' command. + +-- foo-output -- +this is Foo. Flags: &{0} +-- foo-help -- +clir - a clir executable for testscript + +clir foo - Foo the bar +Flags: + + -bar int + How many bars + -help + Get help on the 'clir foo' command. +