Documentation ¶
Overview ¶
Package mainer defines types relevant to command entrypoint implementation. It includes the Stdio struct that abstracts the I/O and working directory of a command, and the Parser struct that implements a simple flag parser with support for struct tags and environment variables-based argument values.
A typical main entrypoint looks like this, where the cmd struct could be implemented in a distinct package so the main package is minimal (just the main function at the end):
type cmd struct { Help bool `flag:"h,help"` Version bool `flag:"v,version"` FooBar string `flag:"foo-bar" env:"FOO_BAR"` } func (c *cmd) Validate() error { // the struct may implement a Validate method, and if it does the // Parser will call it once the flags are stored in the fields. return nil } func (c *cmd) Main(args []string, stdio mainer.Stdio) mainer.ExitCode { // parse the flags, using env var <CMD>_FOO_BAR for the --foo-bar // flag if the flag is not set (where <CMD> defaults to the base name // of the executable, in uppercase and without extension). p := &mainer.Parser{EnvVars: true} if err := p.Parse(args, c); err != nil { fmt.Fprintln(stdio.Stderr, err) return mainer.InvalidArgs } // execute the command... return mainer.Success } func main() { var c cmd os.Exit(int(c.Main(os.Args, mainer.CurrentStdio()))) }
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Mainer ¶
Mainer defines the method to implement for a type that implements a Main entrypoint of a command.
type Parser ¶
type Parser struct { // EnvVars indicates if environment variables are used to read flag values. EnvVars bool // EnvPrefix is the prefix to use in front of each flag's environment // variable name. If it is empty, the name of the program (as read from the // args slice at index 0) is used, all uppercase and with dashes replaced // with underscores. Set it to "-" to disable any prefix. EnvPrefix string }
Parser implements a command-line flags parser that uses struct tags to configure supported flags and returns any error it encounters, without printing anything automatically. It can optionally read flag values from environment variables first, with the command-line flags used to override them.
The struct tag to specify flags is `flag`, while the one to specify environment variables is `env`. See the env/v6 package for full details on struct tags configuration and decoding support: https://github.com/caarlos0/env.
Flag parsing uses the stdlib's flag package internally, and as such shares the same behaviour regarding short and long flags. However, it does support mixing order of flag arguments and non-flag ones.
func (*Parser) Parse ¶
Parse parses args into v, using struct tags to detect flags. Note that the args slice should start with the program name (as is the case for `os.Args`, which is typically used). The tag must be named "flag" and multiple flags may be set for the same field using a comma-separated list.
v must be a pointer to a struct and the flags must be defined on exported fields with one of those types:
- string
- int/int64
- uint/uint64
- float64
- bool
- time.Duration
- a type that directly implements encoding.TextMarshaler/TextUnmarshaler (both interfaces must be satisfied), or a type T that implements those interfaces on *T (a pointer to the type)
- a slice of any of those types
For slices, by default a new value is appended each time the flag is encountered. This behaviour can be altered by adding a "flagSeparator" struct tag to the field, in addition to the "flag" one, e.g.:
type S struct { Name []string `flag:"name" flagSeparator:","` }
This causes the field to be filled with a single flag value being set, and that value is split on the provided separator.
If Parser.EnvVars is true, flag values are initialized from corresponding environment variables first, as defined by the github.com/caarlos0/env/v6 package (which is used for environment parsing).
Flags and arguments can be interspersed, but flag parsing stops if it encounters the "--" value; all subsequent values are treated as arguments.
After parsing, if v implements a Validate method that returns an error, it is called and any non-nil error is returned as error.
If v has a SetArgs([]string) method, it is called with the list of non-flag arguments (a slice of strings) that respects the provided order.
If v has a SetFlags(map[string]bool) method, it is called with the set of flags that were explicitly set by args (a map[string]bool). Note that if a field can be set with multiple flags, the key is canonicalized to the first flag defined on the field.
If v has a SetFlagsCount(map[string]int) method, it is called with the map of flags that were explicitly set by args, and the associated value is the number of times the flag was provided. As for SetFlags, the key is canonicalized to the first flag defined on the field.
Environment variables parsing has no effect on the values reported by SetFlags and SetFlagsCount, only the actual flags parsed from the args.
It panics if v is not a pointer to a struct or if a flag is defined with an unsupported type.
type Stdio ¶
type Stdio struct { // Cwd is the current working directory. Cwd string // Stdin is the standard input reader. Stdin io.Reader // Stdout is the standard output writer. Stdout io.Writer // Stderr is the standard error writer. Stderr io.Writer }
Stdio defines the OS abstraction for standard I/O.
func CurrentStdio ¶
func CurrentStdio() Stdio
CurrentStdio returns the Stdio for the current process. Its Cwd field reflects the working directory at the time of the call.