cobracmd

package
v0.22.0 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package cobracmd builds a ready-made "install" Cobra command from a cliinstall catalog host id. It is the ONLY place in the cli-install Feature that imports Cobra (cli-install#req:core-framework-neutral) — the root cliinstall package has no command-framework dependency, so a CLI built on something else, or on nothing, can call cliinstall.Probe and cliinstall.Install directly.

Everything this package prints, and every exit code the host process eventually uses, is the host's own decision. The command's RunE never calls os.Exit and never picks a code itself (cli-install#req:host-owned-exit-codes): it returns nil, or whatever CommandOptions.Errors.Failure produced, and the host's own top-level runner is what turns that into a process exit code — exactly the contract selfupdate/cobracmd already establishes for self-update, and this package mirrors it deliberately: two hosts with incompatible exit-code contracts both build a working "install" command from this same adapter.

The formatting and confirmation logic RunE performs lives in the cliui subpackage, which imports neither Cobra nor any other command framework — this package is only the Cobra flag/wiring layer on top of it, kept as the ONE place that logic is implemented so a CLI with no framework at all can reuse it directly instead of re-deriving it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(opts CommandOptions) *cobra.Command

New builds the "install" command for opts.HostID. It registers --all, --yes/-y, --dry-run, --dir and --format text|json.

With no target names, RunE lists the host's relevant targets (--all lists every other catalog entry) and returns — a pure status probe (cli-install#req:list-offline-read-only). With one or more names, RunE first prints, for each target, its description, details, homepage, relevance and planned action — a dry run pass, walked before any confirmation regardless of whether --dry-run itself was given (cli-install#req:details-before-install) — then, unless --dry-run, asks one confirmation covering every target that would actually be installed and installs them (cli-install#req:confirmation-gate, cli-install#req:multi-target-batch). In --format json, the pre- confirmation preview is skipped and interactive prompts move to stderr, so stdout carries exactly one JSON document (cli-install#req:machine-readable-output).

func NewUpgrade added in v0.21.0

func NewUpgrade(opts UpgradeCommandOptions) *cobra.Command

NewUpgrade builds the "upgrade" command for opts.HostID. It registers --all, --check, --yes/-y, --dry-run and --format text|json — no --dir (upgrade always acts on the copy status-probing already located, never a caller-chosen destination) and no aliases beyond opts.Aliases (REQ: update-alias-policy: no "update" alias here, ever).

With no target names and without --all, RunE runs REQ: upgrade-no-args- reports' own bare report: a full plan over the --all target set, printed and exited successfully whenever every lookup succeeded — whether or not an upgrade is available — closing with the next-step line. That report NEVER calls the error mapper's upgrades-available method; only an explicit --check does (cli-install#req:upgrade-check), over whatever target set names/--all select. With one or more names, or --all, and neither --check nor --dry-run, RunE plans, shows the SAME preview (details-before-install) once, confirms, and executes — exactly install's own Plan/confirm/Execute shape, reused here for UpgradeOptions.

Types

type CommandOptions

type CommandOptions struct {
	// Use is the command name, including any argument hint shown in help
	// text. Defaults to "install [name...]".
	Use string
	// Short is the one-line help text. Defaults to a generic description.
	Short string
	// Aliases are additional names the command responds to.
	Aliases []string
	// HostID is the running host's own catalog id
	// (cli-install#req:host-identity-from-catalog). New panics if it is not
	// a valid catalog id — a programming error the host's own tests must
	// catch, never a runtime state a user sees, per that REQ.
	HostID string
	// Errors maps outcomes to the host's own error type. Required for a
	// host that wants distinguishable exit codes; a nil Errors makes every
	// failure return the underlying error unchanged.
	Errors ErrorMapper
	// Interactive reports whether the process is attached to an interactive
	// terminal, used to implement REQ: non-interactive-refusal for the
	// batch confirmation prompt. Passed straight through to
	// cliui.ConfirmOptions.Interactive; nil means that package's own
	// default. Tests should always override this.
	Interactive func() bool
	// HomebrewPrintOnly reports a Homebrew install's command instead of
	// running it, passed straight through to cliinstall.Options
	// (cli-install#req:homebrew-cask-install).
	HomebrewPrintOnly bool
	// ConfigureRelease optionally overrides a target's resolved
	// selfupdate.Config before it is used to resolve or install that
	// target's release — the release-endpoint injection point
	// cli-install#req:no-network-in-tests requires. Nil keeps the
	// catalog's own defaults (the real GitHub API).
	ConfigureRelease func(target cliinstall.Entry, cfg selfupdate.Config) selfupdate.Config
	// Env carries every side-effecting dependency Probe and Install use.
	// Left unset (a zero cliinstall.InstallEnv), New uses
	// cliinstall.DefaultInstallEnv() — the real host. Tests always set
	// this, exactly as cli-install#req:no-network-in-tests requires.
	Env cliinstall.InstallEnv
	// ProbeOptions tunes status-probe concurrency and per-target time
	// budget; the zero value is production-correct (see
	// cliinstall.ProbeOptions).
	ProbeOptions cliinstall.ProbeOptions
}

CommandOptions configures the command New builds. Use and Short default to "install [name...]" and a generic short description when left empty.

type ErrorMapper

type ErrorMapper interface {
	// Failure maps a non-nil command error into the host's own error type:
	// a *UsageError, Plan's own batch-level *selfupdate.Failure (an unknown
	// name), Execute's own batch-level *selfupdate.Failure (no interactive
	// terminal and --yes not given), or a *cliinstall.BatchFailure carrying
	// every failed target's own typed *selfupdate.Failure
	// (cli-install#req:host-owned-exit-codes: "A batch failure MUST expose
	// each target's typed failure" — task-5 review S3). See
	// cliinstall.BatchFailure's own doc comment for the suggested
	// precedence a host applies when it wants one exit code for a batch
	// that failed for more than one reason.
	Failure(err error) error
}

ErrorMapper translates this package's typed outcomes into the host CLI's own error type/exit-code convention, mirroring selfupdate/cobracmd.ErrorMapper's own shape and reasoning exactly: every host MUST map cli-install's three new failure kinds (selfupdate.KindUnknownTarget, KindNoInstallDir, KindDestinationExists) explicitly, never through a self-update default branch (cli-install#req:host-owned-exit-codes).

type UpgradeCommandOptions added in v0.21.0

type UpgradeCommandOptions struct {
	// Use is the command name, including any argument hint shown in help
	// text. Defaults to "upgrade [name...]".
	Use string
	// Short is the one-line help text. Defaults to a generic description.
	Short string
	// Aliases are additional names the command responds to. REQ: update-
	// alias-policy: never pass "update" here.
	Aliases []string
	// HostID is the running host's own catalog id
	// (cli-install#req:host-identity-from-catalog). NewUpgrade panics if it
	// is not a valid catalog id, matching install's own New.
	HostID string
	// Errors maps outcomes to the host's own error type. Implement
	// UpgradeErrorMapper (not just ErrorMapper) to receive the upgrades-
	// available signal cli-install#req:upgrade-check requires; a plain
	// ErrorMapper, or a nil Errors, simply never gets that call.
	Errors ErrorMapper
	// Interactive reports whether the process is attached to an interactive
	// terminal, used to implement REQ: non-interactive-refusal for the
	// batch confirmation prompt. Passed straight through to
	// cliui.ConfirmOptions.Interactive; nil means that package's own
	// default. Tests should always override this.
	Interactive func() bool
	// ConfigureRelease optionally overrides a non-host target's resolved
	// selfupdate.Config before it is used to look up or apply that target's
	// upgrade — the release-endpoint injection point cli-install#req:no-
	// network-in-tests requires. Nil keeps the catalog's own defaults.
	ConfigureRelease func(target cliinstall.Entry, cfg selfupdate.Config) selfupdate.Config
	// Env carries every side-effecting dependency status probing and
	// upgrading use. Left unset (a zero cliinstall.InstallEnv), NewUpgrade
	// uses cliinstall.DefaultInstallEnv() — the real host. Tests always set
	// this.
	Env cliinstall.InstallEnv
	// ProbeOptions tunes status-probe concurrency and per-target time
	// budget; the zero value is production-correct.
	ProbeOptions cliinstall.ProbeOptions

	// HostConfig is the host's OWN self-update selfupdate.Config — built the
	// identical way its `self-update` command builds one, including any
	// manager overrides or extra Managers it adds beyond its catalog entry
	// (cli-install#req:host-target-is-running-binary). Required whenever the
	// host is a candidate target: named explicitly, included under --all, or
	// part of the bare report's own --all set (i.e. essentially always — a
	// host that never wants itself offered has no way to opt out short of
	// naming every OTHER target explicitly and never using --all or the bare
	// report).
	HostConfig selfupdate.Config
	// HostAfterUpdate is the host's own after-update hook — the SAME closure
	// its `self-update` command configures, so `upgrade <self>` runs the
	// identical hook `self-update` does
	// (cli-install#req:self-update-equals-upgrade-self).
	HostAfterUpdate selfupdate.AfterUpdateFunc
	// DetectHost overrides how the host's own install is classified,
	// passed straight through to cliinstall.UpgradeOptions.DetectHost. Nil
	// (the production default) uses opts.HostConfig.DetectSelf, exactly
	// what the host's own `self-update` command calls (cli-install#req:
	// host-target-is-running-binary; task-22 review S1). Tests inject a
	// fake here so they never depend on the real running test binary's own
	// path.
	DetectHost func() (selfupdate.Detection, error)
	// VerifyManaged probes an executable managed target after its manager
	// command completes, passed straight through to cliinstall.
	// UpgradeOptions.VerifyManaged. Nil defaults to
	// selfcliui.VerifyManagedBinary — the SAME verifier the host's own
	// `self-update` command uses, which filters PATH candidates by the
	// detected manager's own markers (task-22 review S2: a bespoke,
	// manager-blind probe could hand AfterUpdate the wrong executable's
	// identity).
	VerifyManaged selfupdate.ManagedBinaryVerifier

	// LookupConcurrency and LookupTimeout tune PlanUpgrade's own release-
	// lookup bounds (cli-install#req:upgrade-release-lookups-bounded); zero
	// keeps cliinstall.UpgradeOptions' own defaults (4, 15s).
	LookupConcurrency int
	LookupTimeout     time.Duration
}

UpgradeCommandOptions configures the command NewUpgrade builds. Use and Short default to "upgrade [name...]" and a generic short description when left empty. There is deliberately no Aliases-based "update" alias field beyond the generic Aliases slice: REQ: update-alias-policy forbids adding one to upgrade at all, so a host that passes []string{"update"} here is making its own policy violation, not this package's.

type UpgradeErrorMapper

type UpgradeErrorMapper interface {
	ErrorMapper
	// UpgradesAvailable is called with every target whose Verdict is
	// selfupdate.UpdateAvailable or selfupdate.Undetermined, mirroring
	// self-update's own UpdateAvailable mapping (cli-install#req:upgrade-
	// check: "Targets that are ahead of latest or skipped as non-release
	// builds MUST NOT count"). Never called for the bare, no-argument
	// report (cli-install#req:upgrade-no-args-reports: "MUST exit
	// successfully... whether or not upgrades are available") — only for an
	// explicit `--check` over named targets or `--all`.
	UpgradesAvailable(results []cliinstall.UpgradeResult) error
}

UpgradeErrorMapper extends ErrorMapper with the method the `upgrade` command's Cobra adapter calls when at least one looked-up target has an update available or an undetermined verdict (cli-install#req:upgrade- check: "the Cobra adapter MUST call the host's error mapper's upgrades-available method"), mirroring how selfupdate/cobracmd. ErrorMapper already has its own UpdateAvailable. Declared here as a SEPARATE interface — not a new method on ErrorMapper itself — precisely so that adding it never breaks a host's existing `install`-only ErrorMapper implementation (task-5 review M15). A host that wires `upgrade` implements both by implementing this one interface; a host that only wires `install` never needs to know it exists.

Results is []cliinstall.UpgradeResult (task-21's real batch-result type, not task-5's own placeholder []cliinstall.Result, which described the unrelated install batch): task-5 deliberately reserved this method's EXISTENCE without settling its final argument type, precisely so this task could land the real shape without an ErrorMapper-breaking rename.

type UsageError

type UsageError struct{ Err error }

UsageError identifies invalid command input before any status probe, confirmation, network request or write begins: an invalid --format value, or --all combined with target names (cli-install#req:host-owned-exit-codes: "pass usage errors (bad flag value, --all with names) through a distinguishable usage error type"). Hosts may use errors.As to distinguish it from a *selfupdate.Failure.

func (*UsageError) Error

func (e *UsageError) Error() string

func (*UsageError) Unwrap

func (e *UsageError) Unwrap() error

Jump to

Keyboard shortcuts

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