Root Command¶
Root Command Architecture¶
Lifecycle Hooks (PersistentPreRunE)¶
Before any subcommand is executed, the root command performs the following automated steps:
- Flag Extraction: Validates and parses the global flags.
- Configuration Loading: Merges embedded assets with local filesystem configuration.
- Logging Setup: Configures the global
props.Loggerlevel and format based on flags and config. - Update Checking: Optionally performs a background check for newer versions (unless
--ciis set or the check was done in the last 24 hours).
Signal Handling¶
root.Execute runs the command tree with a signal-aware execution context: it derives a cancellable context watching os.Interrupt (SIGINT/Ctrl-C) and syscall.SIGTERM, and passes it to Cobra via ExecuteContext, so every command's cmd.Context() is cancelled on interruption.
The lifecycle mirrors kubectl/docker:
- First signal — cancels
cmd.Context(). Long-running commands observingctx.Done()unwind gracefully; the deferred telemetry flush still runs (on a bounded background context, so cancellation cannot abort the flush itself). - Second signal — force-exits immediately, so a hung cleanup can never trap the user.
- Exit code — a signal-terminated run exits
128 + signum(130for SIGINT,143for SIGTERM), threaded through theErrorHandler's exit path viaerrorhandling.WithExitCodeso it never conflicts with normal error exits.
An interrupt is a deliberate user choice, not a failure, so the interrupted by signal: … notice is logged at debug, not error (it routes through errorhandling.LevelFatalQuiet, which exits like LevelFatal but logs at debug). End users see a clean exit with the conventional code; --debug still surfaces the notice. The non-zero exit code is the signal.
On Windows only os.Interrupt is deliverable; the SIGTERM registration is harmless there, so no build tags are needed.
Interactive prompts own Ctrl-C
While a TUI prompt (Huh/Bubble Tea) is active, the terminal is in raw mode, so Ctrl-C arrives as a keystroke — it aborts the current prompt and never raises SIGINT. The outer signal context therefore only acts when no TUI is reading the keyboard. An external kill -INT/kill -TERM still cancels the whole run, which is the desired semantic for supervisors.
Commands should treat cmd.Context() as the single cancellation source:
RunE: func(cmd *cobra.Command, args []string) error {
select {
case <-cmd.Context().Done():
return cmd.Context().Err() // graceful unwind on Ctrl-C / SIGTERM
case result := <-work:
return handle(result)
}
},
Implementation¶
The root command is implemented in cmd/root/root.go and created via the root.NewCmdRoot(props) entry point.
For more information on the dependency injection pattern used here, see the Props Documentation.