CMDGEN
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?
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
subcommands foo 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.
Usage
Install the command:
go install github.com/rusq/cmdgen
Run it:
cmdgen -cmd yourmaincmd -var YourMainCmd -pkg github.com/you/yourpackage/cmd/yourmaincmd /path/to/your/project/cmd/yourmaincmd
Command line switches
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
Environment variables
GEN_CMD=foo
GEN_PKG=github.com/you/foo
GEN_VAR=FooCommand
GEN_OUTPUT_DIR=/path/to/your/project/cmd/foo
Tutors
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"
Adding new command
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.
Go Stringer
To generate string versions of status codes, run:
go install golang.org/x/tools/cmd/stringer@latest
go generate ./...