Documentation
¶
Overview ¶
Package cli provides helpers for building command-line applications with go-service.
This package wraps the command framework used by this module (github.com/cristalhq/acmd) and provides a small layer of conveniences for wiring subcommands using go-service DI (Fx/Dig via the `di` package).
In typical service applications, this package is used together with `go-service-template` and the high-level module bundles from the `module` package.
Entry points ¶
Start with NewApplication to construct an Application and register subcommands via a RegisterFunc. Most applications then call either:
- Application.Run to execute the CLI and return any error, or
- Application.RunCode to execute the CLI and return a process exit code.
Application.RunCode returns os.ExitCodeSuccess on success, returns the requested non-zero shutdown exit code when the DI application shuts down with one, and returns os.ExitCodeFailure for other errors.
Application.Run reads the go-service os.Args variable, sanitizes injected Go test harness flags such as `-test.v` and `-test.run=...`, and then passes the remaining arguments to the command runner.
Subcommands and DI wiring ¶
Subcommands are added via Commander methods:
- Application.AddServer creates a long-running server-style command. It starts the DI app and then blocks until the DI app signals completion, stopping it afterwards.
- Application.AddClient creates a short-lived client-style command. It starts the DI app, then stops it immediately after startup completes.
Each added subcommand returns a *Command, which embeds a `*flag.FlagSet`. Define command-specific flags on that `FlagSet` before execution. The command implementation parses it and wires the parsed flag set into DI so constructors can read parsed values. Command names must be unique across the application.
Environment-derived metadata ¶
The CLI name and version are derived from environment helpers in `env` and exposed via package variables (Name and Version) so they can be reused consistently.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrCommandRegistered = errors.New("command already registered")
ErrCommandRegistered indicates a subcommand name has already been registered on an Application.
var FS = os.NewFS()
FS is the filesystem used by CLI helpers for configuration lookup and reading sources.
It defaults to an *os.FS rooted in the host filesystem (see os.NewFS). Tests may override this variable to control filesystem reads performed during CLI setup.
var Name = env.NewName(FS)
Name is the CLI application name derived from the environment.
The name is resolved via `env.NewName(FS)` and is used by Application.Run to populate the command runner's app metadata (for example help text and descriptions). It is resolved at package initialization; tests or embedders that need to change it after init should assign this variable directly.
var Version = env.NewVersion()
Version is the CLI application version derived from the environment.
The version is resolved via `env.NewVersion()` and is used by Application.Run to populate the command runner's version information. It is resolved at package initialization; tests or embedders that need to change it after init should assign this variable directly.
Functions ¶
This section is empty.
Types ¶
type Application ¶
type Application struct {
// contains filtered or unexported fields
}
Application is a command-line application composed of subcommands.
An Application maintains a set of commands and delegates parsing/execution to the underlying command framework (github.com/cristalhq/acmd).
func NewApplication ¶
func NewApplication(register RegisterFunc) *Application
NewApplication constructs an Application and invokes register to add subcommands.
The returned Application is pre-populated with the current module-level Name and Version values. Those variables are initialized from the environment at package init time and can be assigned directly by tests or embedders that need post-init overrides.
func (*Application) AddClient ¶
func (a *Application) AddClient(name, description string, opts ...Option) *Command
AddClient adds a short-lived client subcommand with DI lifecycle wiring.
The returned *Command embeds a *flag.FlagSet. The flag set is parsed before DI startup and is then provided into the DI container so constructors can consume parsed flag values. Command names must be unique across the application. Duplicate command names panic with an error that wraps ErrCommandRegistered.
Execution semantics:
- parse the command args into the command's FlagSet
- build a DI application with panic recovery, a fresh copy of the provided options, plus the command's module
- start the DI application
- stop the DI application immediately after startup completes
Client commands should perform their main action from an invoked constructor or a lifecycle OnStart hook so the work completes before startup returns and the graph is stopped.
Any start/stop error is wrapped with the subcommand name for easier attribution.
func (*Application) AddServer ¶
func (a *Application) AddServer(name, description string, opts ...Option) *Command
AddServer adds a long-running server subcommand with DI lifecycle wiring.
The returned *Command embeds a *flag.FlagSet. The flag set is parsed before DI startup and is then provided into the DI container so constructors can consume parsed flag values. Command names must be unique across the application. Duplicate command names panic with an error that wraps ErrCommandRegistered.
Execution semantics:
- parse the command args into the command's FlagSet
- build a DI application with panic recovery, a fresh copy of the provided options, plus the command's module and runtime.Module
- start the DI application
- block until the DI application shuts down or ctx is canceled
- stop the DI application
Any start/stop error or non-zero shutdown request is wrapped with the subcommand name for easier attribution.
func (*Application) Run ¶
func (a *Application) Run(ctx context.Context) error
Run executes the application using the configured command set.
Run configures the underlying command runner with:
- app name/description derived from a.name
- version derived from a.version
- sanitized process arguments from the go-service os.Args variable, with Go test harness flags such as "-test.v" removed (see os.SanitizeArgs)
- the provided context
It returns any execution error from the underlying runner or command ExecFunc.
func (*Application) RunCode ¶ added in v2.372.0
func (a *Application) RunCode(ctx context.Context) int
RunCode executes the application and returns the process exit code that represents the result.
RunCode returns os.ExitCodeSuccess when Run succeeds. When Run returns an error, RunCode logs the error and returns either the non-zero shutdown exit code carried by the error or os.ExitCodeFailure.
type Command ¶
Command wraps a *flag.FlagSet and provides DI wiring for CLI subcommands.
The embedded FlagSet is intended to be configured with flags by the caller, then parsed by the subcommand execution path. The `module` method exposes providers for the filesystem/name/version metadata and the command's FlagSet, and enables DI panic recovery.
func NewCommand ¶ added in v2.66.0
NewCommand creates a new CLI Command with the given name.
The returned Command embeds a *flag.FlagSet that you can use to define CLI flags. Application subcommands call flag.FlagSet.Parse before starting DI, and the Command's `module` wires the parsed FlagSet into the DI container so constructors can read flag values.
type Commander ¶
type Commander interface {
// AddServer registers a long-running server-style subcommand.
//
// Command names must be unique across the entire application.
//
// The subcommand:
// - parses command args into the returned `*Command`'s FlagSet,
// - starts a DI application built from opts plus server-specific wiring,
// - blocks until the DI application signals completion,
// - then stops the DI application.
AddServer(name, description string, opts ...Option) *Command
// AddClient registers a short-lived client-style subcommand.
//
// Command names must be unique across the entire application.
//
// The subcommand:
// - parses command args into the returned `*Command`'s FlagSet,
// - starts a DI application built from opts plus client-specific wiring,
// - then stops the DI application immediately after startup completes.
//
// Run the command's main action from an invoked constructor or a lifecycle
// OnStart hook so it completes before startup returns.
AddClient(name, description string, opts ...Option) *Command
}
Commander registers CLI subcommands on an application.
Implementations typically add subcommands that build and run a DI application using go-service's `di` package. The returned *Command embeds a `*flag.FlagSet` so you can define command-specific flags before execution.
type RegisterFunc ¶
type RegisterFunc = func(commander Commander)
RegisterFunc registers subcommands on a Commander.
A RegisterFunc is invoked by NewApplication to populate the application's command set. Implementations typically call commander.AddServer and/or commander.AddClient.