Documentation
¶
Overview ¶
Package subcommand provides a SubCommand interface and a SubCommander type that is able to execute a command line application that has multiple subcommands.
The SubCommand type provides methods needed ofr parsing and setting command line arguments and executing code once parsing is complete.
The SubCommander type is a wrapper that handles executing a SubCommand and providing help and error output in the case of errors not related to executing a SubCommand.
The help and error output follow the general form loosely based on Go templates:
{{.ErrorIfAParsingErrorNotAnExecutionError}}
{{if .KnowTheSubCommand}}
{{.SubCommandNameAndDescriptionIfErrHelp}}
usage: {{.SubCommander.CommandName}} {{.AvailableCommandLineArguments}}
{{.AvailableFlagOptionUsageIfThereAreOptions}}
{{.AvailableParameterUsageIfThereAreParameters}}
{{else}}
{{.GlobalOptionUsageIfThereAreGlobalOptions}}
{{.AllSubCommandUsage}}
{{end}}
Please see the examples for actual output.
Example ¶
subCommand := &SubCommandStruct{
NameValue: "sub1",
ExecuteValue: func(ctx context.Context, _ io.Reader, out, _ io.Writer) error {
fs := ctx.Value(0).(*clitest.SimpleFlagSetter)
fmt.Fprintln(out, fs.Int)
return nil
},
}
globalFlags := &clitest.SimpleFlagSetter{}
sc := &SubCommander{
GlobalFlags: globalFlags,
}
sc.Register(subCommand)
ctx := context.WithValue(context.Background(), 0, globalFlags)
err := sc.ExecuteContext(
ctx,
strings.Fields("-int 1234 sub1"),
os.Stdin,
os.Stdout,
os.Stderr,
)
if err != nil {
fmt.Println(err)
}
Output: 1234
Example (ErrorFlagErrHelp) ¶
subCommand1 := &SubCommandStruct{
NameValue: "sub1",
SynopsisValue: "Synopsis for sub1",
}
subCommand2 := &SubCommandStruct{
NameValue: "sub2",
AliasesValue: []string{"alias2.2", "alias2.1"},
SynopsisValue: "Synopsis for sub2",
}
sc := &SubCommander{
CommandName: "example_errorHelp",
GlobalFlags: clitest.NewStringsFlagSetter("value"),
}
sc.Register(subCommand2)
sc.Register(subCommand1)
//We use os.Stdout for outErr so that we can verify output.
sc.ExecuteContext(
context.Background(),
strings.Fields("-h"),
os.Stdin,
os.Stdout,
os.Stdout,
)
Output: usage: example_errorHelp [global_options...] <sub_command> [[global_options | sub_command_options | parameters]...] global_options: -value string value_usage (default "value_default") sub_commands: sub1 Synopsis for sub1 sub2, alias2.1, alias2.2 Synopsis for sub2
Example (ErrorParsingGlobalArguments) ¶
subCommand1 := &SubCommandStruct{
NameValue: "sub1",
SynopsisValue: "Synopsis for sub1",
}
sc := &SubCommander{
CommandName: "example_errorParsingGlobalArguments",
GlobalFlags: clitest.NewStringsFlagSetter("value"),
}
sc.Register(subCommand1)
//We use os.Stdout for outErr so that we can verify output.
sc.ExecuteContext(
context.Background(),
strings.Fields("-foo bar sub1"),
os.Stdin,
os.Stdout,
os.Stdout,
)
Output: flag provided but not defined: -foo usage: example_errorParsingGlobalArguments [global_options...] <sub_command> [[global_options | sub_command_options | parameters]...] global_options: -value string value_usage (default "value_default") sub_commands: sub1 Synopsis for sub1
Example (ErrorParsingSubCommandArguments) ¶
subCommand1 := &SubCommandStruct{
NameValue: "sub1",
SynopsisValue: "Synopsis for sub1",
FlagSetter: clitest.NewStringsFlagSetter("subflag"),
}
sc := &SubCommander{
CommandName: "example_errorParsingSubCommandArguments",
GlobalFlags: clitest.NewStringsFlagSetter("value"),
}
sc.Register(subCommand1)
//We use os.Stdout for outErr so that we can verify output.
sc.ExecuteContext(
context.Background(),
strings.Fields("-value foobar sub1 -foo bar"),
os.Stdin,
os.Stdout,
os.Stdout,
)
Output: flag provided but not defined: -foo usage: ... sub1 [[global_options | sub_command_options]...] global_options: -value string value_usage (default "value_default") sub_command_options: -subflag string subflag_usage (default "subflag_default")
Example (ErrorUnknownSubCommand) ¶
subCommand1 := &SubCommandStruct{
NameValue: "sub1",
SynopsisValue: "Synopsis for sub1",
}
sc := &SubCommander{
CommandName: "example_errorUnknownSubCommand",
GlobalFlags: clitest.NewStringsFlagSetter("value"),
}
sc.Register(subCommand1)
//We use os.Stdout for outErr so that we can verify output.
sc.ExecuteContext(
context.Background(),
strings.Fields("-value foobar sub2"),
os.Stdin,
os.Stdout,
os.Stdout,
)
Output: unknown sub_command "sub2" usage: example_errorUnknownSubCommand [global_options...] <sub_command> [[global_options | sub_command_options | parameters]...] sub_commands: sub1 Synopsis for sub1
Example (HelpSubCommand) ¶
subCommand1 := &SubCommandStruct{
NameValue: "sub1",
SynopsisValue: "Synopsis for sub1",
DescriptionValue: "This is a description.",
ParameterSetter: &clitest.ParameterSetterStruct{
ParameterUsageValue: func() ([]*cli.Parameter, string) {
params := []*cli.Parameter{
&cli.Parameter{
Name: "files",
Many: true,
},
}
return params, FormatParameter(params[0]) + " are the files to process"
},
},
}
sc := &SubCommander{
CommandName: "example_helpSubCommand",
}
sc.RegisterHelp("help", "", "")
sc.Register(subCommand1)
//We use os.Stdout for outErr so that we can verify output.
sc.ExecuteContext(
context.Background(),
strings.Fields("help sub1"),
os.Stdin,
os.Stdout,
os.Stdout,
)
Example (ListSubCommand) ¶
subCommand1 := &SubCommandStruct{
NameValue: "sub1",
SynopsisValue: "Synopsis for sub1",
}
sc := &SubCommander{
CommandName: "example_listSubCommand",
}
sc.RegisterHelp("help", "", "", "h")
sc.RegisterList("list", "", "", "subcommands")
sc.Register(subCommand1)
//We use os.Stdout for outErr so that we can verify output.
sc.ExecuteContext(
context.Background(),
strings.Fields("list"),
os.Stdin,
os.Stdout,
os.Stdout,
)
Output: sub_commands: help, h Prints help information for a sub_command list, subcommands Prints available sub_commands sub1 Synopsis for sub1
Index ¶
- Constants
- Variables
- func IsExecutionError(err error) bool
- type ExecutingSubCommandError
- type ParsingGlobalArgsError
- type ParsingSubCommandError
- type SubCommand
- type SubCommandStruct
- func (scs *SubCommandStruct) Aliases() []string
- func (scs *SubCommandStruct) Description() string
- func (scs *SubCommandStruct) Execute(ctx context.Context, in io.Reader, out, outErr io.Writer) error
- func (scs *SubCommandStruct) Name() string
- func (scs *SubCommandStruct) ParameterUsage() ([]*cli.Parameter, string)
- func (scs *SubCommandStruct) SetFlags(f *flag.FlagSet)
- func (scs *SubCommandStruct) SetParameters(params []string) error
- func (scs *SubCommandStruct) Synopsis() string
- type SubCommander
- func (sc *SubCommander) Execute(args []string) error
- func (sc *SubCommander) ExecuteContext(ctx context.Context, args []string, in io.Reader, out, outErr io.Writer) (err error)
- func (sc *SubCommander) Register(subCommand SubCommand)
- func (sc *SubCommander) RegisterHelp(name, synopsis, description string, aliases ...string)
- func (sc *SubCommander) RegisterList(name, synopsis, description string, aliases ...string)
- type UnknownSubCommandError
Examples ¶
Constants ¶
const ( Usage = cli.Usage GlobalOptionsName = "global_options" SubCommandName = "sub_command" SubCommandsName = "sub_commands" SubCommandOptionsName = "sub_command_options" ParametersName = cli.ParametersName ArgumentSeparator = cli.ArgumentSeparator )
Output values that affect error and help output.
Variables ¶
var ErrUnsuppliedSubCommand = fmt.Errorf("%s not supplied", SubCommandName)
ErrUnsuppliedSubCommand is a value error denoting a sub-command was not supplied during argument parsing. Note that this error message will not be printed to output, it is simply a sentinel value.
var FormatArgument = cli.FormatArgument
FormatArgument formats an argument's name given whether or not it is optional or multiple values are allowed.
This value may be changed to affect the output of this package.
var FormatParameter = cli.FormatParameter
FormatParameter returns a string representation of p appropriate for help and error output.
This value may be changed to affect the output of this package.
var FormatParameterName = cli.FormatParameterName
FormatParameterName returns a string representation of a Parameter name appropriate for help and error output.
This value my be changed to affect the output of this package.
Functions ¶
func IsExecutionError ¶
IsExecutionError returns whether or not err is an ExecutingSubCommandError.
Types ¶
type ExecutingSubCommandError ¶
type ExecutingSubCommandError struct {
Err error
}
ExecutingSubCommandError is an error wrapper denoting that executing a sub-command failed.
func (*ExecutingSubCommandError) Error ¶
func (e *ExecutingSubCommandError) Error() string
Error return e.Err.Error().
type ParsingGlobalArgsError ¶
type ParsingGlobalArgsError struct {
Err error
}
ParsingGlobalArgsError is an error wrapper denoting global argument parsing failed.
func (*ParsingGlobalArgsError) Error ¶
func (e *ParsingGlobalArgsError) Error() string
Error return e.Err.Error().
type ParsingSubCommandError ¶
type ParsingSubCommandError struct {
Err error
}
ParsingSubCommandError is an error wrapper denoting sub-command argument parsing failed.
func (*ParsingSubCommandError) Error ¶
func (e *ParsingSubCommandError) Error() string
Error return e.Err.Error().
type SubCommand ¶
type SubCommand interface {
//Name returns the name of the SubCommand.
//Names must not overlap with other SubCommand Name()s or Aliases() in the
//same SubCommander.
Name() string
//Aliases returns the aliases of the SubCommand.
//These are listed in command help output and will cause a SubCommand to execute
//just as if the SubCommand's name were used from the command line.
//Aliases must not overlap with other SubCommand Name()s or Aliases() in the
//same SubCommander.
Aliases() []string
//Synopsis returns a synopsis of the SubCommand.
//This should be less than one line and is used for command help output.
Synopsis() string
//Description returns a longer description of the SubCommand.
//This can be however long you like and is used for help specific to this
//SubCommand.
Description() string
//FlagSetter for SubCommand flags.
//
//This value may be called multiple times with different values for f if argument
//parsing fails. This is done to obtain possible help and error output.
//If there are no errors during the argument parsing process, then SetFlags
//is only called once. Thus SetFlags should be idempotent and set static
//values on f.
cli.FlagSetter
//ParameterSetter for SubCommand parameters.
cli.ParameterSetter
//Execute is where the SubCommand should do its work.
//A non-nil return value indicates the execution failed and that error will
//be processed by a SubCommander.
//Ctx is the Command's Context provided by the calling code.
//In, out, and outErr are the standard in, out, and err that the SubCommand
//should use.
Execute(ctx context.Context, in io.Reader, out, outErr io.Writer) error
}
SubCommand defines the options for a sub-command to be executed by a SubCommander.
The methods of this interface (except SetParameters and Execute) may be called multiple times to obtain help and error output when needed. These methods should be idempotent.
type SubCommandStruct ¶
type SubCommandStruct struct {
//NameValue is returned from SubCommand's Name() method.
NameValue string
//AliasesValue is returned from SubCommand's Aliases() method.
AliasesValue []string
//SynopsisValue is returned from SubCommand's Synopsis() method.
SynopsisValue string
//DescriptionValue is returned from SubCommand's Description() method.
DescriptionValue string
//FlagSetter is used as the SubCommand's implementation for SetFlags if not nil.
cli.FlagSetter
//ParameterSetter is used as the SubCommand's implementation for ParameterSetter's
//methods if not nil.
cli.ParameterSetter
//ExecuteValue is used as the SubCommand's implementation if not nil.
ExecuteValue func(context.Context, io.Reader, io.Writer, io.Writer) error
}
SubCommandStruct is a struct type implementation of SubCommand where each field represents the value to delegate to in SubCommand methods. Nil interface and func values are not used and the zero values are used for return values if not supplied.
func (*SubCommandStruct) Aliases ¶
func (scs *SubCommandStruct) Aliases() []string
Aliases returns scs.AliasesValue.
func (*SubCommandStruct) Description ¶
func (scs *SubCommandStruct) Description() string
Description returns scs.DescriptionValue.
func (*SubCommandStruct) Execute ¶
func (scs *SubCommandStruct) Execute(ctx context.Context, in io.Reader, out, outErr io.Writer) error
Execute calls and returns the result from scs.ExecuteValue(ctx, out, outErr) if the field is not nil. Otherwise, it returns nil.
func (*SubCommandStruct) Name ¶
func (scs *SubCommandStruct) Name() string
Name returns scs.NameValue.
func (*SubCommandStruct) ParameterUsage ¶
func (scs *SubCommandStruct) ParameterUsage() ([]*cli.Parameter, string)
ParameterUsage delegates to scs.ParameterSetter if the field is not nil. Otherwise, it returns nil and the empty string.
func (*SubCommandStruct) SetFlags ¶
func (scs *SubCommandStruct) SetFlags(f *flag.FlagSet)
SetFlags delegates to scs.FlagSetter if the field is not nil.
func (*SubCommandStruct) SetParameters ¶
func (scs *SubCommandStruct) SetParameters(params []string) error
SetParameters delegates to scs.ParameterSetter if the field is not nil. Otherwise it returns nil.
func (*SubCommandStruct) Synopsis ¶
func (scs *SubCommandStruct) Synopsis() string
Synopsis returns scs.SynopsisValue
type SubCommander ¶
type SubCommander struct {
//CommandName is used in error and help output. It should be the name of the
//program that was invoked.
//Usually os.Args[0].
CommandName string
//GlobalFlags is a FlagSetter that is used for setting global flags for subcommands.
//
//This value may be called multiple times with different values for f if argument
//parsing fails. This is done to obtain possible help and error output.
//If there are no errors during the argument parsing process, then SetFlags
//is only called once. Thus SetFlags should be idempotent and set static
//values on f.
GlobalFlags cli.FlagSetter
//DisallowGlobalFlagsWithSubCommand denotes whether or not global flags may
//be present once the sub-command has been defined in the arguments.
//
//For example, a false value would allow the following arguments:
// ["-global1" "1" "sub-command" "-global2" "2" "-subcommand1" "sc1"]
//while true would not. A true value would require the above ["-global2" "2"]
//to come before "sub-command" in the argument slice.
DisallowGlobalFlagsWithSubCommand bool
// contains filtered or unexported fields
}
SubCommander provides registering multiple SubCommands and executing them from command line arguments.
Note that SubCommander is NOT safe for use with multiple goroutines.
func (*SubCommander) Execute ¶
func (sc *SubCommander) Execute(args []string) error
Execute is syntactic sugar for sc.ExecuteContext() with context.Background(), args, os.Stdin, os.Stdout, and os.Stderr.
func (*SubCommander) ExecuteContext ¶
func (sc *SubCommander) ExecuteContext(ctx context.Context, args []string, in io.Reader, out, outErr io.Writer) (err error)
ExecuteContext executes a SubCommand registered with sc with the provided parameters.
Ctx is the Context passed unaltered to SubCommand.Execute.
Args should be the program arguments excluding the program name - usually os.Args[1:].
The parameters in, out, and outErr are passed unaltered to SubCommand.Execute and should represent the standard input, output, and error files for the executing SubCommand.
Err will be non-nil if parsing args failed - with type *ParsingGlobalArgsError, *ParsingSubCommandError. It will be ErrUnsuppliedSubCommand if the subcommand is not supplied in command It will be of type UnknownSubCommandError if the subcommand name arguments supplied was not found in the registered SubCommands' names or aliases. It will be of type *ExecutingSubCommandError if the SubCommand.Execute method returns an error.
If the returned error is of type *ParsingGlobalArgsError, *ParsingSubCommandError, ErrUnsuppliedSubCommand, or UnknownSubCommandError then error and help output will be written to outErr. See the package documentation for more details on error and help output. If this is the error, then execution stops and SubCommand.Execute is never called.
If the error is an *ExecutingSubCommandError then nothing is output by sc.
func (*SubCommander) Register ¶
func (sc *SubCommander) Register(subCommand SubCommand)
Register registers subCommand to be possibly executed later via its Name() or Aliases(). This will overwrite any previously registered SubCommands with the same Name()s or Aliases().
func (*SubCommander) RegisterHelp ¶
func (sc *SubCommander) RegisterHelp(name, synopsis, description string, aliases ...string)
RegisterHelp registers a help SubCommand that prints out help information about a required sub-command parameter. The SubCommand's name, synopsis, description, and aliases are provided as parameters. If synopsis or description are the empty string, then defaults are used.
func (*SubCommander) RegisterList ¶
func (sc *SubCommander) RegisterList(name, synopsis, description string, aliases ...string)
RegisterList registers a list SubCommand that prints out all available sub-commands when invoked. The SubCommand's name, synopsis, description, and aliases are provided as parameters. If synopsis or description or the empty string, then defaults are used.
type UnknownSubCommandError ¶
type UnknownSubCommandError string
UnknownSubCommandError is an error denoting the provided sub-command is not registered.
func (UnknownSubCommandError) Error ¶
func (e UnknownSubCommandError) Error() string
Error provides the error implementation.