Documentation
¶
Overview ¶
Package cliutil provides a tiny, stdlib-only way to attach structured metadata and sentinels to errors while staying fully composable with the Go standard library. The model is:
Each function builds an entry with New(...) passing an optional trailing cause: return doterr.New(ErrRepo, "key", val, cause) // cause last
With(...) is a flexible convenience for same-function enrichment. It can:
Enrich the rightmost doterr entry within an existing joined error, or
Join a new entry if no doterr entry exists, and
(Optionally) treat a final trailing error as the cause and join it last.
Combine([]error) bundles independent failures into a single error that unwraps to its members, preserving order.
Package cliutil provides output management and synchronized writing for CLI applications.
Index ¶
- Constants
- Variables
- func AddCLIOption(flagDef FlagDef) (err error)
- func AppendErr(errs []error, err error) []error
- func BuildCommandTree() (err error)
- func CallInitializerFuncs(args InitializerArgs) (err error)
- func CombineErrs(errs []error) error
- func ErrValue[T any](err error, key string) (T, bool)
- func Errorf(format string, args ...any)
- func Errors(err error) []error
- func FindErr[T error](err error) (out T, ok bool)
- func Initialize(w Writer) (err error)
- func IsTerminalError(err error) (isTermErr bool)
- func NewErr(parts ...any) error
- func Printf(format string, args ...any)
- func RegisterCommand(cmd Command, parents ...Command) (err error)
- func RegisterInitializerFunc(f InitializerFunc)
- func SetWriter(w Writer)
- func ShowCmdHelp(cmdName string, args UsageArgs) (err error)
- func ShowMainHelp(args UsageArgs) error
- func Stderrf(format string, args ...any)
- func Stdiof(w io.Writer, format string, args ...any)
- func Stdoutf(format string, args ...any)
- func ValidateCmds() (err error)
- func ValidateCommands() (err error)
- func WithErr(parts ...any) error
- type ArgDef
- type CmdArgs
- type CmdBase
- func (c *CmdBase) AddParent(r reflect.Type)
- func (c *CmdBase) AddSubCommand(cmd Command)
- func (c *CmdBase) ArgDefs() []*ArgDef
- func (c *CmdBase) AssignArgs(args []string) (err error)
- func (c *CmdBase) AutoExamples() bool
- func (c *CmdBase) DelegateTo() Command
- func (c *CmdBase) Description() string
- func (c *CmdBase) Examples() []Example
- func (c *CmdBase) FlagName() string
- func (c *CmdBase) FlagSets() []*FlagSet
- func (c *CmdBase) FullNames() (names []string)
- func (c *CmdBase) IsHidden() bool
- func (c *CmdBase) Name() string
- func (c *CmdBase) NoExamples() bool
- func (c *CmdBase) Order() int
- func (c *CmdBase) ParentTypes() []reflect.Type
- func (c *CmdBase) ParseFlagSets(args []string) (remainingArgs []string, err error)
- func (c *CmdBase) SetCommandRunnerArgs(args CmdRunnerArgs)
- func (c *CmdBase) SetDelegateTo(cmd Command)
- func (c *CmdBase) Usage() string
- type CmdRunner
- type CmdRunnerArgs
- type CmdUsage
- type Command
- type CommandHandler
- type Config
- type Example
- type FlagDef
- type FlagRow
- type FlagSet
- func (fs *FlagSet) Assign() (err error)
- func (fs *FlagSet) Build() (err error)
- func (fs *FlagSet) FlagNames() (names []string)
- func (fs *FlagSet) GetUnknownFlags() []string
- func (fs *FlagSet) Parse(args []string) (remainingArgs []string, err error)
- func (fs *FlagSet) ResetUnknownFlags()
- func (fs *FlagSet) Validate() (err error)
- type FlagType
- type GlobalOptions
- type GlobalOptionsArgs
- type GlobalOptionsGetter
- type InitializerArgs
- type InitializerFunc
- type KV
- type NULL
- type Options
- type SubCmdRow
- type TopCmdRow
- type Usage
- type UsageArgs
- type ValidationFunc
- type Verbosity
- type Writer
- type WriterArgs
- type WriterLogger
- func (wl WriterLogger) ErrorError(msg string, args ...any) (err error)
- func (wl WriterLogger) Info(format string, args ...any)
- func (wl WriterLogger) InfoLoud(msg string, args ...any)
- func (wl WriterLogger) InfoPrint(msg string, args ...any)
- func (wl WriterLogger) LogError(msg string, attrs ...any)
- func (wl WriterLogger) Printf(format string, args ...any)
- func (wl WriterLogger) V2() WriterLogger
- func (wl WriterLogger) V3() WriterLogger
- func (wl WriterLogger) WarnError(msg string, args ...any)
- func (wl WriterLogger) WriteErrorf(format string, args ...any)
Constants ¶
const ( ExitSuccess = 0 // Successful execution ExitOptionsParseError = 1 // Command-line option parsing failed ExitConfigLoadError = 2 // Configuration file loading failed ExitConfigParseError = 3 // Configuration parsing/validation failed ExitKnownRuntimeError = 4 // Expected/known runtime error during execution ExitUnknownRuntimeError = 5 // Unexpected/unknown runtime error ExitLoggerSetupError = 6 // Logger initialization failed )
const ( DefaultTimeout = 3 DefaultQuiet = false DefaultDryRun = false DefaultForce = false DefaultVerbosity = int(LowVerbosity) )
Variables ¶
var ( ErrMissingSentinel = errors.New("missing required sentinel error") ErrTrailingKey = errors.New("trailing key without value") ErrMisplacedError = errors.New("error in wrong position") ErrInvalidArgumentType = errors.New("invalid argument type") ErrOddKeyValueCount = errors.New("odd number of key-value arguments") ErrCrossPackageError = errors.New("error from different doterr package") ErrFailedTypeAssertion = errors.New("failed type assertion") )
Sentinel errors for validation failures
var ( ErrShowUsage = fmt.Errorf("run '%s help' for usage", os.Args[0]) ErrUnknownCommand = errors.New("unknown command") ErrCommandNotFound = errors.New("command not found") ErrFlagsParsingFailed = errors.New("flags parsing failed") ErrAssigningArgsFailed = errors.New("assigning args failed") // ErrOmitUserNotify signals that the error has already been displayed to the user // in a user-friendly format, and the technical error message should be omitted // from user output (but can still be logged). ErrOmitUserNotify = errors.New("omit user notification") )
var ( ErrInvalidateVerbosity = errors.New("invalid verbosity level") ErrVerbosityTooLow = errors.New("verbosity too low; must be between 0..3 inclusive") ErrVerbosityTooHigh = errors.New("verbosity too high; must be between 0..3 inclusive") )
var CmdUsageTemplate = template.Must(template.New("cmd_usage").Parse(CmdUsageTemplateText))
var CmdUsageTemplateText string
var ErrCommandRegistrationFailed = errors.New("command registration failed")
var ErrFlagTypeNotDiscoverable = errors.New("flag type is not discoverable")
var UsageTemplate = template.Must(template.New("usage").Parse(UsageTemplateText))
var UsageTemplateText string
Functions ¶
func AddCLIOption ¶ added in v0.2.0
func BuildCommandTree ¶
func BuildCommandTree() (err error)
BuildCommandTree builds the command hierarchy from registrations This should be called by gmover.Initialize() after all init() functions complete
func CallInitializerFuncs ¶
func CallInitializerFuncs(args InitializerArgs) (err error)
func CombineErrs ¶
CombineErrs bundles a slice of errors into a single composite error that unwraps to its members. Order is preserved and nils are skipped. Returns nil for an empty/fully-nil slice, or the sole error when there is exactly one.
func ErrValue ¶
ErrValue extracts a single metadata value by key with type safety. Returns the value and true if found and the value is of type T. Returns the zero value of T and false if not found or type mismatch.
Example:
status, ok := doterr.ErrValue[int](err, "http_status")
if ok {
fmt.Printf("Status: %d\n", status)
}
name, ok := doterr.ErrValue[string](err, "parameter_name")
func Errors ¶
Errors returns the errors stored on a doterr entry. If err is a doterr entry, returns its errors. If err is a joined error (has Unwrap() []error), scans immediate children left-to-right and returns errors from the first doterr entry found. Otherwise returns nil. The returned slice preserves insertion order and is a copy.
Note: These errors may be sentinel errors (e.g., ErrRepo), custom error types (e.g., *rfc9457.Error), or any other error type stored in the entry.
func FindErr ¶
FindErr walks an error tree (including errors.Join trees) and returns the first match for target (via errors.As).
func Initialize ¶
func IsTerminalError ¶
IsTerminalError checks if an error is related to terminal/input operations These errors should abort the entire operation rather than continue
func NewErr ¶
NewErr builds a standalone structured entry (no primary cause inside). Accepted parts:
- error — sentinel/tag (required: at least one, must be first)
- KV{Key,Value} — explicit key/value
- "key", value — implicit pair (value can be any type, including error)
- error — optional trailing cause (joined last via errors.Join)
Pattern: one or more sentinels (error), then zero or more key-value pairs, then optional trailing cause (error). After the first string key, all remaining args must form valid pairs, except for an optional final error. Returns nil if no meaningful parts are provided after validation. Returns a validation error joined with the partial entry if validation fails.
func RegisterCommand ¶
RegisterCommand registers a command with optional parent type declarations First argument is the actual command, remaining arguments are parent type prototypes Example: RegisterCommand(&JobRunCmd{...}, &JobCmd{})
func RegisterInitializerFunc ¶
func RegisterInitializerFunc(f InitializerFunc)
func SetWriter ¶
func SetWriter(w Writer)
SetWriter sets the global writer writer (primarily for testing)
func ShowCmdHelp ¶
ShowCmdHelp displays help for a specific command
func ShowMainHelp ¶
ShowMainHelp displays the main help screen
func ValidateCmds ¶
func ValidateCmds() (err error)
ValidateCmds ensures all registered commands have handlers
func ValidateCommands ¶
func ValidateCommands() (err error)
func WithErr ¶
WithErr is a flexible enrichment helper. Typical uses:
// Enrich an existing composite error (err may be an errors.Join tree):
err = doterr.With(err, "Foo", 10)
// Build an entry and join a trailing cause in one shot:
err = doterr.With("endpoint", ep, ErrTemplate, cause) // 'cause' is last
Behavior:
If the FIRST arg is an error, it is treated as the base error to enrich: • If it is a doterr entry, merge KVs/sentinels into that entry. • If it is a multi-unwrap (errors.Join tree), find the RIGHTMOST doterr entry, merge into it, and rebuild preserving order. • If no doterr entry is found, a new entry will be joined in (see step 3).
After consuming the base (if present), if the LAST remaining arg is an error, it is treated as the CAUSE and joined LAST.
The remaining middle args (if any) are collected into an entry. If we enriched an existing doterr entry in step 1, that merged entry is used; otherwise, a fresh entry is created. If there is a trailing CAUSE from step 2, the result is errors.Join(entry, cause). If there is no cause, the entry is returned.
Note: For inter-function composition, prefer New() with trailing cause:
return doterr.New(ErrRepo, "key", val, cause) // cause last
Types ¶
type ArgDef ¶
type ArgDef struct {
Name string
Usage string
Required bool
Default any
String *string // Where to assign the argument value
Example string // OPTIONAL: sample value for example generation (e.g., "www")
}
ArgDef defines a positional command argument
type CmdArgs ¶
type CmdArgs struct {
Name string
Usage string
Description string
DelegateTo Command
FlagDefs []FlagDef // Legacy flag definitions (will be deprecated)
FlagSets []*FlagSet // New FlagSet-based approach
ArgDefs []*ArgDef // Positional argument definitions
Examples []Example // Custom examples
NoExamples bool // Do not display any examples
AutoExamples bool // Display auto-generated examples even if custom are provided
Order int // Display order in help (0=last, 1+=ordered)
FlagName string // Flag name that triggers this command (e.g., "setup" for --setup)
Hide bool // Hide from help output
}
type CmdBase ¶
type CmdBase struct {
CmdRunnerArgs
// contains filtered or unexported fields
}
CmdBase provides common functionality for all commands It implements the cliutil.Cmd interface
func (*CmdBase) AddSubCommand ¶
AddSubCommand returns the subcommands map
func (*CmdBase) AssignArgs ¶
AssignArgs assigns positional arguments to their defined config fields
func (*CmdBase) AutoExamples ¶
func (*CmdBase) DelegateTo ¶
DelegateTo returns the command to delegate to, if any
func (*CmdBase) Description ¶
Description returns the command description with flag details
func (*CmdBase) NoExamples ¶
func (*CmdBase) ParentTypes ¶
func (*CmdBase) ParseFlagSets ¶
ParseFlagSets parses flags using the new FlagSet-based approach
func (*CmdBase) SetCommandRunnerArgs ¶
func (c *CmdBase) SetCommandRunnerArgs(args CmdRunnerArgs)
func (c *CmdBase) Logger() *slog.Logger {
return c.logger
}
func (c *CmdBase) Writer() Writer {
return c.writer
}
func (*CmdBase) SetDelegateTo ¶
SetDelegateTo sets the command to delegate to
type CmdRunner ¶
type CmdRunner struct {
Args CmdRunnerArgs
}
func NewCmdRunner ¶
func NewCmdRunner(args CmdRunnerArgs) *CmdRunner
type CmdRunnerArgs ¶
type CmdUsage ¶ added in v0.2.0
type CmdUsage struct {
CmdName string
Usage string
Description string
FlagRows []FlagRow
SubCmdRows []SubCmdRow
Examples []Example
}
func BuildCmdUsage ¶ added in v0.2.0
BuildCmdUsage builds the data structure for command-specific help
type Command ¶
type Command interface {
Name() string
FullNames() []string
Usage() string
Description() string
AddSubCommand(Command)
DelegateTo() Command
AddParent(reflect.Type)
ParentTypes() []reflect.Type
FlagSets() []*FlagSet
ParseFlagSets([]string) ([]string, error)
AssignArgs([]string) error
Examples() []Example
NoExamples() bool
AutoExamples() bool
ArgDefs() []*ArgDef
Order() int
SetCommandRunnerArgs(CmdRunnerArgs)
FlagName() string
IsHidden() bool
}
Command interface for basic command metadata and delegation
func GetDefaultCommand ¶
GetDefaultCommand retrieves a command or its default at any depth using dot notation
func GetExactCommand ¶
GetExactCommand retrieves a command at any depth using dot notation
func GetSubCmds ¶
GetSubCmds returns all subcommands for a given path
func GetTopLevelCmds ¶
func GetTopLevelCmds() []Command
GetTopLevelCmds returns all top-level commands sorted by name
func RegisteredCommands ¶ added in v0.2.0
func RegisteredCommands() (cmds []Command)
type CommandHandler ¶
CommandHandler interface for commands that actually execute logic
type FlagDef ¶
type FlagDef struct {
Name string
Shortcut byte
Default any
Usage string
Required bool
Regex *regexp.Regexp
ValidationFunc ValidationFunc
String *string
Bool *bool
Int64 *int64
Int *int
Example string // OPTIONAL: sample value for example generation (e.g., "www")
}
FlagDef defines a command flag declaratively
func (*FlagDef) ValidateValue ¶
ValidateValue validates the flag value using the defined validation rules
type FlagSet ¶
type FlagSet struct {
Name string
FlagSet *flag.FlagSet
FlagDefs []FlagDef
Values map[string]any
// contains filtered or unexported fields
}
FlagSet combines a FlagSet with automatic config binding
func GetGlobalFlagSet ¶ added in v0.3.0
func GetGlobalFlagSet() *FlagSet
func (*FlagSet) GetUnknownFlags ¶ added in v0.2.0
GetUnknownFlags returns the list of flags that were not recognized by this FlagSet
func (*FlagSet) ResetUnknownFlags ¶ added in v0.2.0
func (fs *FlagSet) ResetUnknownFlags()
ResetUnknownFlags clears the list of unknown flags
type GlobalOptions ¶ added in v0.3.0
type GlobalOptions struct {
// contains filtered or unexported fields
}
func GetGlobalOptions ¶ added in v0.3.0
func GetGlobalOptions() *GlobalOptions
func NewGlobalOptions ¶ added in v0.3.0
func NewGlobalOptions(args GlobalOptionsArgs) (*GlobalOptions, error)
NewGlobalOptions creates a new GlobalOptions instance from raw values. This is useful when loading options from configuration files or other sources. Any nil values will use the corresponding defaults.
func ParseGlobalOptions ¶ added in v0.3.0
func ParseGlobalOptions(osArgs []string) (_ *GlobalOptions, _ []string, err error)
ParseGlobalOptions converts raw options into GlobalOptions.
Expects os.Args as input. Strips program name and defaults to ["help"] if no args.
func (*GlobalOptions) DryRun ¶ added in v0.3.0
func (o *GlobalOptions) DryRun() bool
func (*GlobalOptions) Force ¶ added in v0.3.0
func (o *GlobalOptions) Force() bool
func (*GlobalOptions) Options ¶ added in v0.3.0
func (o *GlobalOptions) Options()
func (*GlobalOptions) Quiet ¶ added in v0.3.0
func (o *GlobalOptions) Quiet() bool
func (*GlobalOptions) Timeout ¶ added in v0.3.0
func (o *GlobalOptions) Timeout() time.Duration
func (*GlobalOptions) Verbosity ¶ added in v0.3.0
func (o *GlobalOptions) Verbosity() Verbosity
type GlobalOptionsArgs ¶ added in v0.3.0
type GlobalOptionsGetter ¶ added in v0.3.0
type GlobalOptionsGetter interface {
GlobalOptions() *GlobalOptions
}
type InitializerArgs ¶
type InitializerArgs struct {
Writer Writer
}
type InitializerFunc ¶
type InitializerFunc func(InitializerArgs) error
type KV ¶
KV represents a key/value metadata pair. Keys are preserved in insertion order, and values may be of any type.
func ErrMeta ¶
ErrMeta returns the key/value pairs stored on a doterr entry. If err is a doterr entry, returns its metadata. If err is a joined error (has Unwrap() []error), scans immediate children left-to-right and returns metadata from the first doterr entry found. Otherwise returns nil. The returned slice preserves insertion order and is a copy.
type Usage ¶
type Usage struct {
appinfo.AppInfo
CLIWriter Writer
TopCmdRows []TopCmdRow
GlobalFlags []FlagRow
Examples []Example
}
func BuildUsage ¶
BuildUsage Build the data for the template (auto + optional custom examples)
type ValidationFunc ¶
ValidationFunc validates a flag value and returns an error if invalid
type Writer ¶
type Writer interface {
Printf(string, ...any)
Errorf(string, ...any)
Loud() Writer
V2() Writer
V3() Writer
Writer() io.Writer
ErrWriter() io.Writer
}
Writer defines the interface for user-facing writer
type WriterArgs ¶
type WriterLogger ¶
func NewWriterLogger ¶
func NewWriterLogger(writer Writer, logger *slog.Logger) WriterLogger
func (WriterLogger) ErrorError ¶
func (wl WriterLogger) ErrorError(msg string, args ...any) (err error)
func (WriterLogger) Info ¶
func (wl WriterLogger) Info(format string, args ...any)
func (WriterLogger) InfoLoud ¶
func (wl WriterLogger) InfoLoud(msg string, args ...any)
func (WriterLogger) InfoPrint ¶
func (wl WriterLogger) InfoPrint(msg string, args ...any)
func (WriterLogger) LogError ¶ added in v0.2.1
func (wl WriterLogger) LogError(msg string, attrs ...any)
func (WriterLogger) Printf ¶
func (wl WriterLogger) Printf(format string, args ...any)
func (WriterLogger) V2 ¶
func (wl WriterLogger) V2() WriterLogger
func (WriterLogger) V3 ¶
func (wl WriterLogger) V3() WriterLogger
func (WriterLogger) WarnError ¶
func (wl WriterLogger) WarnError(msg string, args ...any)
func (WriterLogger) WriteErrorf ¶ added in v0.2.1
func (wl WriterLogger) WriteErrorf(format string, args ...any)