Skip to content

Latest commit

 

History

History
145 lines (109 loc) · 5.55 KB

File metadata and controls

145 lines (109 loc) · 5.55 KB
type Package Documentation
title CoreCLI runtime — lifecycle, signals, daemon mode
description The CLI runtime layer — Init/Main lifecycle, Options, signal handling, execution modes, the Daemon process helper, and exit-code errors
repo core/cli
module dappco.re/go/cli

Runtime — lifecycle, signals, daemon mode

The runtime layer stands up a *core.Core for the process, runs command setup, executes the requested command, and shuts down cleanly. Source: go/pkg/cli/app.go, runtime.go, service.go, daemon.go, daemon_process.go, errors.go, io.go, log.go.

Entry points

cli.Main is the whole main function for a Core binary. It initialises the runtime with framework translations, registers command setups, executes, and exits with the right code:

func main() {
    cli.WithAppName("core")
    cli.Main(
        cli.WithCommands("config", config.AddConfigCommands),
        cli.WithCommands("doctor", doctor.AddDoctorCommands),
    )
}

MainWithLocales is the same with extra translation sources:

locales := []cli.LocaleSource{cli.WithLocales(embeddedLocales, "locales")}
cli.MainWithLocales(locales, doctor.AddDoctorCommands)

Main recovers panics (logs the stack, shuts down, exits via Fatal), sets a banner of AppName + SemVer() on the Core CLI, and honours *ExitError codes from failed execution.

For finer control, the pieces Main composes are public:

r := cli.Init(cli.Options{AppName: "core"})
if !r.OK { panic(r.Error()) }
defer cli.Shutdown()

c := cli.Core()          // the underlying *core.Core
r = cli.Execute()        // parse args and run the matching command
ctx := cli.Context()     // runtime context, cancelled on signal

Run(ctx) and RunWithTimeout(timeout) support long-running service use.

Options

type Options struct {
    AppName     string
    Version     string
    Services    []core.Service // additional services to register
    I18nSources []LocaleSource // additional translation sources

    // OnReload is called when SIGHUP is received (daemon mode).
    // Leave nil to ignore SIGHUP.
    OnReload func() error
}

Init creates the Core instance via the package's own Register(c) service (never core.WithCli(), which would double-register the CLI primitive), then registers a signal service and any extra services.

Versioning

Build-time variables set via ldflags, composed by SemVer() into a SemVer 2.0.0 string:

// go build -ldflags="-X dappco.re/go/cli/pkg/cli.AppVersion=1.2.0 \
//   -X dappco.re/go/cli/pkg/cli.BuildCommit=df94c24 \
//   -X dappco.re/go/cli/pkg/cli.BuildDate=2026-02-06 \
//   -X dappco.re/go/cli/pkg/cli.BuildPreRelease=dev.8"
// SemVer() -> "1.2.0-dev.8+df94c24.2026-02-06"
var AppVersion, BuildCommit, BuildDate, BuildPreRelease

The same values are exposed as actions: cli.version, cli.app_name, cli.build_info (registered in service.go).

Execution modes

daemon.go detects how the process is being run:

mode := cli.DetectMode()
// cli.ModeDaemon      when CORE_DAEMON=1
// cli.ModePipe        when stdout is not a terminal (colours disabled)
// cli.ModeInteractive otherwise

TTY probes: IsTTY(), IsStdinTTY(), IsStderrTTY() (backed by internal/term, a thin wrapper over golang.org/x/term exposing IsTerminal and TerminalSize).

Daemon process helper

daemon_process.go provides a background-process harness with PID file and HTTP health probes:

d := cli.NewDaemon(cli.DaemonOptions{
    PIDFile:    "/var/run/app.pid",
    HealthAddr: ":8090",          // empty string disables the server
    HealthPath: "/healthz",       // liveness
    ReadyPath:  "/readyz",        // readiness
    HealthCheck: func() bool { return true },
})
r := d.Start(ctx)
defer d.Stop(ctx)

StopPIDFile(pidFile, timeout) stops a previously started daemon by its PID file.

Errors and exit codes

errors.go wraps the core error primitives for CLI use:

Function Purpose
Err(format, args...) Failed core.Result from a format string
Wrap(err, msg) Wrap with message; core.Ok(nil) when err is nil
WrapVerb(err, verb, subject) i18n grammar: "Failed to load config: …"
WrapAction(err, verb) i18n grammar: "Failed to connect: …"
Is, As, Join Re-exports of the core error-tree helpers
Exit(code, err) Result carrying an *ExitError
Fatal(failure), Fatalf, FatalWrap, FatalWrapVerb Print and exit

ExitError{Code, Err} is honoured by Main: a failed Execute whose value unwraps to an ExitError exits with that code.

Stream redirection and logging

io.go lets tests and hosts swap the standard streams: SetStdin(r), SetStdout(w), SetStderr(w). log.go forwards to the core logger: LogDebug, LogInfo, LogWarn, LogError, LogSecurity, LogSecurityf.

File map

File Contents
go/pkg/cli/app.go Main, MainWithLocales, WithAppName, WithLocales, SemVer, build vars
go/pkg/cli/runtime.go Init, Options, Core, Execute, Run, Context, Shutdown, signal service
go/pkg/cli/service.go CLI service registration, cli.version / cli.app_name / cli.build_info actions
go/pkg/cli/daemon.go Mode, DetectMode, TTY probes
go/pkg/cli/daemon_process.go Daemon, DaemonOptions, StopPIDFile
go/pkg/cli/errors.go Err, Wrap*, ExitError, Exit, Fatal*
go/pkg/cli/io.go SetStdin, SetStdout, SetStderr
go/pkg/cli/log.go Log* forwarding to the core logger
go/internal/term/term.go IsTerminal, TerminalSize