cliinstall

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: 18 Imported by: 0

Documentation

Overview

Package cliinstall carries the fleet's compiled-in catalog of installable CLIs (cli-install#req:catalog-compiled-in): a stable id per CLI, its release identity in the github.com/strongo/cli-helpers/selfupdate Config shape, its Homebrew cask coordinates, and the host -> target relevance texts a fleet CLI shows when it lists or explains its siblings.

Identity lives here, once

Every per-CLI identity constructor — repository, tag prefix, managers, supported platforms, asset and checksum naming, version-probe arguments — lives in this package as an Entry, never in selfupdate itself (cli-install#req:catalog-identity-single-source). A host builds its own self-update Config from its own Entry.Config, so its self-update and every other host's "install <that cli>" resolve releases identically. This couples a CLI's release naming to a cli-helpers release: a CLI that changes its GoReleaser archive or checksum naming must first update its catalog entry here.

Built on the catalog

cliinstall carries the catalog's data and validates it against recorded snapshots (see the gen subpackage and TestCatalog*), locates and probes installed copies (Probe), plans a destination and install method (Install's own planning, unexported), and performs a direct or Homebrew install. It has no command framework or terminal dependency (cli-install#req:core-framework-neutral); the optional text/JSON writers and Cobra adapter are a later piece of the cli-install Feature, built on top of this package.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IDs

func IDs() []string

IDs returns every catalog id, sorted.

Types

type BatchFailure added in v0.19.0

type BatchFailure struct {
	Failures []*selfupdate.Failure
}

BatchFailure aggregates every failed target's typed *selfupdate.Failure from one batch (see BatchResult.Failure).

It implements Unwrap() []error, so errors.Is/errors.As still work against it exactly as they do against a single *selfupdate.Failure — for example errors.As(err, &batchFailure) or, for one specific kind, errors.As(err, &oneFailure) finds any matching entry. selfupdate.KindOf resolves through errors.As too, so KindOf(batchFailure) reports the FIRST failure's kind for a caller that only wants one classification; a host that wants full precedence should type-assert to *BatchFailure and walk every Failures entry itself.

Suggested precedence for a host that wants ONE exit code for a mixed batch: usage-level treatment (mapping selfupdate.KindUnknownTarget to an invalid-arguments code) applies ONLY when it is the batch's one and only failure kind. A typo named alongside a target that failed for a real operational reason (a checksum mismatch, a permission error, a denied destination) is not "just a usage error" — something real also broke, and folding that into a usage exit code would hide it from a script that branches on exit codes. This package does not enforce the rule; each host's ErrorMapper is where it is applied, as every exit-code decision is (cli-install#req:host-owned-exit-codes).

func (*BatchFailure) Error added in v0.19.0

func (b *BatchFailure) Error() string

Error joins every failure's own message, one per line, so a caller that never inspects Failures individually still gets a complete report.

func (*BatchFailure) Unwrap added in v0.19.0

func (b *BatchFailure) Unwrap() []error

Unwrap exposes every failure to errors.Is/errors.As (and, transitively, selfupdate.KindOf) via Go's multi-error unwrapping.

type BatchResult added in v0.17.0

type BatchResult struct {
	Host    string
	Results []Result
}

BatchResult is the outcome of one batch Install call: the running host's own catalog id and one Result per de-duplicated named target, in the order names first named them (cli-install#req:multi-target-batch).

func Execute added in v0.19.0

func Execute(ctx context.Context, plan BatchResult, opts Options) (BatchResult, error)

Execute installs every still-pending target in plan (Outcome == OutcomeDryRun) — asking at most one confirmation covering all of them (unless opts.Yes), then installing EXACTLY the release, or running EXACTLY the cask command, Plan already resolved: Execute never re-probes a target's status or re-resolves its release (task-5 review B1). Every other Result in plan (already installed, or a failure Plan already decided) passes through unchanged.

Execute always returns a fully populated BatchResult — one Result per target, covering every outcome including a non-interactive confirmation refusal — never an empty one (task-5 review S2: "the JSON one-document rule is broken on refusal"). Its own returned error exists only so a caller that wants one classification can still get it (the confirmation gate's own non-interactive refusal, or another error Confirm itself returned); BatchResult.Failure() is the way to see every target's own typed failure.

func Install added in v0.17.0

func Install(ctx context.Context, names []string, opts Options) (BatchResult, error)

Install is the Plan + confirm + Execute convenience: it plans the whole batch, and — unless opts.DryRun — executes it. `--dry-run` never calls Execute at all, so Plan's own OutcomeDryRun Results are the returned answer unchanged (cli-install#req:install-dry-run). The returned error is non-nil only for a batch-level refusal before any target-specific outcome was decided (an unknown name, per Plan, or the confirmation gate's own non-interactive refusal, per Execute); every other outcome, including every per-target failure, is reported in BatchResult.Results.

func Plan added in v0.19.0

func Plan(ctx context.Context, names []string, opts Options) (BatchResult, error)

Plan validates every name, probes the running host's current status, and resolves an install method, destination (or cask) and — for a direct install that is not already installed — the EXACT release to install, once per target (cli-install#req:install-dry-run, cli-install#req:direct-release-install). It asks no confirmation, downloads nothing, runs no manager command, and creates no directory: Plan alone is `--dry-run`'s complete answer, and it is the SAME plan Execute later installs from — the version, tag and asset URL a caller shows before confirming are never re-resolved a second time (task-5 review B1).

Every name in names MUST be a valid catalog id before ANY target is probed or looked up (cli-install#req:unknown-target-refused: "MUST fail before any confirmation, network request or write" — task-5 review S1): one misspelled name in a batch refuses the WHOLE batch immediately, so a typo never half-installs the targets that were spelled correctly. That case is reported as the returned error (every unknown name, and the valid ids); BatchResult carries no Results, since nothing was probed. Every other outcome — including every per-target failure — is reported only in BatchResult.Results, never as a returned error.

func (BatchResult) Failed added in v0.17.0

func (b BatchResult) Failed() bool

Failed reports whether at least one Result in b has OutcomeFailed (cli-install#req:multi-target-batch: "the command fails when at least one target failed"). A host's Cobra adapter uses this, together with each failed Result's typed Failure, to decide its own exit code.

func (BatchResult) Failure added in v0.19.0

func (b BatchResult) Failure() error

Failure returns nil when b did not fail, and otherwise a *BatchFailure carrying EVERY failed target's typed *selfupdate.Failure, in Results' own order (cli-install#req:host-owned-exit-codes: "A batch failure MUST expose each target's typed failure" — task-5 review S3, which found a mapper that only ever saw the FIRST failed target). A host's ErrorMapper receives this single error and decides its own exit code from it — see BatchFailure's own doc comment for the suggested precedence rule.

type Entry

type Entry struct {
	// ID is the catalog id, equal to the binary name
	// (cli-install#req:host-identity-from-catalog).
	ID string
	// Homepage is the CLI's canonical homepage URL.
	Homepage string
	// Description is a one-line description shown in a listing row.
	Description string
	// Details is a longer description of at most a few short paragraphs,
	// shown before a confirmation prompt
	// (cli-install#req:details-before-install).
	Details string

	// Repository is "owner/repo" on GitHub that publishes this CLI's
	// releases — see selfupdate.Config.Repository.
	Repository string
	// TagPrefix selects this binary's releases within Repository when that
	// repository publishes more than one product's releases — see
	// selfupdate.Config.TagPrefix.
	TagPrefix string
	// Managers are the package managers that might own this binary's
	// install, exactly as this CLI's own self-update declares them — see
	// selfupdate.Config.Managers.
	Managers []selfupdate.Manager
	// SupportedPlatforms restricts install and self-replace to the
	// GOOS/GOARCH pairs this CLI's release actually publishes — see
	// selfupdate.Config.SupportedPlatforms.
	SupportedPlatforms []selfupdate.Platform
	// VersionProbeArgs are the arguments run against a newly installed copy
	// to confirm its version. A zero value leaves selfupdate.Config's own
	// default ({"--version"}) in effect.
	VersionProbeArgs []string
	// UndeterminedVersions lists the CurrentVersion values that mean "this
	// build cannot say its own version". A zero value leaves
	// selfupdate.Config's own default ({"dev"}) in effect.
	UndeterminedVersions []string
	// AssetName names this CLI's release archive for one version/platform
	// combination. Nil leaves selfupdate.Config's GoReleaser-shaped default
	// in effect, which every catalog entry's archive naming matches.
	AssetName func(binary, version, goos, goarch string) string
	// ChecksumsName names this CLI's release checksums file for one
	// version. Nil leaves selfupdate.Config's GoReleaser-shaped default
	// ("<binary>_<version>_checksums.txt") in effect; some CLIs publish a
	// single flat "checksums.txt" instead and override this.
	ChecksumsName func(binary, version string) string

	// CaskToken is the argument to `brew install --cask`, tap-qualified
	// (e.g. "sneat-dev/tap/wb"). Empty means this CLI publishes no
	// Homebrew cask.
	CaskToken string
	// CaskOS lists the GOOS values ("darwin", "linux") CaskToken's cask
	// supports. Empty when CaskToken is empty.
	CaskOS []string

	// LegacyVersionSignatures optionally lists bare `--version` output
	// patterns that identify an old build of this CLI, for the
	// status-probe-order fallback step
	// (cli-install#req:status-probe-order). Empty when no such pattern is
	// declared for this CLI.
	LegacyVersionSignatures []string

	// SelfUpdateHooks reports whether this CLI's own `self-update` performs
	// after-update work beyond the swap itself — a daemon restart, a skills
	// re-sync — via selfupdate.Options.AfterUpdate
	// (cli-install#req:self-update-hook-hint). Upgrade does not run another
	// CLI's hooks itself; when a target other than the host has this set and
	// is upgraded or has its manager command executed, the result carries a
	// `<target> self-update` finish hint instead. True today for wb (daemon
	// restart, skills sync) and codegrapher (skills sync) — verified against
	// each repository's own self-update command wiring; every other catalog
	// entry leaves this at its false zero value.
	SelfUpdateHooks bool
}

Entry is one compiled-in catalog record: a fleet CLI's stable identity, its release identity in the Self-Update Library's Config shape, its Homebrew cask coordinates, and the descriptive text a host shows a user before installing it (cli-install#req:catalog-entry-identity).

func ByID

func ByID(id string) (Entry, bool)

ByID returns the catalog entry for id and whether it was found (cli-install#req:host-identity-from-catalog).

func Entries

func Entries() []Entry

Entries returns every catalog entry, sorted by id, as a defensive copy — mutating the returned slice or its elements' slice/func fields never affects the compiled-in catalog.

func (Entry) Config

func (e Entry) Config(currentVersion string) selfupdate.Config

Config returns e's release identity as a selfupdate.Config for a build currently reporting currentVersion (cli-install#req:catalog-identity- single-source). It reproduces e's fields exactly; a caller that needs something only its own self-update requires (an AfterUpdate hook, for instance, which is a cobracmd.CommandOptions field, not a Config one) adds it outside this method.

func (Entry) HasCask

func (e Entry) HasCask() bool

HasCask reports whether e publishes a Homebrew cask.

type Env added in v0.16.0

type Env struct {
	// PathDirs returns the current PATH's directories, in order. It need
	// not exclude relative entries itself — Probe filters those
	// defensively — but DefaultEnv's implementation does anyway, since a
	// relative entry is never meaningful to report as a directory that
	// was searched.
	PathDirs func() []string
	// HostDir returns the running host CLI's own executable directory
	// (cli-install#req:status-locate). Returning a non-nil error is
	// treated as "no host directory to search", not a fatal Probe error.
	HostDir func() (string, error)
	// IsExecutable reports whether path names an executable regular file
	// — "not merely a file of that name" (cli-install#req:status-locate).
	IsExecutable func(path string) bool
	// EvalSymlinks resolves path's symlinks for classification
	// (cli-install#req:status-locate). May be left nil, in which case
	// classification uses only the unresolved path.
	EvalSymlinks func(path string) (string, error)
	// Run executes path with args directly, without a shell, with empty
	// stdin, "NO_COLOR=1" set, and returns the combined stdout+stderr —
	// so a probed binary's error or usage text is still available for
	// Status.Output when a step doesn't recognize the subcommand. Run
	// MUST honor ctx's deadline by killing the process when it expires
	// (cli-install#req:status-probe-bounded) and MUST NOT itself retry,
	// write any file, or make a network request.
	Run func(ctx context.Context, path string, args []string) ([]byte, error)
}

Env carries every side-effecting dependency Probe uses: PATH and process execution, filesystem access, and symlink resolution (cli-install#req:no-network-in-tests: "PATH and environment, executable probing... MUST be injectable"). A caller that wants Probe to see the real host passes DefaultEnv(); a test passes a fake, purpose-built Env and never touches a real installed binary or a real PATH.

Every field is required — DefaultEnv sets all of them, and Probe calls them unconditionally, so an Env built by hand must do the same or the missing field's nil func value panics on first use, the same as calling any other nil func.

func DefaultEnv added in v0.16.0

func DefaultEnv() Env

DefaultEnv returns an Env wired to the real host: the real "PATH" environment variable, the real running executable's directory, real filesystem and symlink checks, and real (network-free, no-shell) process execution. It is the Env a production `install`/`version`-probing command wires in; tests use a purpose-built Env instead.

type InstallEnv added in v0.17.0

type InstallEnv struct {
	Env
	// UserHomeDir returns the current user's home directory, used only on
	// non-Windows platforms to build the per-user bin directory.
	UserHomeDir func() (string, error)
	// Getenv reads one environment variable, used for %LOCALAPPDATA% and
	// the destination denylist's Windows roots and $GOROOT.
	Getenv func(string) string
	// MkdirAll creates the per-user bin directory (mode 0755) only when a
	// real, non-dry-run install actually needs it
	// (cli-install#req:per-user-bin-dir: "created only for a real
	// install... when missing").
	MkdirAll func(dir string, perm fs.FileMode) error
	// RunManaged executes `brew install --cask <token>` as structured
	// argv, streaming its own output
	// (cli-install#req:homebrew-cask-install). Required whenever a batch
	// actually runs a (non-print-only) Homebrew install; nil fails that
	// install with KindManagedCommand rather than panicking (see
	// executeHomebrewInstall).
	//
	// This package builds no default implementation itself: doing so would
	// mean deciding what to stream brew's output to, and this core layer
	// MUST NOT touch the terminal or assume any I/O streams
	// (cli-install#req:core-framework-neutral). A caller wires one from its
	// own owned streams — e.g. selfupdate/cliui.ManagedCommandRunner(in,
	// out, errOut) — exactly as selfupdate's own cobracmd adapter wires
	// Options.RunManaged for self-replace.
	RunManaged selfupdate.ManagedCommandRunner
}

InstallEnv extends Env with the additional side-effecting dependencies planning and installing need beyond status probing: per-user directory lookup, directory creation, and the managed command runner Homebrew installs run through (cli-install#req:no-network-in-tests: "the managed command runner, the per-user bin directory... MUST be injectable"). Env is embedded so an InstallEnv is usable anywhere an Env is required, e.g. passing opts.Env.Env straight to Probe.

func DefaultInstallEnv added in v0.17.0

func DefaultInstallEnv() InstallEnv

DefaultInstallEnv returns an InstallEnv wired to the real host: the real DefaultEnv, the real user home directory and environment, and real directory creation. RunManaged is left nil — see its own doc comment — and MUST be set by the caller before a batch that might run a real Homebrew install. It is what a production `install` command starts from; tests use a purpose-built InstallEnv instead.

type Method added in v0.17.0

type Method int

Method is how a target will be, or was, installed.

const (
	// MethodDirect means a verified release asset is downloaded and placed
	// at a destination path this package chose
	// (cli-install#req:direct-release-install).
	MethodDirect Method = iota
	// MethodHomebrew means `brew install --cask <token>` places the target
	// (cli-install#req:homebrew-cask-install).
	MethodHomebrew
)

func (Method) String added in v0.17.0

func (m Method) String() string

String renders Method as a stable, lower_snake_case token, matching this module's other String() conventions.

type Options added in v0.17.0

type Options struct {
	// HostID is the running host's own catalog id
	// (cli-install#req:host-identity-from-catalog). It MUST be a valid
	// catalog id; an absent one is a programming error Install panics on,
	// per that REQ's "caught by the host's tests, not a runtime state
	// users see."
	HostID string
	// Dir is the --dir flag's value; empty when it was not given.
	Dir string
	// Yes skips the confirmation gate (cli-install#req:confirmation-gate),
	// matching selfupdate's own --yes convention.
	Yes bool
	// DryRun walks the full decision path without any write, brew
	// invocation, directory creation, or confirmation
	// (cli-install#req:install-dry-run).
	DryRun bool
	// HomebrewPrintOnly reports a Homebrew install's command instead of
	// running it (cli-install#req:homebrew-cask-install).
	HomebrewPrintOnly bool
	// Env carries every side-effecting dependency.
	Env InstallEnv
	// Confirm asks whether to proceed with every target that would be
	// installed, called at most once per batch by Execute, only when at
	// least one target needs it and Yes is false
	// (cli-install#req:confirmation-gate). It receives the already-planned
	// []Result for exactly those pending targets — version, tag, asset URL,
	// destination or cask argv all already resolved by Plan — so a caller
	// renders the confirmation prompt (and, in a Cobra host, the
	// details-before-install preview) from the SAME data Execute is about
	// to act on, never a second, independently-resolved lookup. Its own
	// refusal — no interactive terminal and Yes false — is reported by
	// returning a *selfupdate.Failure{Kind: selfupdate.KindNonInteractive},
	// exactly as selfupdate.Options.Confirm documents
	// (self-update#req:non-interactive-refusal); Execute has no
	// interactive-terminal opinion of its own; it relies entirely on this
	// callback to enforce it.
	Confirm func(planned []Result) (bool, error)
	// ConfigureRelease optionally overrides a target's resolved
	// selfupdate.Config before it is used to install or resolve 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 Entry, cfg selfupdate.Config) selfupdate.Config
	// ProbeOptions tunes status probing; the zero value is
	// production-correct (see ProbeOptions).
	ProbeOptions ProbeOptions
}

Options configures Install. Every side-effecting dependency is injectable (cli-install#req:no-network-in-tests).

type Outcome added in v0.17.0

type Outcome int

Outcome classifies one target's batch install result (cli-install#req:multi-target-batch).

const (
	// OutcomeInstalled means the target was freshly installed and
	// post-install verification ran.
	OutcomeInstalled Outcome = iota
	// OutcomeAlreadyInstalled means the target's status was already
	// Installed; nothing was downloaded, reinstalled or replaced
	// (cli-install#req:already-installed-no-op).
	OutcomeAlreadyInstalled
	// OutcomeRedirected means a Homebrew install was configured print-only:
	// the command was reported, never run
	// (cli-install#req:homebrew-cask-install).
	OutcomeRedirected
	// OutcomeDryRun means --dry-run reported the planned action without
	// performing it (cli-install#req:install-dry-run).
	OutcomeDryRun
	// OutcomeDeclined means the batch confirmation was asked and declined;
	// nothing was installed and this is not a failure
	// (cli-install#req:confirmation-gate).
	OutcomeDeclined
	// OutcomeFailed means installing (or planning to install) this target
	// failed with the typed Failure.
	OutcomeFailed
)

func (Outcome) String added in v0.17.0

func (o Outcome) String() string

String renders Outcome as a stable, lower_snake_case token.

type ProbeOptions added in v0.16.0

type ProbeOptions struct {
	// Concurrency is how many targets are located and probed at once.
	// Zero defaults to 4.
	Concurrency int
	// Budget is the per-target time budget covering every probe step.
	// Zero defaults to 3 seconds.
	Budget time.Duration
}

ProbeOptions tunes Probe's concurrency and per-target time budget. The zero value is production-correct per cli-install#req:status-probe- bounded (a 3 second per-target budget, at least four targets probed concurrently); tests override both fields to stay fast and deterministic without faking Env.Run's own timeout behavior.

type Relevance

type Relevance struct {
	// Target is the relevant CLI's catalog id.
	Target string
	// Text is the relevance text written for this exact host/target pair.
	Text string
}

Relevance is one host -> target row of the catalog's relevance matrix (cli-install#req:relevance-matrix): why a user of the host would want the target.

func Relevant

func Relevant(hostID string) []Relevance

Relevant returns hostID's relevant targets in matrix order (cli-install#req:relevance-matrix, cli-install#req:list-relevant). An unknown or catalog-absent hostID, or one with no relevant targets, both return nil.

type Result added in v0.17.0

type Result struct {
	// Target is the catalog id this result describes, or — only for
	// OutcomeFailed with a KindUnknownTarget Failure — the raw name that
	// was not a catalog id.
	Target string
	// Outcome classifies what happened to Target.
	Outcome Outcome
	// Method is how Target will be, or was, installed. Meaningful only when
	// Outcome is OutcomeInstalled, OutcomeRedirected, OutcomeDryRun, or
	// OutcomeFailed after a destination was already planned.
	Method Method
	// Destination is the full destination file path for a MethodDirect
	// plan or install; empty for MethodHomebrew.
	Destination string
	// CaskArgv is the exact `brew install --cask <token>` argv for a
	// MethodHomebrew plan, redirect, or install; nil for MethodDirect.
	CaskArgv []string
	// Version and Tag are the release that was (or, for a dry run or a
	// still-planned pending target, would be) installed. Tag is the exact
	// published tag, which may differ from Version by a repository's
	// TagPrefix and/or a leading "v". Both are resolved exactly once, by
	// Plan, and Execute installs precisely this Tag — never re-resolving
	// "latest" a second time (cli-install#req:direct-release-install).
	Version string
	Tag     string
	// AssetURL is the exact release-asset URL a MethodDirect plan will
	// download; empty for MethodHomebrew
	// (cli-install#req:details-before-install: "the exact... asset URL").
	AssetURL string
	// UpdateHint names the command that updates Target, set only for
	// OutcomeAlreadyInstalled (cli-install#req:already-installed-no-op).
	UpdateHint string
	// Status is Target's probed install state: the pre-install probe for
	// every outcome except OutcomeInstalled, which carries the
	// post-install re-probe (cli-install#req:post-install-verification).
	// Zero when Target was never a valid catalog id.
	Status Status
	// Failure is set exactly when Outcome is OutcomeFailed.
	Failure *selfupdate.Failure
	// Warnings are human-readable, non-fatal notes: a shell command cache
	// hint after a real install, a shadowing notice, a PATH or
	// post-install-verification remedy, or Status's own warnings.
	Warnings []string
	// contains filtered or unexported fields
}

Result is one named target's outcome from a batch Install call — the shape task-5's output writers and Cobra adapter consume. Every fact this module's REQs require appears here as a field, in the same shape Status itself uses for probed identity, so a writer can flatten Result directly into cli-install#req:machine-readable-output's JSON document.

type State added in v0.16.0

type State int

State is a located target's install state (cli-install#req:status-probe-order, cli-install#req:list-relevant).

const (
	// NotInstalled means no executable named after the target's id (with
	// the platform suffix) was found on PATH, in the host directory, or in
	// dir.
	NotInstalled State = iota
	// Installed means a located copy's identity was confirmed by one of
	// the three status-probe-order steps.
	Installed
	// Unrecognized means a copy was located but no probe step confirmed
	// this target's identity — never trusted or reported as installed
	// (cli-install#req:unrecognized-copy-not-trusted).
	Unrecognized
)

func (State) String added in v0.16.0

func (s State) String() string

String renders State as a stable, lower_snake_case token suitable for machine-readable output, matching selfupdate.Action/FailureKind's convention.

type Status added in v0.16.0

type Status struct {
	// ID is the catalog id this Status describes.
	ID string
	// State is this target's install state.
	State State

	// Path is the primary reported copy: the first PATH match, or — when
	// no copy is on PATH — the first copy found in the host directory or
	// dir (cli-install#req:status-locate). Empty when State is
	// NotInstalled.
	Path string
	// OnPath reports whether Path itself was found on an absolute PATH
	// entry. False means Path was found only in the host directory or
	// dir, in which case Warnings carries a not-on-PATH warning.
	OnPath bool
	// OtherPaths lists every other located copy of this target, in the
	// order they were found (cli-install#req:status-locate: "additional
	// copies... count in text, full paths in JSON").
	OtherPaths []string
	// ResolvedPath is Path with its symlinks followed (cli-install#req:
	// upgrade-per-target-policy: "The path passed for replacement MUST be
	// the symlink-resolved path"), or exactly Path when Env.EvalSymlinks is
	// nil, resolution fails, or Path is not itself a symlink. Empty when
	// State is NotInstalled. Task-21's own upgrade planning is the reason
	// this is carried on Status rather than re-resolved later: a symlink
	// target can change between probing and upgrading, and re-resolving at
	// upgrade time would silently reopen the same TOCTOU window
	// cli-install#req:install-never-overwrites' no-replace placement exists
	// to close on the install side.
	ResolvedPath string

	// Method classifies Path's install method, checking both Path itself
	// and its symlink-resolved form against every manager declared
	// anywhere in the compiled catalog, preferring managed
	// (cli-install#req:status-locate). Meaningful only when State is
	// Installed or Unrecognized.
	Method selfupdate.InstallMethod
	// Manager identifies the owning package manager when Method is
	// selfupdate.Managed; nil otherwise.
	Manager *selfupdate.Manager

	// Version, Commit, Date and DateSource are read from whichever step
	// VersionSource names. Commit and Date are "" when unknown; a raw
	// "none" or "unknown" token from a text probe is normalized to ""
	// (cli-install#req:status-probe-order). Meaningful only when State is
	// Installed.
	Version    string
	Commit     string
	Date       string
	DateSource string
	// VersionSource names the step that produced Version/Commit/Date/
	// DateSource.
	VersionSource VersionSource

	// Output is the trimmed combined output of the last probe step that
	// produced any, kept for display when State is Unrecognized
	// (cli-install#req:status-probe-order: "reported with its path and
	// the output that was seen").
	Output string

	// Warnings are human-readable, non-fatal notes: a not-on-PATH warning
	// when OnPath is false, or a timeout warning when this target's probe
	// budget was exhausted.
	Warnings []string
}

Status is one target's located and probed install state — the type task-4's planner and task-5's output writers consume. It is produced entirely offline and read-only by Probe (cli-install#req:list-offline- read-only).

func Probe added in v0.16.0

func Probe(ctx context.Context, targets []Entry, dir string, env Env, opts ProbeOptions) []Status

Probe locates and identifies every entry in targets — searching absolute PATH entries, the host executable's directory, and dir (empty when no --dir was given) — and returns one Status per target, in targets' own order (cli-install#req:status-locate, cli-install#req:status-probe-order, cli-install#req:status-probe-bounded). It makes no network requests and writes, moves or deletes nothing (cli-install#req:list-offline-read- only); every side-effecting operation goes through env, so tests need exec no real installed binary.

type UpgradeBatchResult added in v0.20.0

type UpgradeBatchResult struct {
	Host    string
	Results []UpgradeResult
}

UpgradeBatchResult is the outcome of one batch PlanUpgrade/CheckUpgrades/ ExecuteUpgrade/Upgrade call: the running host's own catalog id and one UpgradeResult per target, in processing order (host always last per cli-install#req:host-upgraded-last).

func CheckUpgrades added in v0.20.0

func CheckUpgrades(ctx context.Context, names []string, opts UpgradeOptions) (UpgradeBatchResult, error)

CheckUpgrades is `--check`'s and the bare report's own entry point (cli-install#req:upgrade-check, cli-install#req:upgrade-no-args-reports). It resolves every candidate's classification and, for every installed, not-skipped target, calls selfupdate.Config.Check — self-update's own read-only comparison, the SAME call `self-update --check` makes — never selfupdate.Config.UpdateAt, so it can never download, write, confirm, run a manager command, or invoke an AfterUpdate hook, regardless of Verdict or install method. An ambiguous classification is still reported as UpgradeOutcomeRefused (task-22 review B1), but — unlike PlanUpgrade/ ExecuteUpgrade — CheckUpgrades' own caller (cobracmd's read-only report) never fails the command merely because a target is refused; only a real lookup failure (UpgradeOutcomeFailed) does that (self-update's own --check never fails for an ambiguous install either).

func ExecuteUpgrade added in v0.20.0

func ExecuteUpgrade(ctx context.Context, plan UpgradeBatchResult, opts UpgradeOptions) (UpgradeBatchResult, error)

ExecuteUpgrade upgrades every still-pending target in plan (Outcome == UpgradeOutcomeDryRun — the rows whose PlanUpgrade UpdateAt(DryRun) call returned ActionPlanned) — asking at most one confirmation covering all of them (unless opts.Yes) — then calls the REAL selfupdate.Config.UpdateAt (DryRun false) for each one, passing EXACTLY the release tag PlanUpgrade already resolved via selfupdate.Options.ResolvedTag, with no per-target Confirm callback (the batch gate already asked; UpdateAt with a nil Confirm proceeds immediately). Every other Result in plan — ahead, redirected, refused, skipped, not installed, unrecognized or failed — is a terminal outcome PlanUpgrade's own UpdateAt call already decided and passes through unchanged. The one exception is an already-current HOST row: ExecuteUpgrade makes a SECOND, real UpdateAt call for it — see the dedicated paragraph below — every other row never gets a second call (task-22 review B3; task-22 third review N3, correcting an earlier revision of this comment that claimed no row ever gets one). Targets execute in plan's own order, which already carries the host last (cli-install#req:host-upgraded-last).

An already-current host's after-update hook runs from a SECOND, real (non-dry-run) UpdateAt call, unconditionally, regardless of how the pending-confirmation gate above resolved — proceeded, declined, or refused outright (task-22 third review N2): selfupdate.Config.UpdateAt's own runAfterUpdate skips the hook whenever Options.DryRun is set, so PlanUpgrade's own DryRun(true) call, which already decided this row is already current, never fires it, exactly as `self-update --dry-run` itself never does; `self-update --yes` on an already-current binary makes exactly ONE UpdateAt call with DryRun false, and THAT call's runAfterUpdate does fire. Gating this second call behind the SAME confirmation the pending targets need would be wrong: the host is a no-op either way — nothing is downloaded, written, or replaced — so REQ: confirmation-gate's own "before any download or write" scope never applies to it, and self-update itself never asks before running this hook either. A non-interactive refusal or a Confirm error for some OTHER pending target must not suppress it, so this call happens on every return path, not only the "everything proceeded" one.

ExecuteUpgrade always returns a fully populated UpgradeBatchResult, one Result per target, even for a batch-level confirmation refusal — mirroring Execute's own "never an empty BatchResult" contract. Its own returned error exists only for a caller that wants one classification of a batch-level refusal; UpgradeBatchResult.Failure() is the way to see every target's own typed failure.

func PlanUpgrade added in v0.20.0

func PlanUpgrade(ctx context.Context, names []string, opts UpgradeOptions) (UpgradeBatchResult, error)

PlanUpgrade validates and locates every target and, for each one that is installed and not skipped, calls the REAL selfupdate.Config.UpdateAt with DryRun set — exactly the call `self-update --dry-run` makes for the same classified copy (cli-install#req:upgrade-per-target-policy: "Each target MUST be handled by the Self-Update Library's policy"). PlanUpgrade itself makes no ambiguous/managed/current/ahead decision: mapAction only translates UpdateAt's own Outcome.Action and Failure into this package's display vocabulary.

PlanUpgrade's own UpdateAt(DryRun) call never runs the host's after- update hook, even for an already-current host: selfupdate.Config. UpdateAt's own runAfterUpdate skips it whenever Options.DryRun is set (self-update's own, pre-existing behavior — there being nothing to preview for a no-op), and PlanUpgrade's call always sets DryRun. A real (non-dry-run, non-check) run's after-update hook fires from ExecuteUpgrade's own real UpdateAt call instead — including a SECOND such call for an already-current host, since that row is otherwise terminal after planning and would not reach a real call at all (task-22 review B2; see ExecuteUpgrade's own doc comment). `--check` and the bare, no-argument report do not call PlanUpgrade at all — they call CheckUpgrades, which uses the strictly read-only selfupdate.Config.Check instead (cli-install#req:upgrade-check, cli-install#req:upgrade-no-args- reports).

PlanUpgrade alone is `--dry-run`'s complete answer, and it is the SAME plan ExecuteUpgrade later acts on for whatever is still pending — the tag a caller shows before confirming is the SAME tag ExecuteUpgrade passes to UpdateAt's own ResolvedTag (cli-install#req:upgrade-resolves- release-once).

names selects explicit targets; opts.All, or an empty names with opts.All false, selects cli-install#req:upgrade-targets' "--all" set instead (every installed catalog id, plus the host). An unknown name fails the WHOLE batch before anything is probed or looked up (cli-install#req:unknown-target-refused); that case is the returned error, with an empty BatchResult. Every other outcome, including every per-target failure, is reported only in BatchResult.Results.

func Upgrade added in v0.20.0

func Upgrade(ctx context.Context, names []string, opts UpgradeOptions) (UpgradeBatchResult, error)

Upgrade is the PlanUpgrade + confirm + ExecuteUpgrade convenience: it plans the whole batch, and — unless opts.DryRun — executes it, mirroring Install's own Plan + confirm + Execute contract exactly.

func (UpgradeBatchResult) Failed added in v0.20.0

func (b UpgradeBatchResult) Failed() bool

Failed reports whether at least one Result counts as a failure per upgradeResultFailed — mirroring BatchResult.Failed(). An unrecognized, not-installed, ahead, or skipped target is a descriptive state, not something that went wrong this run; a refused (ambiguous) one is.

func (UpgradeBatchResult) Failure added in v0.20.0

func (b UpgradeBatchResult) Failure() error

Failure returns nil when b did not fail, and otherwise a *BatchFailure carrying every failed target's typed *selfupdate.Failure (including every refused/ambiguous one) — the same aggregate type BatchResult.Failure returns, so a host's ErrorMapper handles both install and upgrade batches through one code path.

type UpgradeOptions added in v0.20.0

type UpgradeOptions struct {
	// HostID is the running host's own catalog id
	// (cli-install#req:host-identity-from-catalog). Must be a valid catalog
	// id; PlanUpgrade panics otherwise, matching Plan's own contract.
	HostID string
	// All selects every catalog id whose status is installed, plus the
	// host, regardless of the relevance matrix (cli-install#req:upgrade-
	// targets). Names given alongside All is a caller/usage-layer concern
	// (cobracmd's own "--all takes no target names" refusal, mirroring
	// install's own usage check) — PlanUpgrade itself treats All as taking
	// priority and simply ignores any names passed alongside it. An empty
	// names list with All false is ALSO treated as the All set
	// (cli-install#req:upgrade-no-args-reports: the bare, no-argument
	// report runs the read-only check over the --all set), so a caller
	// need not special-case the truly-bare invocation.
	All bool
	// Yes skips the confirmation gate, matching Options.Yes.
	Yes bool
	// DryRun walks the full decision path without confirming, replacing,
	// or running any manager command (cli-install#req:upgrade-batch-
	// semantics inheriting cli-install#req:install-dry-run). Upgrade
	// returns PlanUpgrade's own result unchanged when set, exactly as
	// Install does for Options.DryRun.
	DryRun bool
	// Env carries every side-effecting dependency: status probing (via the
	// embedded Env) and the managed command runner (RunManaged) upgrade
	// shares with install. Getenv additionally supplies GH_TOKEN/
	// GITHUB_TOKEN for the bearer-auth HTTPClient default (cli-install#req:
	// upgrade-release-lookups-bounded).
	Env InstallEnv
	// Confirm asks whether to proceed with every target that would be
	// upgraded, called at most once per batch by ExecuteUpgrade, exactly
	// as Options.Confirm — it receives the already-planned pending
	// []UpgradeResult (current, latest, verdict, method, command all
	// already resolved).
	Confirm func(pending []UpgradeResult) (bool, error)
	// ConfigureRelease optionally overrides a non-host target's resolved
	// selfupdate.Config before it is used to look up 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, bearer-authenticated
	// per HostConfig's own doc comment).
	ConfigureRelease func(target Entry, cfg selfupdate.Config) selfupdate.Config
	// ProbeOptions tunes status-probe concurrency and per-target time
	// budget; the zero value is production-correct.
	ProbeOptions 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: "The host MUST
	// use its own self-update Config and options... so upgrade <self> and
	// self-update reach the same library call"). Required whenever the
	// host is a candidate target (named explicitly, or under All/the bare
	// report). When its HTTPClient is left nil, PlanUpgrade/ExecuteUpgrade
	// default it to a bearer-authenticated client exactly as it does for
	// every other target — see the package-level githubHTTPClient doc
	// comment.
	HostConfig selfupdate.Config
	// HostAfterUpdate is the host's own after-update hook, passed straight
	// through to selfupdate.Options.AfterUpdate only for the host's own
	// REAL (non-dry-run) UpdateAt call, in ExecuteUpgrade — 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), including when
	// the host is already current (task-22 review B2: ExecuteUpgrade makes
	// a second real UpdateAt call for an already-current host specifically
	// because selfupdate.Config.UpdateAt's own runAfterUpdate skips the
	// hook under DryRun, so PlanUpgrade's own DryRun(true) call alone never
	// fires it — see ExecuteUpgrade's own doc comment). Never used for any
	// other target: v1 reports a FinishHint instead of running another
	// CLI's hooks (cli-install#req:self-update-hook-hint).
	HostAfterUpdate selfupdate.AfterUpdateFunc
	// DetectHost resolves the host's own install classification. Nil
	// defaults to opts.HostConfig.DetectSelf — the real running executable
	// — exactly matching what the host's own `self-update` command would
	// call (cli-install#req:host-target-is-running-binary; task-22 review
	// S1: classification MUST come from DetectSelf, not a rebuilt
	// `<hostDir>/<hostID>` path, which can name the wrong file for a
	// renamed or aliased binary). Tests inject a fake to avoid depending on
	// the actual test binary's own location; production callers leave this
	// nil.
	DetectHost func() (selfupdate.Detection, error)
	// VerifyManaged probes an executable managed target after its manager
	// command completes, passed straight through to
	// selfupdate.Options.VerifyManaged for every target including the host
	// (task-22 review S2: this MUST be the same verifier `self-update`
	// itself uses — filtering PATH candidates by the detected manager's own
	// markers — never an ad hoc probe with no manager filter). cliinstall
	// itself has no opinion on how verification works; a Cobra host
	// defaults this to selfcliui.VerifyManagedBinary, exactly as its own
	// self-update command does. Required whenever any candidate target
	// might be an executable managed install; nil makes such an upgrade
	// fail with selfupdate.KindManagedCommand, matching UpdateAt's own
	// "not configured" failure.
	VerifyManaged selfupdate.ManagedBinaryVerifier

	// LookupConcurrency bounds how many targets' latest-release lookups run
	// at once. Zero defaults to 4 (cli-install#req:upgrade-release-
	// lookups-bounded).
	LookupConcurrency int
	// LookupTimeout bounds each individual latest-release lookup. Zero
	// defaults to 15 seconds (cli-install#req:upgrade-release-lookups-
	// bounded).
	LookupTimeout time.Duration
}

UpgradeOptions configures PlanUpgrade/CheckUpgrades/ExecuteUpgrade/ Upgrade. Every side-effecting dependency is injectable (cli-install#req:no-network-in-tests).

type UpgradeOutcome added in v0.20.0

type UpgradeOutcome int

UpgradeOutcome classifies one named target's result from a batch PlanUpgrade/CheckUpgrades/Upgrade call (cli-install#req:upgrade-batch- semantics: "per-target results (upgraded, manager executed, redirected, already current, ahead of latest, skipped non-release build, not installed, unrecognized, refused, dry run, declined, or failed)" — this type carries exactly those twelve tokens).

Every non-terminal value below (everything except SkippedNonRelease, NotInstalled, Unrecognized) is produced by mapping selfupdate.Config.UpdateAt's own Outcome.Action or Failure — never by a decision this package makes on its own (cli-install#req:upgrade-per- target-policy: "handled by the Self-Update Library's policy"). See mapAction and PlanUpgrade's own doc comment.

const (
	// UpgradeOutcomeUpgraded means a manual install was verified,
	// downloaded and atomically replaced (selfupdate.ActionUpdated).
	UpgradeOutcomeUpgraded UpgradeOutcome = iota
	// UpgradeOutcomeManagerExecuted means an executable package-manager
	// update ran to completion (selfupdate.ActionManagerExecuted).
	UpgradeOutcomeManagerExecuted
	// UpgradeOutcomeRedirected means a redirect-only managed install's
	// upgrade command was reported without running anything
	// (selfupdate.ActionRedirected).
	UpgradeOutcomeRedirected
	// UpgradeOutcomeAlreadyCurrent means the running version already equals
	// the latest stable release; nothing changed
	// (selfupdate.ActionAlreadyCurrent). For the host, and only for a real
	// (non-dry-run, non-check) run, ExecuteUpgrade makes one further real
	// UpdateAt call for this row so its after-update hook still runs,
	// exactly as self-update does (REQ: host-target-is-running-binary;
	// task-22 review B2) — selfupdate.Config.UpdateAt's own runAfterUpdate
	// skips the hook under DryRun, so PlanUpgrade's own DryRun(true) call
	// alone never fires it.
	UpgradeOutcomeAlreadyCurrent
	// UpgradeOutcomeAhead means the installed version orders strictly above
	// the latest stable release (self-update#req:ahead-of-latest); nothing
	// changed and this never counts as an available upgrade
	// (selfupdate.ActionAhead).
	UpgradeOutcomeAhead
	// UpgradeOutcomeSkippedNonRelease means an --all- or report-sourced
	// target was a non-release build and was never looked up
	// (cli-install#req:upgrade-skips-non-release-builds).
	UpgradeOutcomeSkippedNonRelease
	// UpgradeOutcomeNotInstalled means an explicitly named target has no
	// located copy; InstallHint names the remedy.
	UpgradeOutcomeNotInstalled
	// UpgradeOutcomeUnrecognized means a located copy's identity could not
	// be confirmed; it is never touched
	// (cli-install#req:unrecognized-copy-not-trusted).
	UpgradeOutcomeUnrecognized
	// UpgradeOutcomeRefused means the install method is ambiguous
	// (selfupdate#req:ambiguous-safe-default): Failure always carries
	// selfupdate.KindAmbiguous, and this counts as a batch failure exactly
	// like UpgradeOutcomeFailed — see UpgradeBatchResult.Failed/Failure —
	// because `self-update` itself fails outright for an ambiguous install,
	// and `upgrade <self>`/`upgrade <name>` must reach the same verdict
	// (cli-install#req:self-update-equals-upgrade-self). It is computed
	// BEFORE any verdict is even considered: an ambiguous target is refused
	// whether it is current, ahead, or has an update available.
	UpgradeOutcomeRefused
	// UpgradeOutcomeDryRun means this target would be upgraded: it is
	// either --dry-run's own final answer, or PlanUpgrade's "still pending
	// confirmation" marker that ExecuteUpgrade replaces with a terminal
	// outcome (selfupdate.ActionPlanned, mapped 1:1).
	UpgradeOutcomeDryRun
	// UpgradeOutcomeDeclined means the batch confirmation was asked and
	// declined; nothing changed and this is not a failure.
	UpgradeOutcomeDeclined
	// UpgradeOutcomeFailed means resolving or applying this target's
	// upgrade failed with the typed Failure.
	UpgradeOutcomeFailed
)

func (UpgradeOutcome) String added in v0.20.0

func (o UpgradeOutcome) String() string

String renders UpgradeOutcome as a stable, lower_snake_case token, matching this module's other String() conventions.

type UpgradeResult added in v0.20.0

type UpgradeResult struct {
	// Target is the catalog id this result describes.
	Target string
	// Host is true exactly for the row describing the running host itself
	// (cli-install#req:host-target-is-running-binary).
	Host bool
	// Outcome classifies what happened to Target — REQ: upgrade-batch-
	// semantics' "action".
	Outcome UpgradeOutcome

	// InstallMethod classifies Target's install (cli-install#req:upgrade-
	// per-target-policy): for a non-host target this follows DetectSelf's
	// own rule (managed on either the PATH-found or symlink-resolved path,
	// otherwise manual or ambiguous judged on the resolved path alone); for
	// the host it is literally selfupdate.Config.DetectSelf's own
	// classification of the running executable (REQ: host-target-is-
	// running-binary — task-22 review S1), not a rebuilt path. Meaningful
	// only when Target was located and Installed.
	InstallMethod selfupdate.InstallMethod
	// Manager identifies the owning package manager when InstallMethod is
	// selfupdate.Managed; nil otherwise.
	Manager *selfupdate.Manager
	// ResolvedPath is the file this upgrade acts on: the symlink-resolved
	// path for a Manual or Ambiguous classification (REQ: upgrade-per-
	// target-policy: "The path passed for replacement MUST be the
	// symlink-resolved path, so a symlink is kept"), or the located path
	// for a Managed one, whose file is never written directly.
	ResolvedPath string

	// Current is Target's installed version: the probed Status.Version for
	// a non-host target, or the host's own Config.CurrentVersion for the
	// host row — never the version a status probe of the host's own PATH
	// copy would have found (REQ: host-target-is-running-binary).
	Current string
	// Latest is the resolved latest stable release's normalized version,
	// set once a lookup has completed.
	Latest string
	// Tag is Latest's exact published tag, passed to
	// selfupdate.Options.ResolvedTag so Execute never independently
	// re-searches for "latest" a second time (cli-install#req:upgrade-
	// resolves-release-once) — UpdateAt's own re-verification that this
	// tag is STILL latest is a separate, deliberate check documented on
	// that call, not a second search.
	Tag string
	// Verdict is the comparison between Current and Latest, set once a
	// lookup has completed. Zero (selfupdate.UpToDate) when no lookup ran.
	Verdict selfupdate.Verdict

	// Command is the manager's display upgrade command, set whenever
	// Manager is non-nil, regardless of Outcome. Empty for a manager that
	// carries only Hint instead — e.g. the built-in system-package manager,
	// which has no single copy-pasteable command (see selfupdate.Manager.
	// UpgradeHint). A renderer MUST NOT print an empty Command after a
	// "Run:"-style prefix.
	Command string
	// Hint is the manager's UpgradeHint — human-readable prose naming how
	// to update when there is no single Command to print — set whenever
	// Manager is non-nil, regardless of Outcome. At most one of Command and
	// Hint is normally non-empty; a renderer shows Hint in a natural
	// sentence, never after a "Run:" prefix the way Command is.
	Hint string
	// AssetURL is the exact release-asset URL a pending manual upgrade
	// would fetch, taken from selfupdate.Outcome.PlannedURL
	// (cli-install#req:upgrade-batch-semantics: "version transition, asset
	// URL and path" — task-22 review S3). Empty for a managed target (its
	// Command already names the action) and for any terminal outcome that
	// never reached a planned replacement.
	AssetURL string
	// NonReleaseBuild is true when Current was classified a non-release
	// build (cli-install#req:upgrade-skips-non-release-builds) and this
	// target was offered anyway because it was named explicitly — the
	// confirmation prompt tags such a target by name (task-22 review S3).
	NonReleaseBuild bool
	// InstallHint names the remedy for UpgradeOutcomeNotInstalled:
	// "<host> install <target>".
	InstallHint string
	// FinishHint names the remedy for a non-host target whose catalog entry
	// declares SelfUpdateHooks and was Upgraded or had its manager command
	// executed: "<target> self-update" (cli-install#req:self-update-hook-
	// hint). Empty otherwise; upgrade never runs another CLI's hooks
	// itself.
	FinishHint string

	// Status is Target's probed install state, as REQ: status-probe-order
	// found it before this upgrade acted (or, for a target this upgrade
	// never touches, its only state). Always zero for the host: the host's
	// classification and version come from DetectSelf/Config, never from a
	// status probe of its own PATH copy (task-22 review M2) — a separate
	// PATH copy, if one exists, is named only in Warnings and OtherPaths.
	Status Status
	// OtherPaths lists additional located copies of Target, exactly as
	// Status.OtherPaths does for a non-host row; for the host row this is
	// the probed PATH copy (if any) instead, since Status itself is zero.
	OtherPaths []string
	// Failure is set exactly when Outcome is UpgradeOutcomeFailed or
	// UpgradeOutcomeRefused.
	Failure *selfupdate.Failure
	// Warnings are human-readable, non-fatal notes: a non-release-build
	// notice, an ambiguous-install guidance message, another-PATH-copy
	// warning for the host, a post-swap or after-update warning, a finish
	// hint's own prose, or Status's own warnings.
	Warnings []string
}

UpgradeResult is one target's outcome from a batch PlanUpgrade/ CheckUpgrades/ExecuteUpgrade/Upgrade call — the shape cliinstall/cliui's output writers flatten into cli-install#req:machine-readable-output's added upgrade fields ("current, latest, verdict, action, command and resolved_path").

type VersionSource added in v0.16.0

type VersionSource int

VersionSource identifies which status-probe-order step produced a Status's Version/Commit/Date/DateSource fields. Meaningful only when State is Installed.

const (
	// VersionSourceNone means no step produced version information —
	// State is not Installed.
	VersionSourceNone VersionSource = iota
	// VersionSourceJSON means step 1, `version --json`, succeeded.
	VersionSourceJSON
	// VersionSourceText means step 2, plain `version` text, succeeded.
	VersionSourceText
	// VersionSourceFlag means step 3, `--version` matching a declared
	// legacy signature, succeeded.
	VersionSourceFlag
)

func (VersionSource) String added in v0.16.0

func (v VersionSource) String() string

String renders VersionSource as the stable token REQ: machine-readable- output's "version_source" JSON field carries.

Directories

Path Synopsis
Package cliui holds the framework-neutral parts of an install CLI's user interaction: the Row view type a caller assembles from cliinstall's own catalog, status and batch-result types; the text and JSON writers for a listing, a details/dry-run/install-result view, and the batch confirmation prompt.
Package cliui holds the framework-neutral parts of an install CLI's user interaction: the Row view type a caller assembles from cliinstall's own catalog, status and batch-result types; the text and JSON writers for a listing, a details/dry-run/install-result view, and the batch confirmation prompt.
Package cobracmd builds a ready-made "install" Cobra command from a cliinstall catalog host id.
Package cobracmd builds a ready-made "install" Cobra command from a cliinstall catalog host id.
Command gen records, under cliinstall/testdata/snapshots/, a snapshot of each catalog CLI's real published release asset list and (where one exists) its real Homebrew cask file.
Command gen records, under cliinstall/testdata/snapshots/, a snapshot of each catalog CLI's real published release asset list and (where one exists) its real Homebrew cask file.

Jump to

Keyboard shortcuts

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