Documentation ¶
Overview ¶
Package cli defines an SDK for building performant and consistent CLIs. All commands start with a RootCommand which can then accept one or more nested subcommands. Subcommands can also be RootCommand, which creates nested CLIs (e.g. "my-tool do the-thing").
The CLI provides opinionated, formatted help output including flag structure. It also provides a more integrated experience for defining CLI flags, hiding flags, and generating aliases.
To minimize startup times, things are as lazy-loaded as possible. This means commands are instantiated only when needed. Most applications will create a private global variable that returns the root command:
var rootCmd = func() cli.Command { return &cli.RootCommand{ Name: "my-tool", Version: "1.2.3", Commands: map[string]cli.CommandFactory{ "eat": func() cli.Command { return &EatCommand{} }, "sleep": func() cli.Command { return &SleepCommand{} }, }, } }
This CLI could be invoked via:
$ my-tool eat $ my-tool sleep
Deeply-nested RootCommand behave like nested CLIs:
var rootCmd = func() cli.Command { return &cli.RootCommand{ Name: "my-tool", Version: "1.2.3", Commands: map[string]cli.CommandFactory{ "transport": func() cli.Command { return &cli.RootCommand{ Name: "transport", Description: "Subcommands for transportation", Commands: map[string]cli.CommandFactory{ "bus": func() cli.Command { return &BusCommand{} }, "car": func() cli.Command { return &CarCommand{} }, "train": func() cli.Command { return &TrainCommand{} }, }, } }, }, } }
This CLI could be invoked via:
$ my-tool transport bus $ my-tool transport car $ my-tool transport train
Example (AfterParse) ¶
package main import ( "context" "fmt" "os" "github.com/abcxyz/pkg/cli" ) type StreamCommand struct { cli.BaseCommand flagOldAddress string flagAddress string } func (c *StreamCommand) Desc() string { return "Stream a data stream" } func (c *StreamCommand) Help() string { return ` Usage: {{ COMMAND }} [options] Stream a data stream. ` } func (c *StreamCommand) Flags() *cli.FlagSet { set := c.NewFlagSet() f := set.NewSection("SERVER OPTIONS") f.StringVar(&cli.StringVar{ Name: "server-address", Example: "https://my.corp.server:8145", Default: "http://localhost:8145", EnvVar: "CLI_SERVER_ADDRESS", Target: &c.flagAddress, Usage: "Endpoint, including protocol and port, the server.", }) // Deprecated - use -server-address instead. f.StringVar(&cli.StringVar{ Name: "address", Default: "http://localhost:8145", Target: &c.flagOldAddress, Hidden: true, }) // Each AfterParse will be invoked after flags have been parsed. set.AfterParse(func(existingErr error) error { // Example of deferred defaulting. At this point, it is safe to set values // of flags to other values. if c.flagOldAddress != "" { c.Errf("WARNING: -address is deprecated, use -server-address instead") } if c.flagAddress == "" { c.flagAddress = c.flagOldAddress } return nil }) return set } func (c *StreamCommand) Run(ctx context.Context, args []string) error { if err := c.Flags().Parse(args); err != nil { return fmt.Errorf("failed to parse flags: %w", err) } c.Outf("address: %s", c.flagAddress) // TODO: implement return nil } func main() { ctx := context.Background() rootCmd := func() cli.Command { return &cli.RootCommand{ Name: "my-tool", Version: "1.2.3", Commands: map[string]cli.CommandFactory{ "stream": func() cli.Command { return &StreamCommand{} }, }, } } cmd := rootCmd() // Help output is written to stderr by default. Redirect to stdout so the // "Output" assertion works. cmd.SetStderr(os.Stdout) if err := cmd.Run(ctx, []string{"stream", "-address", "1.2.3"}); err != nil { panic(err) } }
Output: WARNING: -address is deprecated, use -server-address instead address: http://localhost:8145
Example (CommandGroup) ¶
package main import ( "context" "fmt" "os" "github.com/abcxyz/pkg/cli" ) type EatCommand struct { cli.BaseCommand } func (c *EatCommand) Desc() string { return "Eat some food" } func (c *EatCommand) Help() string { return ` Usage: {{ COMMAND }} [options] The eat command eats food. ` } func (c *EatCommand) Flags() *cli.FlagSet { return c.NewFlagSet() } func (c *EatCommand) Run(ctx context.Context, args []string) error { if err := c.Flags().Parse(args); err != nil { return fmt.Errorf("failed to parse flags: %w", err) } // TODO: implement return nil } type DrinkCommand struct { cli.BaseCommand } func (c *DrinkCommand) Desc() string { return "Drink some water" } func (c *DrinkCommand) Help() string { return ` Usage: {{ COMMAND }} [options] The drink command drinks water. ` } func (c *DrinkCommand) Flags() *cli.FlagSet { return c.NewFlagSet() } func (c *DrinkCommand) Run(ctx context.Context, args []string) error { if err := c.Flags().Parse(args); err != nil { return fmt.Errorf("failed to parse flags: %w", err) } // TODO: implement return nil } func main() { ctx := context.Background() rootCmd := func() cli.Command { return &cli.RootCommand{ Name: "my-tool", Version: "1.2.3", Commands: map[string]cli.CommandFactory{ "eat": func() cli.Command { return &EatCommand{} }, "drink": func() cli.Command { return &DrinkCommand{} }, }, } } cmd := rootCmd() // Help output is written to stderr by default. Redirect to stdout so the // "Output" assertion works. cmd.SetStderr(os.Stdout) cmd.Outf("\nTop-level help:") if err := cmd.Run(ctx, []string{"-h"}); err != nil { panic(err) } cmd.Outf("\nCommand-level help:") if err := cmd.Run(ctx, []string{"eat", "-h"}); err != nil { panic(err) } }
Output: Top-level help: Usage: my-tool COMMAND drink Drink some water eat Eat some food Command-level help: Usage: my-tool eat [options] The eat command eats food.
Example (CommandWithFlags) ¶
package main import ( "context" "fmt" "os" "strconv" "github.com/abcxyz/pkg/cli" ) type CountCommand struct { cli.BaseCommand flagStep int64 } func (c *CountCommand) Desc() string { return "Counts from 0 up to a number" } func (c *CountCommand) Help() string { return ` Usage: {{ COMMAND }} [options] MAX The count command prints out a list of numbers starting from 0 up to and including the provided MAX. $ {{ COMMAND }} 50 The value for MAX must be a positive integer. ` } func (c *CountCommand) Flags() *cli.FlagSet { set := c.NewFlagSet() f := set.NewSection("NUMBER OPTIONS") f.Int64Var(&cli.Int64Var{ Name: "step", Aliases: []string{"s"}, Example: "1", Default: 1, Target: &c.flagStep, Usage: "Numeric value by which to increment between each number.", }) return set } func (c *CountCommand) Run(ctx context.Context, args []string) error { f := c.Flags() if err := f.Parse(args); err != nil { return fmt.Errorf("failed to parse flags: %w", err) } args = f.Args() if len(args) != 1 { return fmt.Errorf("expected 1 argument, got %q", args) } maxStr := args[0] max, err := strconv.ParseInt(maxStr, 10, 64) if err != nil { return fmt.Errorf("failed to parse max: %w", err) } for i := int64(0); i <= max; i += c.flagStep { c.Outf("%d", i) } return nil } func main() { ctx := context.Background() // Create the command. rootCmd := func() cli.Command { return &cli.RootCommand{ Name: "my-tool", Version: "1.2.3", Commands: map[string]cli.CommandFactory{ "count": func() cli.Command { return &CountCommand{} }, }, } } cmd := rootCmd() // Help output is written to stderr by default. Redirect to stdout so the // "Output" assertion works. cmd.SetStderr(os.Stdout) cmd.Outf("\nUp to 3:") if err := cmd.Run(ctx, []string{"count", "3"}); err != nil { panic(err) } cmd.Outf("\nUp to 10, stepping 2") if err := cmd.Run(ctx, []string{"count", "-step=2", "10"}); err != nil { panic(err) } }
Output: Up to 3: 0 1 2 3 Up to 10, stepping 2 0 2 4 6 8 10
Example (Completions) ¶
package main import ( "context" "strconv" "time" "github.com/posener/complete/v2" "github.com/posener/complete/v2/predict" "github.com/abcxyz/pkg/cli" ) type SingCommand struct { cli.BaseCommand flagSong string flagFade time.Duration flagNow int64 } func (c *SingCommand) Desc() string { return "Sings a song" } func (c *SingCommand) Help() string { return ` Usage: {{ COMMAND }} [options] PATH Sings the given song at the audio file. ` } // PredictArgs is an optional interface which will predict argument values. If // omitted, no arguments are suggested. func (c *SingCommand) PredictArgs() complete.Predictor { return predict.Files("*.mp3") } func (c *SingCommand) Flags() *cli.FlagSet { set := c.NewFlagSet() f := set.NewSection("SONG OPTIONS") f.StringVar(&cli.StringVar{ Name: "song", Aliases: []string{"s"}, Example: "Itsy Bitsy Spider", Target: &c.flagSong, Predict: predict.Set{"Happy Birthday", "Twinkly Twinkle Little Star"}, Usage: "Name of the song to play.", }) f.DurationVar(&cli.DurationVar{ Name: "fade", Example: "5s", Default: 5 * time.Second, Target: &c.flagFade, Predict: predict.Set{"1s", "5s", "10s"}, Usage: "Duration to fade audio tracks.", }) f.Int64Var(&cli.Int64Var{ Name: "now", Example: "10404929", Default: time.Now().Unix(), Target: &c.flagNow, Predict: complete.PredictFunc(func(prefix string) []string { return []string{strconv.FormatInt(time.Now().Unix(), 10)} }), Usage: "Curring timestamp, in unix seconds.", }) return set } func (c *SingCommand) Run(ctx context.Context, args []string) error { return nil } func main() { // The example is above, demonstrating various ways to define completions. To // see even more ways, look at the examples at // github.com/posener/complete/tree/master. // // Since completions are a shell function, users must add something to their // shell configuration (e.g. .bashrc, .zshrc). The easiest method to install // completions is to allow the binary to do it. It will detect the shell and // insert the correct code into the user's shell profile. Instruct users to // run the following command: // // COMP_INSTALL=1 COMP_YES=1 my-cli // // This will automatically install shell completions. To uninstall // completions, instruct users to run: // // COMP_UNINSTALL=1 COMP_YES=1 my-cli // // This will automatically uninstall the completions. // // If users want to install the completions manually, you will need to provide // them shell-specific instructions. The setup usually requires adding the // following lines: // // autoload -U +X bashcompinit && bashcompinit // complete -o nospace -C /full/path/to/my-cli my-cli // // Of note: // // 1. You must use the full filepath to the CLI binary // 2. The argument to the CLI binary is itself }
Output:
Example (PersistentFlags) ¶
package main import ( "context" "fmt" "os" "github.com/abcxyz/pkg/cli" ) // ServerFlags represent the shared flags among all server commands. Embed this // struct into any commands that interact with a server. type ServerFlags struct { flagAddress string flagTLSSkipVerify bool } func (sf *ServerFlags) Register(set *cli.FlagSet) { f := set.NewSection("SERVER OPTIONS") f.StringVar(&cli.StringVar{ Name: "server-address", Example: "https://my.corp.server:8145", Default: "http://localhost:8145", EnvVar: "CLI_SERVER_ADDRESS", Target: &sf.flagAddress, Usage: "Endpoint, including protocol and port, the server.", }) f.BoolVar(&cli.BoolVar{ Name: "insecure", Default: false, EnvVar: "CLI_SERVER_TLS_SKIP_VERIFY", Target: &sf.flagTLSSkipVerify, Usage: "Skip TLS verification. This is bad, please don't do it.", }) } type UploadCommand struct { cli.BaseCommand serverFlags ServerFlags } func (c *UploadCommand) Desc() string { return "Upload a file" } func (c *UploadCommand) Help() string { return ` Usage: {{ COMMAND }} [options] Upload a file to the server. ` } func (c *UploadCommand) Flags() *cli.FlagSet { set := c.NewFlagSet() c.serverFlags.Register(set) return set } func (c *UploadCommand) Run(ctx context.Context, args []string) error { if err := c.Flags().Parse(args); err != nil { return fmt.Errorf("failed to parse flags: %w", err) } _ = c.serverFlags.flagAddress _ = c.serverFlags.flagTLSSkipVerify // TODO: implement return nil } type DownloadCommand struct { cli.BaseCommand serverFlags ServerFlags } func (c *DownloadCommand) Desc() string { return "Download a file" } func (c *DownloadCommand) Help() string { return ` Usage: {{ COMMAND }} [options] Download a file from the server. ` } func (c *DownloadCommand) Flags() *cli.FlagSet { set := c.NewFlagSet() c.serverFlags.Register(set) return set } func (c *DownloadCommand) Run(ctx context.Context, args []string) error { if err := c.Flags().Parse(args); err != nil { return fmt.Errorf("failed to parse flags: %w", err) } _ = c.serverFlags.flagAddress _ = c.serverFlags.flagTLSSkipVerify // TODO: implement return nil } func main() { ctx := context.Background() rootCmd := func() cli.Command { return &cli.RootCommand{ Name: "my-tool", Version: "1.2.3", Commands: map[string]cli.CommandFactory{ "download": func() cli.Command { return &DownloadCommand{} }, "upload": func() cli.Command { return &UploadCommand{} }, }, } } cmd := rootCmd() // Help output is written to stderr by default. Redirect to stdout so the // "Output" assertion works. cmd.SetStderr(os.Stdout) cmd.Outf("\nTop-level help:") if err := cmd.Run(ctx, []string{"-h"}); err != nil { panic(err) } cmd.Outf("\nCommand-level help:") if err := cmd.Run(ctx, []string{"download", "-h"}); err != nil { panic(err) } }
Output: Top-level help: Usage: my-tool COMMAND download Download a file upload Upload a file Command-level help: Usage: my-tool download [options] Download a file from the server. SERVER OPTIONS -insecure Skip TLS verification. This is bad, please don't do it. The default value is "false". This option can also be specified with the CLI_SERVER_TLS_SKIP_VERIFY environment variable. -server-address="https://my.corp.server:8145" Endpoint, including protocol and port, the server. The default value is "http://localhost:8145". This option can also be specified with the CLI_SERVER_ADDRESS environment variable.
Index ¶
- func Flag[T any](f *FlagSection, i *Var[T])
- type AfterParseFunc
- type ArgPredictor
- type BaseCommand
- func (c *BaseCommand) Errf(format string, a ...any)
- func (c *BaseCommand) ExecutablePath() (string, error)
- func (c *BaseCommand) Flags() *FlagSet
- func (c *BaseCommand) GetEnv(key string) string
- func (c *BaseCommand) Hidden() bool
- func (c *BaseCommand) LookupEnv(key string) (string, bool)
- func (c *BaseCommand) NewFlagSet(opts ...Option) *FlagSet
- func (c *BaseCommand) Outf(format string, a ...any)
- func (c *BaseCommand) Pipe() (stdin, stdout, stderr *bytes.Buffer)
- func (c *BaseCommand) Prompt(ctx context.Context, msg string, args ...any) (string, error)
- func (c *BaseCommand) PromptAll(ctx context.Context, msg string, args ...any) (string, error)
- func (c *BaseCommand) PromptTo(ctx context.Context, splitFunc bufio.SplitFunc, msg string, args ...any) (string, error)
- func (c *BaseCommand) SetLookupEnv(fn LookupEnvFunc)
- func (c *BaseCommand) SetStderr(w io.Writer)
- func (c *BaseCommand) SetStdin(r io.Reader)
- func (c *BaseCommand) SetStdout(w io.Writer)
- func (c *BaseCommand) Stderr() io.Writer
- func (c *BaseCommand) Stdin() io.Reader
- func (c *BaseCommand) Stdout() io.Writer
- func (c *BaseCommand) WorkingDir() (string, error)
- type BoolVar
- type Command
- type CommandFactory
- type DurationVar
- type FlagSection
- func (f *FlagSection) BoolVar(i *BoolVar)
- func (f *FlagSection) DurationVar(i *DurationVar)
- func (f *FlagSection) Float64Var(i *Float64Var)
- func (f *FlagSection) Int64Var(i *Int64Var)
- func (f *FlagSection) IntVar(i *IntVar)
- func (f *FlagSection) LogLevelVar(i *LogLevelVar)
- func (f *FlagSection) StringMapVar(i *StringMapVar)
- func (f *FlagSection) StringSliceVar(i *StringSliceVar)
- func (f *FlagSection) StringVar(i *StringVar)
- func (f *FlagSection) TimeVar(layout string, i *TimeVar)
- func (f *FlagSection) Uint64Var(i *Uint64Var)
- func (f *FlagSection) UintVar(i *UintVar)
- type FlagSet
- func (f *FlagSet) AfterParse(fn AfterParseFunc)
- func (f *FlagSet) Arg(i int) string
- func (f *FlagSet) Args() []string
- func (f *FlagSet) GetEnv(k string) string
- func (f *FlagSet) Help() string
- func (f *FlagSet) Lookup(name string) *flag.Flag
- func (f *FlagSet) LookupEnv(k string) (string, bool)
- func (f *FlagSet) NewSection(name string) *FlagSection
- func (f *FlagSet) Parse(args []string) error
- func (f *FlagSet) Parsed() bool
- func (f *FlagSet) Visit(fn func(*flag.Flag))
- func (f *FlagSet) VisitAll(fn func(*flag.Flag))
- type Float64Var
- type Int64Var
- type IntVar
- type LogLevelVar
- type LookupEnvFunc
- type Option
- type ParserFunc
- type PrinterFunc
- type RootCommand
- type SetterFunc
- type StringMapVar
- type StringSliceVar
- type StringVar
- type TimeVar
- type Uint64Var
- type UintVar
- type Value
- type Var
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Flag ¶
func Flag[T any](f *FlagSection, i *Var[T])
Flag is a lower-level API for creating a flag on a flag section. Callers should use this for defining new flags as it sets defaults and provides more granular usage details.
It panics if any of the target, parser, or printer are nil.
Types ¶
type AfterParseFunc ¶ added in v0.6.0
AfterParseFunc is the type signature for functions that are called after flags have been parsed.
type ArgPredictor ¶ added in v0.4.0
type ArgPredictor interface {
PredictArgs() complete.Predictor
}
ArgPredictor is an optional interface that Command can implement to declare predictions for their arguments. By default, commands predict nothing for arguments.
type BaseCommand ¶
type BaseCommand struct {
// contains filtered or unexported fields
}
BaseCommand is the default command structure. All commands should embed this structure.
func (*BaseCommand) Errf ¶ added in v0.4.0
func (c *BaseCommand) Errf(format string, a ...any)
Errf is a shortcut to write to BaseCommand.Stderr.
func (*BaseCommand) ExecutablePath ¶ added in v0.5.0
func (c *BaseCommand) ExecutablePath() (string, error)
ExecutablePath returns the absolute path of the CLI executable binary. All symlinks are resolved to their real values.
func (*BaseCommand) Flags ¶
func (c *BaseCommand) Flags() *FlagSet
Flags returns the base command flags, which is always nil.
func (*BaseCommand) GetEnv ¶ added in v0.6.0
func (c *BaseCommand) GetEnv(key string) string
GetEnv returns the value from the environment at the given key.
func (*BaseCommand) Hidden ¶
func (c *BaseCommand) Hidden() bool
Hidden indicates whether the command is hidden. The default is unhidden.
func (*BaseCommand) LookupEnv ¶ added in v0.6.0
func (c *BaseCommand) LookupEnv(key string) (string, bool)
LookupEnv returns the value from the environment at the given key. The second return value indicates whether the value was set.
func (*BaseCommand) NewFlagSet ¶ added in v0.6.0
func (c *BaseCommand) NewFlagSet(opts ...Option) *FlagSet
NewFlagSet creates a new flag set that inherits properties from the command.
func (*BaseCommand) Outf ¶ added in v0.4.0
func (c *BaseCommand) Outf(format string, a ...any)
Outf is a shortcut to write to BaseCommand.Stdout.
func (*BaseCommand) Pipe ¶
func (c *BaseCommand) Pipe() (stdin, stdout, stderr *bytes.Buffer)
Pipe creates new unqiue stdin, stdout, and stderr buffers, sets them on the command, and returns them. This is most useful for testing where callers want to simulate inputs or assert certain command outputs.
func (*BaseCommand) Prompt ¶
Prompt asks for user input and reads it from [Stdin] until it encounters a newline character. If there's an input stream (e.g. a pipe), it will read the pipe. The result will not include the trailing newline or carriage return. For more information about the conditions under which the prompt is displayed, see [PromptTo].
func (*BaseCommand) PromptAll ¶ added in v0.6.1
PromptAll asks for user input and reads from [Stdin] until it encounters an EOF. If there's an input stream (e.g. a pipe), it will read the pipe. For more information about the conditions under which the prompt is displayed, see [PromptTo].
func (*BaseCommand) PromptTo ¶ added in v0.6.1
func (c *BaseCommand) PromptTo(ctx context.Context, splitFunc bufio.SplitFunc, msg string, args ...any) (string, error)
PromptTo provides a mechanism for asking for user input. It reads from [Stdin], using the provided scanner split function. If there's an input stream (e.g. a pipe), it will read the pipe.
The prompt will be printed to c.Stdout() if any of these cases is true:
- the terminal is a TTY (for real user interaction)
- c.StdIn(), c.Stdout(), and c.Stderr() came from io.Pipe() (for unit-testing back-and-forth dialog)
It will fail if stdin pipe and the terminal is not a tty. If the context is canceled, [Stdin] could be in a partially-read state.
func (*BaseCommand) SetLookupEnv ¶ added in v0.6.0
func (c *BaseCommand) SetLookupEnv(fn LookupEnvFunc)
SetLookupEnv sets the CLIs environment lookup logic to use the provided function.
func (*BaseCommand) SetStderr ¶
func (c *BaseCommand) SetStderr(w io.Writer)
SetStdout sets the standard error.
func (*BaseCommand) SetStdin ¶
func (c *BaseCommand) SetStdin(r io.Reader)
SetStdout sets the standard input.
func (*BaseCommand) SetStdout ¶
func (c *BaseCommand) SetStdout(w io.Writer)
SetStdout sets the standard out.
func (*BaseCommand) Stderr ¶
func (c *BaseCommand) Stderr() io.Writer
Stderr returns the stderr stream.
func (*BaseCommand) Stdout ¶
func (c *BaseCommand) Stdout() io.Writer
Stdout returns the stdout stream.
func (*BaseCommand) WorkingDir ¶ added in v0.5.0
func (c *BaseCommand) WorkingDir() (string, error)
WorkingDir returns the absolute path of current working directory from where the command was started. All symlinks are resolved to their real paths.
type Command ¶
type Command interface { // Desc provides a short, one-line description of the command. It must be // shorter than 50 characters and should not end with a period or punctuation. Desc() string // Help is the long-form help output. It should include usage instructions and // flag information. // // Callers can insert the literal string "{{ COMMAND }}" which will be // replaced with the actual subcommand structure. Help() string // Flags returns the list of flags that are defined on the command. Flags() *FlagSet // Hidden indicates whether the command is hidden from help output. Hidden() bool // Run executes the command. Run(ctx context.Context, args []string) error // Stdout returns the stdout stream. SetStdout sets the stdout stream. Stdout() io.Writer SetStdout(w io.Writer) // Outf is a shortcut to write to [Command.Stdout]. It automatically appends a // trailing newline if one is not present. Outf(format string, a ...any) // Stderr returns the stderr stream. SetStderr sets the stderr stream. Stderr() io.Writer SetStderr(w io.Writer) // Errf is a shortcut to write to [Command.Stderr]. It automatically appends a // trailing newline if one is not present. Errf(format string, a ...any) // Stdin returns the stdin stream. SetStdin sets the stdin stream. Stdin() io.Reader SetStdin(r io.Reader) }
Command is the interface for a command or subcommand. Most of these functions have default implementations on BaseCommand.
type CommandFactory ¶
type CommandFactory func() Command
CommandFactory returns a new instance of a command. This returns a function instead of allocations because we want the CLI to load as fast as possible, so we lazy load as much as possible.
type DurationVar ¶
type FlagSection ¶
type FlagSection struct {
// contains filtered or unexported fields
}
FlagSection represents a group section of flags. The flags are actually "flat" in memory, but maintain a structure for better help output and alias matching.
func (*FlagSection) BoolVar ¶
func (f *FlagSection) BoolVar(i *BoolVar)
BoolVar creates a new boolean variable (true/false). By convention, the default value should always be false. For example:
Bad: -enable-cookies (default: true) Good: -disable-cookies (default: false)
Consider naming your flags to match this convention.
func (*FlagSection) DurationVar ¶
func (f *FlagSection) DurationVar(i *DurationVar)
func (*FlagSection) Float64Var ¶
func (f *FlagSection) Float64Var(i *Float64Var)
func (*FlagSection) Int64Var ¶
func (f *FlagSection) Int64Var(i *Int64Var)
func (*FlagSection) IntVar ¶
func (f *FlagSection) IntVar(i *IntVar)
func (*FlagSection) LogLevelVar ¶ added in v0.7.0
func (f *FlagSection) LogLevelVar(i *LogLevelVar)
func (*FlagSection) StringMapVar ¶
func (f *FlagSection) StringMapVar(i *StringMapVar)
func (*FlagSection) StringSliceVar ¶
func (f *FlagSection) StringSliceVar(i *StringSliceVar)
func (*FlagSection) StringVar ¶
func (f *FlagSection) StringVar(i *StringVar)
func (*FlagSection) TimeVar ¶ added in v0.4.0
func (f *FlagSection) TimeVar(layout string, i *TimeVar)
func (*FlagSection) Uint64Var ¶
func (f *FlagSection) Uint64Var(i *Uint64Var)
func (*FlagSection) UintVar ¶
func (f *FlagSection) UintVar(i *UintVar)
type FlagSet ¶
type FlagSet struct {
// contains filtered or unexported fields
}
FlagSet is the root flag set for creating and managing flag sections.
func (*FlagSet) AfterParse ¶ added in v0.6.0
func (f *FlagSet) AfterParse(fn AfterParseFunc)
AfterParse defines a post-parse function. This can be used to set flag defaults that should not be set until after parsing, such as defaulting flag values to the value of other flags. These functions are called after flags have been parsed by the flag library, but before [Parse] returns.
Example (CheckIfError) ¶
set := NewFlagSet() set.AfterParse(func(existingErr error) error { // Do not run this function if flag parsing or other AfterParse functions // have failed. if existingErr != nil { return nil //nolint:nilerr } // Logic return nil })
Output:
Example (DeferredDefault) ¶
set := NewFlagSet() f := set.NewSection("FLAGS") // This is an old flag that we will remove in the future. We want "-address" // to default to the value of this flag. However, the value of this flag is // not known until after parsing, so we can't set `Default` on the address // flag to this flag, since that's resolved at compile time. Instead, we need // to use the `AfterParse` function to set the defaults. var host string f.StringVar(&StringVar{ Name: "host", Target: &host, Hidden: true, }) var address string f.StringVar(&StringVar{ Name: "address", Target: &address, }) set.AfterParse(func(existingErr error) error { if address == "" { address = host } return nil })
Output:
Example (DeferredDefaultArgs) ¶
set := NewFlagSet() f := set.NewSection("FLAGS") // The default value should be the first argument. Setting this to default to // `os.Args[1]` will not work, because arguments can shift after flag parsing. // Instead, we need to use the `AfterParse` function to set the default. var address string f.StringVar(&StringVar{ Name: "address", Target: &address, }) set.AfterParse(func(existingErr error) error { if address == "" { address = set.Arg(1) } return nil })
Output:
Example (Validation) ¶
set := NewFlagSet() f := set.NewSection("FLAGS") var address string f.StringVar(&StringVar{ Name: "address", Target: &address, }) var protocol string f.StringVar(&StringVar{ Name: "protocol", Target: &protocol, }) set.AfterParse(func(existingErr error) error { var merr error if address == "" { return fmt.Errorf("-address is required") } if address == "" { return fmt.Errorf("-protocol is required") } return merr })
Output:
func (*FlagSet) GetEnv ¶ added in v0.6.0
GetEnv is a convenience function for looking up an environment variable. By default, it is the same as os.GetEnv, but the lookup function can be overridden.
func (*FlagSet) LookupEnv ¶ added in v0.6.0
LookupEnv is a convenience function for looking up an environment variable. By default, it is the same as os.LookupEnv, but the lookup function can be overridden.
func (*FlagSet) NewSection ¶
func (f *FlagSet) NewSection(name string) *FlagSection
NewSection creates a new flag section. By convention, section names should be all capital letters (e.g. "MY SECTION"), but this is not strictly enforced.
type Float64Var ¶
type LogLevelVar ¶ added in v0.7.0
type LookupEnvFunc ¶
LookupEnvFunc is the signature of a function for looking up environment variables. It makes that of os.LookupEnv.
func MapLookuper ¶
func MapLookuper(m map[string]string) LookupEnvFunc
MapLookuper returns a LookupEnvFunc that reads from a map instead of the environment. This is mostly used for testing.
func MultiLookuper ¶ added in v0.6.0
func MultiLookuper(fns ...LookupEnvFunc) LookupEnvFunc
MultiLookuper accepts multiple LookupEnvFunc. It runs them in order on the environment key, returning the first entry that reports found.
type Option ¶
Option is an option to the flagset.
func WithLookupEnv ¶
func WithLookupEnv(fn LookupEnvFunc) Option
WithLookupEnv defines a custom function for looking up environment variables. This is mostly useful for testing.
To bind to a CLI's lookup function:
func (c *CountCommand) Flags() *cli.FlagSet { set := cli.NewFlagSet(cli.WithLookupEnv(c.LookupEnv)) }
Alternatively use BaseCommand.NewFlagSet.
type ParserFunc ¶
ParserFunc is a function that parses a value into T, or returns an error.
type PrinterFunc ¶
PrinterFunc is a function that pretty-prints T.
type RootCommand ¶
type RootCommand struct { BaseCommand // Name is the name of the command or subcommand. For top-level commands, this // should be the binary name. For subcommands, this should be the name of the // subcommand. Name string // Description is the human-friendly description of the command. Description string // Hide marks the entire subcommand as hidden. It will not be shown in help // output. Hide bool // Version defines the version information for the command. This can be // omitted for subcommands as it will be inherited from the parent. Version string // Commands is the list of sub commands. Commands map[string]CommandFactory }
RootCommand represents a command root for a parent or collection of subcommands.
func (*RootCommand) Desc ¶
func (r *RootCommand) Desc() string
Desc is the root command description. It is used to satisfy the Command interface.
func (*RootCommand) Help ¶
func (r *RootCommand) Help() string
Help compiles structured help information. It is used to satisfy the Command interface.
func (*RootCommand) Hidden ¶
func (r *RootCommand) Hidden() bool
Hidden determines whether the command group is hidden. It is used to satisfy the Command interface.
type SetterFunc ¶
type SetterFunc[T any] func(cur *T, val T)
SetterFunc is a function that sets *T to T.
type StringMapVar ¶
type StringSliceVar ¶
type Value ¶
type Value interface { flag.Value // Get returns the value. Even though we know the concrete type with generics, // this returns [any] to match the standard library. Get() any // Aliases returns any defined aliases of the flag. Aliases() []string // Example returns an example input for the flag. For example, if the flag was // accepting a URL, this could be "https://example.com". This is largely meant // as a hint to the CLI user and only affects help output. // // If there is a default value, the example value should be different from the // default value. Example() string // Hidden returns true if the flag is hidden, false otherwise. Hidden() bool // IsBoolFlag returns true if the flag accepts no arguments, false otherwise. IsBoolFlag() bool // Predictor returns a completion predictor. All flags have a default // predictor, but they can be further customized by the developer when // instantiating the flag. Predictor() complete.Predictor }
Value is an extension of flag.Value which adds additional fields for setting examples and defining aliases. All flags with this package must statisfy this interface.
type Var ¶
type Var[T any] struct { Name string Aliases []string Usage string Example string Default T Hidden bool IsBool bool EnvVar string Target *T // Parser and Printer are the generic functions for converting string values // to/from the target value. These are populated by the individual flag // helpers. Parser ParserFunc[T] Printer PrinterFunc[T] // Predict is the completion predictor. If no predictor is defined, it // defaults to predicting something (waiting for a value) for all flags except // boolean flags (which have no value). Callers are encouraged to customize // the predictions. Predict complete.Predictor // Setter defines the function that sets the variable into the target. If nil, // it uses a default setter which overwrites the entire value of the Target. // Implementations that do special processing (such as appending to a slice), // may override this to customize the behavior. Setter SetterFunc[T] }