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.