Documentation
¶
Overview ¶
Package cli provides utilities for building command-line interfaces from wrapped functions.
Overview ¶
The cli package enables you to create command dispatchers that parse command-line arguments and execute wrapped functions. It supports both single-level and multi-level command hierarchies, automatic help text generation, and shell completion.
Basic Usage ¶
Create a simple CLI with commands:
func Deploy(env, service string, version int) error {
fmt.Printf("Deploying %s v%d to %s\n", service, version, env)
return nil
}
func main() {
dispatcher := cli.NewStringArgsDispatcher("myapp")
dispatcher.MustAddCommand("deploy", "Deploy a service",
function.MustReflectWrapper("deploy", Deploy))
err := dispatcher.DispatchCombinedCommandAndArgs(context.Background(), os.Args[1:])
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
Usage:
$ myapp deploy production api-server 42 Deploying api-server v42 to production
Multi-level Commands ¶
Create nested command hierarchies:
dispatcher := cli.NewSuperStringArgsDispatcher("myapp")
// Add user commands
userCmd := dispatcher.MustAddSuperCommand("user")
userCmd.MustAddCommand("create", "Create a new user",
function.MustReflectWrapper("CreateUser", CreateUser))
userCmd.MustAddCommand("delete", "Delete a user",
function.MustReflectWrapper("DeleteUser", DeleteUser))
// Add db commands
dbCmd := dispatcher.MustAddSuperCommand("db")
dbCmd.MustAddCommand("migrate", "Run migrations",
function.MustReflectWrapper("Migrate", Migrate))
dispatcher.DispatchCombinedCommandAndArgs(context.Background(), os.Args[1:])
Usage:
$ myapp user create alice alice@example.com $ myapp user delete alice $ myapp db migrate
Default Commands ¶
You can register a default command that runs when no command is specified:
dispatcher.MustAddDefaultCommand("Run the server",
function.MustReflectWrapper("RunServer", RunServer))
Now running the program without arguments will execute the default command:
$ myapp Server started on :8080
Help and Usage ¶
Automatically print available commands:
if len(os.Args) == 1 || os.Args[1] == "help" {
dispatcher.PrintCommandsUsageIntro()
os.Exit(0)
}
This prints formatted help text with command names, argument types, and descriptions.
Shell Completion ¶
Enable shell completion for your CLI:
func main() {
dispatcher := cli.NewStringArgsDispatcher("myapp")
// ... add commands ...
// Enable completion
cli.CompleteStringArgsDispatcher(dispatcher)
// Normal dispatch logic
dispatcher.DispatchCombinedCommandAndArgs(context.Background(), os.Args[1:])
}
Users can then install completion:
$ myapp --install-completion $ myapp de<TAB> # completes to "deploy"
Logging ¶
Track command execution with loggers:
logger := cli.StringArgsCommandLoggerFunc(func(command string, args []string) {
log.Printf("Executing: %s with args %v", command, args)
})
dispatcher := cli.NewStringArgsDispatcher("myapp", logger)
Customization ¶
Customize output colors:
import "github.com/fatih/color" cli.UsageColor = color.New(color.FgGreen) cli.DescriptionColor = color.New(color.FgYellow)
Error Handling ¶
The package provides specific error types for better error handling:
err := dispatcher.Dispatch(ctx, "unknown-command")
if cli.IsErrCommandNotFound(err) {
fmt.Println("Command not found. Available commands:")
dispatcher.PrintCommands()
}
Result Handlers ¶
Process function results before they're displayed:
resultHandler := function.ResultsHandlerFunc(func(results []any) ([]any, error) {
// Transform or validate results
return results, nil
})
dispatcher.MustAddCommand("query", "Query the database",
wrapper, resultHandler)
Best Practices ¶
- Use descriptive command names (verbs like "create", "delete", "list")
- Provide clear descriptions for commands and arguments
- Handle errors gracefully with appropriate exit codes
- Use default commands sparingly (only for single-purpose CLIs)
- Enable shell completion for better user experience
- Log command execution in production applications
Index ¶
- Constants
- Variables
- func CompleteStringArgsDispatcher(disp *StringArgsDispatcher)
- func CompleteSuperStringArgsDispatcher(disp *SuperStringArgsDispatcher)
- func IsErrCommandNotFound(err error) bool
- type ErrCommandNotFound
- type ErrSuperCommandNotFound
- type StringArgsCommandLogger
- type StringArgsCommandLoggerFunc
- type StringArgsDispatcher
- func (disp *StringArgsDispatcher) AddCommand(command, description string, commandFunc function.Wrapper, ...) error
- func (disp *StringArgsDispatcher) AddDefaultCommand(description string, commandFunc function.Wrapper, ...) error
- func (disp *StringArgsDispatcher) Commands() []string
- func (disp *StringArgsDispatcher) Dispatch(ctx context.Context, command string, args ...string) error
- func (disp *StringArgsDispatcher) DispatchCombinedCommandAndArgs(ctx context.Context, commandAndArgs []string) (command string, err error)
- func (disp *StringArgsDispatcher) DispatchDefaultCommand() error
- func (disp *StringArgsDispatcher) HasCommand(command string) bool
- func (disp *StringArgsDispatcher) HasDefaultCommand() bool
- func (disp *StringArgsDispatcher) MustAddCommand(command, description string, commandFunc function.Wrapper, ...)
- func (disp *StringArgsDispatcher) MustAddDefaultCommand(description string, commandFunc function.Wrapper, ...)
- func (disp *StringArgsDispatcher) MustDispatch(ctx context.Context, command string, args ...string)
- func (disp *StringArgsDispatcher) MustDispatchCombinedCommandAndArgs(ctx context.Context, commandAndArgs []string) (command string)
- func (disp *StringArgsDispatcher) MustDispatchDefaultCommand()
- func (disp *StringArgsDispatcher) PrintCommands()
- func (disp *StringArgsDispatcher) PrintCommandsUsageIntro()
- func (disp *StringArgsDispatcher) PrintCompletion(args []string)
- type SuperStringArgsDispatcher
- func (disp *SuperStringArgsDispatcher) AddCommand(command, description string, commandFunc function.Wrapper, ...) error
- func (disp *SuperStringArgsDispatcher) AddDefaultCommand(description string, commandFunc function.Wrapper, ...) error
- func (disp *SuperStringArgsDispatcher) AddSuperCommand(superCommand string) (subDisp *StringArgsDispatcher, err error)
- func (disp *SuperStringArgsDispatcher) Commands() []string
- func (disp *SuperStringArgsDispatcher) Dispatch(ctx context.Context, superCommand, command string, args ...string) error
- func (disp *SuperStringArgsDispatcher) DispatchCombinedCommandAndArgs(ctx context.Context, commandAndArgs []string) (superCommand, command string, err error)
- func (disp *SuperStringArgsDispatcher) DispatchDefaultCommand() error
- func (disp *SuperStringArgsDispatcher) HasCommand(superCommand string) bool
- func (disp *SuperStringArgsDispatcher) HasSubCommand(superCommand, command string) bool
- func (disp *SuperStringArgsDispatcher) MustAddCommand(command, description string, commandFunc function.Wrapper, ...)
- func (disp *SuperStringArgsDispatcher) MustAddDefaultCommand(description string, commandFunc function.Wrapper, ...)
- func (disp *SuperStringArgsDispatcher) MustAddSuperCommand(superCommand string) (subDisp *StringArgsDispatcher)
- func (disp *SuperStringArgsDispatcher) MustDispatch(ctx context.Context, superCommand, command string, args ...string)
- func (disp *SuperStringArgsDispatcher) MustDispatchCombinedCommandAndArgs(ctx context.Context, commandAndArgs []string) (superCommand, command string)
- func (disp *SuperStringArgsDispatcher) MustDispatchDefaultCommand()
- func (disp *SuperStringArgsDispatcher) PrintCommands()
- func (disp *SuperStringArgsDispatcher) PrintCommandsUsageIntro()
- func (disp *SuperStringArgsDispatcher) PrintCompletion(args []string)
- func (disp *SuperStringArgsDispatcher) SubCommands(superCommand string) []string
Constants ¶
const (
DefaultCommand = ""
)
Variables ¶
Functions ¶
func CompleteStringArgsDispatcher ¶
func CompleteStringArgsDispatcher(disp *StringArgsDispatcher)
func CompleteSuperStringArgsDispatcher ¶
func CompleteSuperStringArgsDispatcher(disp *SuperStringArgsDispatcher)
func IsErrCommandNotFound ¶
IsErrCommandNotFound returns true if the passed error can be unwrapped to either ErrCommandNotFound or ErrSuperCommandNotFound.
Types ¶
type ErrCommandNotFound ¶
type ErrCommandNotFound string
func (ErrCommandNotFound) Error ¶
func (e ErrCommandNotFound) Error() string
type ErrSuperCommandNotFound ¶
type ErrSuperCommandNotFound string
func (ErrSuperCommandNotFound) Error ¶
func (e ErrSuperCommandNotFound) Error() string
type StringArgsCommandLogger ¶
StringArgsCommandLogger provides a way to log or track command executions. Implementations can write to log files, send metrics, or perform auditing.
type StringArgsCommandLoggerFunc ¶
StringArgsCommandLoggerFunc is a function type that implements StringArgsCommandLogger. It allows standalone functions to be used as loggers.
func (StringArgsCommandLoggerFunc) LogStringArgsCommand ¶
func (f StringArgsCommandLoggerFunc) LogStringArgsCommand(command string, args []string)
type StringArgsDispatcher ¶
type StringArgsDispatcher struct {
// contains filtered or unexported fields
}
StringArgsDispatcher dispatches CLI commands to wrapped functions. It maintains a registry of commands and their associated functions, handles command-line argument parsing, and executes the appropriate function.
Example:
dispatcher := cli.NewStringArgsDispatcher("myapp")
dispatcher.MustAddCommand("deploy", "Deploy a service", deployWrapper)
dispatcher.DispatchCombinedCommandAndArgs(ctx, os.Args[1:])
func NewStringArgsDispatcher ¶
func NewStringArgsDispatcher(baseCommand string, loggers ...StringArgsCommandLogger) *StringArgsDispatcher
NewStringArgsDispatcher creates a new command dispatcher. The baseCommand is used for help text and completion (typically the program name). Optional loggers are called whenever a command is executed.
Example:
logger := cli.StringArgsCommandLoggerFunc(func(cmd string, args []string) {
log.Printf("Executing: %s %v", cmd, args)
})
dispatcher := cli.NewStringArgsDispatcher("myapp", logger)
func (*StringArgsDispatcher) AddCommand ¶
func (disp *StringArgsDispatcher) AddCommand(command, description string, commandFunc function.Wrapper, resultsHandlers ...function.ResultsHandler) error
AddCommand registers a new command with the dispatcher. Returns an error if the command name is invalid or already registered.
Parameters:
- command: The command name (e.g., "deploy", "create", "delete")
- description: Human-readable description for help text
- commandFunc: The wrapped function to execute
- resultsHandlers: Optional handlers to process function results
Example:
err := dispatcher.AddCommand("deploy", "Deploy a service",
function.MustReflectWrapper("deploy", Deploy))
func (*StringArgsDispatcher) AddDefaultCommand ¶
func (disp *StringArgsDispatcher) AddDefaultCommand(description string, commandFunc function.Wrapper, resultsHandlers ...function.ResultsHandler) error
AddDefaultCommand registers a command that runs when no command is specified. This is useful for single-purpose CLIs or when you want a default action.
Example:
// When user runs just "myapp" with no arguments
dispatcher.AddDefaultCommand("Run the server",
function.MustReflectWrapper("serve", Serve))
func (*StringArgsDispatcher) Commands ¶
func (disp *StringArgsDispatcher) Commands() []string
Commands returns a sorted list of all registered command names.
func (*StringArgsDispatcher) Dispatch ¶
func (disp *StringArgsDispatcher) Dispatch(ctx context.Context, command string, args ...string) error
Dispatch executes the specified command with the given arguments. The context is passed to the wrapped function if it accepts one. Loggers are notified before execution.
Returns ErrCommandNotFound if the command doesn't exist, or any error returned by the wrapped function.
Example:
err := dispatcher.Dispatch(ctx, "deploy", "production", "api-server", "42")
func (*StringArgsDispatcher) DispatchCombinedCommandAndArgs ¶
func (disp *StringArgsDispatcher) DispatchCombinedCommandAndArgs(ctx context.Context, commandAndArgs []string) (command string, err error)
DispatchCombinedCommandAndArgs parses and dispatches from os.Args style input. The first element is treated as the command name, and the rest as arguments. If commandAndArgs is empty, the default command is executed.
This is the typical entry point for CLI applications:
command, err := dispatcher.DispatchCombinedCommandAndArgs(ctx, os.Args[1:])
if err != nil {
fmt.Fprintf(os.Stderr, "Error in %s: %v\n", command, err)
os.Exit(1)
}
func (*StringArgsDispatcher) DispatchDefaultCommand ¶
func (disp *StringArgsDispatcher) DispatchDefaultCommand() error
DispatchDefaultCommand executes the default command with a background context.
func (*StringArgsDispatcher) HasCommand ¶ added in v0.5.0
func (disp *StringArgsDispatcher) HasCommand(command string) bool
HasCommand returns true if a command with the given name is registered.
func (*StringArgsDispatcher) HasDefaultCommand ¶ added in v0.5.0
func (disp *StringArgsDispatcher) HasDefaultCommand() bool
HasDefaultCommand returns true if a default command is registered.
func (*StringArgsDispatcher) MustAddCommand ¶
func (disp *StringArgsDispatcher) MustAddCommand(command, description string, commandFunc function.Wrapper, resultsHandlers ...function.ResultsHandler)
MustAddCommand is like AddCommand but panics on error. Use this in initialization code where command registration failures should be fatal.
func (*StringArgsDispatcher) MustAddDefaultCommand ¶
func (disp *StringArgsDispatcher) MustAddDefaultCommand(description string, commandFunc function.Wrapper, resultsHandlers ...function.ResultsHandler)
MustAddDefaultCommand is like AddDefaultCommand but panics on error.
func (*StringArgsDispatcher) MustDispatch ¶
func (disp *StringArgsDispatcher) MustDispatch(ctx context.Context, command string, args ...string)
MustDispatch is like Dispatch but panics on error.
func (*StringArgsDispatcher) MustDispatchCombinedCommandAndArgs ¶
func (disp *StringArgsDispatcher) MustDispatchCombinedCommandAndArgs(ctx context.Context, commandAndArgs []string) (command string)
MustDispatchCombinedCommandAndArgs is like DispatchCombinedCommandAndArgs but panics on error.
func (*StringArgsDispatcher) MustDispatchDefaultCommand ¶
func (disp *StringArgsDispatcher) MustDispatchDefaultCommand()
MustDispatchDefaultCommand is like DispatchDefaultCommand but panics on error.
func (*StringArgsDispatcher) PrintCommands ¶
func (disp *StringArgsDispatcher) PrintCommands()
PrintCommands prints all registered commands with their descriptions and argument types. Output is colorized using UsageColor and DescriptionColor. This is useful for generating help text.
func (*StringArgsDispatcher) PrintCommandsUsageIntro ¶
func (disp *StringArgsDispatcher) PrintCommandsUsageIntro()
PrintCommandsUsageIntro prints a "Commands:" header followed by all commands. Does nothing if no commands are registered.
func (*StringArgsDispatcher) PrintCompletion ¶ added in v0.5.0
func (disp *StringArgsDispatcher) PrintCompletion(args []string)
PrintCompletion prints commands matching the given prefix for shell completion. This is used internally by the completion system.
type SuperStringArgsDispatcher ¶
type SuperStringArgsDispatcher struct {
// contains filtered or unexported fields
}
func NewSuperStringArgsDispatcher ¶
func NewSuperStringArgsDispatcher(baseCommand string, loggers ...StringArgsCommandLogger) *SuperStringArgsDispatcher
func (*SuperStringArgsDispatcher) AddCommand ¶
func (disp *SuperStringArgsDispatcher) AddCommand(command, description string, commandFunc function.Wrapper, resultsHandlers ...function.ResultsHandler) error
func (*SuperStringArgsDispatcher) AddDefaultCommand ¶
func (disp *SuperStringArgsDispatcher) AddDefaultCommand(description string, commandFunc function.Wrapper, resultsHandlers ...function.ResultsHandler) error
func (*SuperStringArgsDispatcher) AddSuperCommand ¶
func (disp *SuperStringArgsDispatcher) AddSuperCommand(superCommand string) (subDisp *StringArgsDispatcher, err error)
func (*SuperStringArgsDispatcher) Commands ¶
func (disp *SuperStringArgsDispatcher) Commands() []string
func (*SuperStringArgsDispatcher) DispatchCombinedCommandAndArgs ¶
func (*SuperStringArgsDispatcher) DispatchDefaultCommand ¶
func (disp *SuperStringArgsDispatcher) DispatchDefaultCommand() error
func (*SuperStringArgsDispatcher) HasCommand ¶ added in v0.5.0
func (disp *SuperStringArgsDispatcher) HasCommand(superCommand string) bool
func (*SuperStringArgsDispatcher) HasSubCommand ¶
func (disp *SuperStringArgsDispatcher) HasSubCommand(superCommand, command string) bool
func (*SuperStringArgsDispatcher) MustAddCommand ¶
func (disp *SuperStringArgsDispatcher) MustAddCommand(command, description string, commandFunc function.Wrapper, resultsHandlers ...function.ResultsHandler)
func (*SuperStringArgsDispatcher) MustAddDefaultCommand ¶
func (disp *SuperStringArgsDispatcher) MustAddDefaultCommand(description string, commandFunc function.Wrapper, resultsHandlers ...function.ResultsHandler)
func (*SuperStringArgsDispatcher) MustAddSuperCommand ¶
func (disp *SuperStringArgsDispatcher) MustAddSuperCommand(superCommand string) (subDisp *StringArgsDispatcher)
func (*SuperStringArgsDispatcher) MustDispatch ¶
func (disp *SuperStringArgsDispatcher) MustDispatch(ctx context.Context, superCommand, command string, args ...string)
func (*SuperStringArgsDispatcher) MustDispatchCombinedCommandAndArgs ¶
func (disp *SuperStringArgsDispatcher) MustDispatchCombinedCommandAndArgs(ctx context.Context, commandAndArgs []string) (superCommand, command string)
func (*SuperStringArgsDispatcher) MustDispatchDefaultCommand ¶
func (disp *SuperStringArgsDispatcher) MustDispatchDefaultCommand()
func (*SuperStringArgsDispatcher) PrintCommands ¶
func (disp *SuperStringArgsDispatcher) PrintCommands()
func (*SuperStringArgsDispatcher) PrintCommandsUsageIntro ¶
func (disp *SuperStringArgsDispatcher) PrintCommandsUsageIntro()
func (*SuperStringArgsDispatcher) PrintCompletion ¶ added in v0.5.0
func (disp *SuperStringArgsDispatcher) PrintCompletion(args []string)
func (*SuperStringArgsDispatcher) SubCommands ¶
func (disp *SuperStringArgsDispatcher) SubCommands(superCommand string) []string