Documentation
¶
Overview ¶
Package ffcli is for building declarative commandline applications.
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 Run. The args passed to // Exec are the args left over after flags parsing. Optional. // // If Exec returns flag.ErrHelp, Run will behave as if -h were passed and // emit the complete usage output. 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.
Example (Then_Run) ¶
package main import ( "context" "flag" "fmt" "log" "github.com/peterbourgon/ff/v2/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.