Documentation
¶
Overview ¶
Package ffcli is for building declarative commandline applications.
See the README at https://github.com/peterbourgon/ff/tree/master/ffcli for more information.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrUnparsed = errors.New("command tree is unparsed, can't run")
ErrUnparsed is returned by Run if Parse hasn't been called first.
Functions ¶
func DefaultUsageFunc ¶
DefaultUsageFunc is the default UsageFunc used for all commands if no custom UsageFunc is provided.
Types ¶
type Command ¶
type Command struct { // Name of the command. Used for sub-command matching, and as a replacement // for Usage, if no Usage string is provided. Required for sub-commands, // optional for the root command. Name string // ShortUsage string for this command. Consumed by the DefaultUsageFunc and // printed at the top of the help output. Recommended but not required. // Should be one line of the form // // cmd [flags] subcmd [flags] <required> [<optional> ...] // // If it's not provided, the DefaultUsageFunc will use Name instead. // Optional, but recommended. ShortUsage string // ShortHelp is printed next to the command name when it appears as a // sub-command, in the help output of its parent command. Optional, but // recommended. ShortHelp string // LongHelp is consumed by the DefaultUsageFunc and printed in the help // output, after ShortUsage and before flags. Typically a paragraph or more // of prose-like text, providing more explicit context and guidance than // what is implied by flags and arguments. Optional. LongHelp string // UsageFunc generates a complete usage output, written to the io.Writer // returned by FlagSet.Output() when the -h flag is passed. The function is // invoked with its corresponding command, and its output should reflect the // command's short usage, short help, and long help strings, subcommands, // and available flags. Optional; if not provided, a suitable, compact // default is used. UsageFunc func(c *Command) string // FlagSet associated with this command. Optional, but if none is provided, // an empty FlagSet will be defined and attached during the parse phase, so // that the -h flag works as expected. FlagSet *flag.FlagSet // Options provided to ff.Parse when parsing arguments for this command. // Optional. Options []ff.Option // Subcommands accessible underneath (i.e. after) this command. Optional. Subcommands []*Command // Exec is invoked if this command has been determined to be the terminal // command selected by the arguments provided to Parse or ParseAndRun. The // args passed to Exec are the args left over after flags parsing. Optional. // // If Exec returns flag.ErrHelp, then Run (or ParseAndRun) will behave as if // -h were passed and emit the complete usage output. // // If Exec is nil, and this command is identified as the terminal command, // then Parse, Run, and ParseAndRun will all return NoExecError. Callers may // check for this error and print e.g. help or usage text to the user, in // effect treating some commands as just collections of subcommands, rather // than being invocable themselves. Exec func(ctx context.Context, args []string) error // contains filtered or unexported fields }
Command combines a main function with a flag.FlagSet, and zero or more sub-commands. A commandline program can be represented as a declarative tree of commands.
func (*Command) Parse ¶
Parse the commandline arguments for this command and all sub-commands recursively, defining flags along the way. If Parse returns without an error, the terminal command has been successfully identified, and may be invoked by calling Run.
If the terminal command identified by Parse doesn't define an Exec function, then Parse will return NoExecError.
Example (Then_Run) ¶
package main import ( "context" "flag" "fmt" "log" "github.com/peterbourgon/ff/v3/ffcli" ) func main() { // Assume our CLI will use some client that requires a token. type FooClient struct { token string } // That client would have a constructor. NewFooClient := func(token string) (*FooClient, error) { if token == "" { return nil, fmt.Errorf("token required") } return &FooClient{token: token}, nil } // We define the token in the root command's FlagSet. var ( rootFlagSet = flag.NewFlagSet("mycommand", flag.ExitOnError) token = rootFlagSet.String("token", "", "API token") ) // Create a placeholder client, initially nil. var client *FooClient // Commands can reference and use it, because by the time their Exec // function is invoked, the client will be constructed. foo := &ffcli.Command{ Name: "foo", Exec: func(context.Context, []string) error { fmt.Printf("subcommand foo can use the client: %v", client) return nil }, } root := &ffcli.Command{ FlagSet: rootFlagSet, Subcommands: []*ffcli.Command{foo}, } // Call Parse first, to populate flags and select a terminal command. if err := root.Parse([]string{"-token", "SECRETKEY", "foo"}); err != nil { log.Fatalf("Parse failure: %v", err) } // After a successful Parse, we can construct a FooClient with the token. var err error client, err = NewFooClient(*token) if err != nil { log.Fatalf("error constructing FooClient: %v", err) } // Then call Run, which will select the foo subcommand and invoke it. if err := root.Run(context.Background()); err != nil { log.Fatalf("Run failure: %v", err) } }
Output: subcommand foo can use the client: &{SECRETKEY}
func (*Command) ParseAndRun ¶
ParseAndRun is a helper function that calls Parse and then Run in a single invocation. It's useful for simple command trees that don't need two-phase setup.
func (*Command) Run ¶
Run selects the terminal command in a command tree previously identified by a successful call to Parse, and calls that command's Exec function with the appropriate subset of commandline args.
If the terminal command previously identified by Parse doesn't define an Exec function, then Run will return NoExecError.
type NoExecError ¶
type NoExecError struct {
Command *Command
}
NoExecError is returned if the terminal command selected during the parse phase doesn't define an Exec function.
func (NoExecError) Error ¶
func (e NoExecError) Error() string
Error implements the error interface.