cli

package
v0.1.0-proto2e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: MPL-2.0 Imports: 26 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNoCommand = errors.New("no command given")

ErrNoCommand is returned when a root is invoked with no subcommand. The contract requires help plus a NON-ZERO exit, and cobra cannot deliver that on its own: a root with no RunE returns flag.ErrHelp from execute(), and ExecuteC catches it, prints help and returns nil, so the process exits 0.

The obvious fix - give the root a RunE that errors - is exactly what GAPI-DIV-057 forbids, because any root RunE restores cobra's pass-through and a mistyped subcommand becomes a positional argument again. So the bare-invocation case is handled OUTSIDE Execute.

Functions

func Execute

func Execute() error

Execute runs the root command. Bare invocation prints help and returns ErrNoCommand so the process exits non-zero (cli-contract.md).

This is where gapictl declares its product, because this is where gapictl's PROCESS begins - package initialization is not that point, since goblinctl runs it too. Set before RunRoot: every control verb resolves config through controlConfig(), which reads the environment namespace and the search path (GAPI-DIV-061).

func GetRoot

func GetRoot() *cobra.Command

GetRoot returns the root command for embedding.

func NewGapidRoot

func NewGapidRoot(start func(*cobra.Command, []string) error) (*cobra.Command, *DaemonFlags, *GapidStartFlags)

NewGapidRoot builds gapid's root here rather than in package main, so a test can construct it. That is not incidental tidiness: GAPI-DIV-058 is closed by comparing each root's persistent set against the shared registrar, and a root declared as a package-level var inside main is unreachable from any test.

The start action is a parameter, so this package still never imports core/supervisor.

func RunRoot

func RunRoot(root *cobra.Command, args []string) error

RunRoot executes root against args, returning ErrNoCommand when no subcommand was named. Callers exit non-zero on any error.

This exists as a function rather than a few lines in main() so the behaviour is testable: main() is not importable, and "bare invocation exits non-zero" is a contract clause that needs a gate.

Types

type ControlFlags

type ControlFlags struct {
	APIAddr     string
	TLSCA       string
	TLSInsecure bool
	LogLevel    string
}

ControlFlags holds the values bound by RegisterControlFlags: which daemon to talk to and how to reach it.

func NewControlRoot

func NewControlRoot(productName, name, version, short string) (*cobra.Command, *ControlFlags)

NewControlRoot builds a control root: no RunE, a version surface, and the persistent control flags. A control binary never starts a daemon, so it gains no start verb here or anywhere.

productName carries the same meaning and the same requirement as on NewDaemonRoot: a control binary resolves the same config file and the same environment namespace as its daemon, so it must agree about which product it is.

func NewGapictlRoot

func NewGapictlRoot() (*cobra.Command, *ControlFlags)

NewGapictlRoot builds a fresh gapictl root, declaring the product. Exported so the parity test can construct one without depending on package initialization order.

The orchestrator embeds this tree through GetRoot(), NOT through this constructor: goblinctl mounting the kernel's verbs under `agent` is not goblinctl becoming gapi.

func RegisterControlFlags

func RegisterControlFlags(cmd *cobra.Command) *ControlFlags

RegisterControlFlags binds the control root's persistent set to cmd.

--api-addr defaults to EMPTY rather than to a literal address: the two daemons listen on different ports, so a shared default would have to be wrong for one of them. Empty means "resolve from config", which keeps config the source of truth and the flag an override.

type DaemonFlags

type DaemonFlags struct {
	ID          string
	LogLevel    string
	LogFormat   string
	LogFile     string
	LogLokiURL  string
	MetricsAddr string
	TLSCA       string
	TLSCert     string
	TLSKey      string
}

DaemonFlags holds the values bound by RegisterDaemonFlags. These are the flags that describe the process itself - who it is, how it reports, and what identity material it serves - so they are persistent and apply to every subcommand.

func NewDaemonRoot

func NewDaemonRoot(productName, name, version, short string, start func(*cobra.Command, []string) error) (*cobra.Command, *DaemonFlags)

NewDaemonRoot builds a daemon root: no RunE, a version surface, the persistent daemon flags, and a `start` subcommand carrying the run action.

The root carries NO RunE, and that is the whole point rather than a stylistic choice. A root RunE makes cobra treat every unmatched argument as a positional parameter and hand it to the daemon, so a mistyped subcommand BOOTS A SUPERVISOR instead of failing (GAPI-DIV-057; goblind reached a 2-minute timeout this way on the word "version").

start is passed in rather than defined here so this package never imports core/supervisor. That keeps the CLI shape importable by a test - and by the orchestrator, which supplies its own start action.

productName is the PRODUCT this daemon belongs to - "gapi", "goblin" - not the binary name. It is a required parameter rather than something the kernel assumes, because every host-namespaced resource the embedded kernel touches derives from it: the environment prefix, /etc/<product>, the agent search paths, the log path, the cgroup names, and the dmesg tag under --pid1 (GAPI-DIV-061). Taking it here is the compile-time half of that guarantee - an embedder cannot build a daemon root without naming itself. core/product.Name()'s panic is the other half, for an embedder that never calls this.

func RegisterDaemonFlags

func RegisterDaemonFlags(cmd *cobra.Command) *DaemonFlags

RegisterDaemonFlags binds the daemon root's persistent set to cmd and returns the struct receiving the values.

On a daemon --tls-ca is SERVER-side material: the CA against which incoming peers are verified, paired with --tls-cert and --tls-key. The control binaries reuse the name for the client's trust root, which is conventional and intended - a later pass that "unifies the TLS flags" across roles would be merging two different things.

type GapidStartFlags

type GapidStartFlags struct {
	ListenAddr    string
	Pid1Mode      bool
	NoEarlyMounts bool
}

GapidStartFlags are local to `gapid start`: they configure a run rather than describing the process, which is what keeps them off the persistent set.

type LocalController

type LocalController struct {
	// contains filtered or unexported fields
}

LocalController implements tui.AgentControl using a local client

func (*LocalController) FetchStatus

func (l *LocalController) FetchStatus(ctx context.Context) ([]tui.AgentStatus, error)

func (*LocalController) GetLogs

func (l *LocalController) GetLogs(ctx context.Context, id string) (<-chan string, error)

func (*LocalController) Lifecycle

func (l *LocalController) Lifecycle(ctx context.Context, id, action string) (bool, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL