An utility to generate command line interface for Go programs.
The template uses the stripped down version of the command processing logic taken from Go command. It is intended to be a lightweight alternative to urfave/cli and cobra.
Why would you want to use this instead of the aforementioned libraries?
- Easily create new subcommands to the main command with unlimited
depth. For example, if your command is
foo
, it can have subcommandsfoo bar
,foo bar baz
, etc. - Centralised configuration storage (package cfg) that can be partitioned by flag mask (see template/internal/cfg/cfg.go).
- Extensibility. As generated files are part of your package you can easily modify them to suit your needs (for example, see slackdump).
- Zero dependencies.
- Lightweight and simple.
Why would you not want to use this package?
- You don't like
flag
package - You fancy those double dash
--flag
arguments. - You don't want to bother with extending it.
- You need something more complex, like binding the environment variables to struct fields.
Install the command:
go install github.com/rusq/cmdgen@latest
Run it:
cmdgen -cmd yourmaincmd -var YourMainCmd -pkg github.com/you/yourpackage/cmd/yourmaincmd /path/to/your/project/cmd/yourmaincmd
Usage: cmdgen <flags> <path>
-cmd name
executable name, i.e. 'foo', if you will run it as './foo help'
-pkg string
Command package name, i.e. 'github.com/you/yourpackage/cmd/slackdump'
-var name
main command variable name, i.e. 'FooCommand', must be exported
GEN_CMD=foo
GEN_PKG=github.com/you/foo
GEN_VAR=FooCommand
GEN_OUTPUT_DIR=/path/to/your/project/cmd/foo
Conventions:
- For simplicity, I'm going to call the package that we're extending "foobar", i.e. "github.com/acme/foobar/cmd/foobar".
- Command name is "foobar"
- Main command variable is "Foobar"
We are going to add a "whambam" subcommand to the "foobar" command, so
that user can run it as foobar whambam
, and when help is printed,
user sees:
Usage: foobar subcommand [flags]
whambam - book some time at WHAMBAM HOTEL
- Create a new directory under the cmd/foobar/internal directory, i.e. cmd/foobar/internal/whambam.
- Create a file named "whambam.go" with the following contents:
package whambam import "github.com/acme/foobar/cmd/foobar/internal/golang/base" var CommandWhamBam = &base.Command{ UsageLine: "foobar whambam [flags]", Short: "sends a web request to book time at Whambam Hotel", PrintFlags: true, Run: runWhambam, } func runWhambam(ctx context.Context, cmd *base.Command, args []string) error { return errors.New("implement me") }
- Add it to the slice of commands at "main.go:21":
//... func init() { base.Foobar.Commands = []*base.Command{ whambam.CommandWhamBam, } } //...
- Save all files, if you haven't done so.
- Run
go run ./cmd/foobar help
and observe that "whambam" is now in the commands list. - Run
go run ./cmd/foobar whambam
to see the error that we carefully planted there.
To generate string versions of status codes, run:
go install golang.org/x/tools/cmd/stringer@latest
go generate ./...