Documentation
¶
Overview ¶
Package update implements prereview's self-update: checking GitHub for a newer release, verifying the download against the release checksums, and atomically swapping the running binary. It also detects package-manager installs (Homebrew, Scoop) whose lifecycle prereview must not disturb.
Index ¶
- Constants
- Variables
- func Reexec(exe, newTag string) error
- func ReleaseVersion(ldflagVersion string) string
- func ResolveExecutablePath() (string, error)
- func SelfUpdate(ctx context.Context, current, targetPath, apiBase string, client *http.Client, ...) (newTag string, err error)
- func ShouldAutoUpdate(version string, noUpdateFlag bool) bool
- type PkgManager
Constants ¶
const (
GithubAPIBase = "https://api.github.com"
)
Variables ¶
var ( ErrDevBuild = errors.New("not a released build (version is \"dev\"); this binary was built from a source tree. Install a release from https://github.com/livetemplate/prereview/releases or via `go install github.com/livetemplate/prereview@latest`") ErrGoBuildCache = errors.New("running from the go build cache (go run); self-update is only for installed release binaries") ErrAlreadyCurrent = errors.New("already on the latest version") ErrThrottled = errors.New("update check skipped (already checked within the last hour)") ErrUnwritable = errors.New("the prereview binary is not writable; reinstall it somewhere you own or run with elevated permissions") ErrChecksumMismatch = errors.New("checksum mismatch: the downloaded archive is corrupt or has been tampered with") )
Sentinel errors. Their message text is what the `--update` command prints to the user, so keep them human-readable. The on-run path treats the "expected, not really a failure" ones as no-ops.
Functions ¶
func Reexec ¶
Reexec replaces the current process with the freshly-installed binary so the in-flight invocation runs the new version. PREREVIEW_UPDATED makes the child skip its own update check (loop guard). On unix this never returns on success (the image is replaced); on Windows it spawns a child, waits, and exits with the child's status.
func ReleaseVersion ¶ added in v0.25.1
ReleaseVersion resolves the running binary's version, given the value of main.version.
goreleaser stamps -X main.version on release builds, so a non-"dev" ldflagVersion is authoritative. A `go install <mod>@vX.Y.Z` build gets no ldflag and so reports the "dev" default even though it *is* a release — but Go records the module version in the embedded build info, so recover it from there. Without this, `go install` (which the ErrDevBuild message recommends) produces a binary that can never self-update.
The fallback is deliberately strict: only a bare vX.Y.Z tag counts. A local `go build` also embeds a version, but as a pseudo-version ("v0.24.5-0.20260723204349-<sha>"), often with a "+dirty" suffix, and a build with no VCS info reports "(devel)". Treating any of those as a release would let the on-run check overwrite a developer's own build with a download. Anything unrecognized stays "dev", which costs the user only a manual install.
func ResolveExecutablePath ¶
ResolveExecutablePath returns the real on-disk path of the running binary with symlinks resolved (Homebrew/asdf/nix wrappers), or ErrGoBuildCache when running via `go run`.
func SelfUpdate ¶
func SelfUpdate(ctx context.Context, current, targetPath, apiBase string, client *http.Client, cacheDir string, force bool) (newTag string, err error)
SelfUpdate is the single orchestrator used by both `--update` (force=true, bypasses the 1h throttle) and the on-run check (force=false). On success it returns the new tag and nil; the "expected non-update" outcomes are returned as sentinel errors so the caller can decide whether to surface or silently ignore them.
func ShouldAutoUpdate ¶
ShouldAutoUpdate is the pure predicate gating the on-run check. It is false for dev builds, when opted out via flag/env, and inside a re-exec'd child (PREREVIEW_UPDATED set) to prevent an update loop.
Types ¶
type PkgManager ¶
type PkgManager struct {
Name string // display name, e.g. "Homebrew"
Upgrade string // e.g. "brew upgrade prereview"
Uninstall string // e.g. "brew uninstall prereview"
}
PkgManager identifies the package manager that owns a binary's lifecycle and the exact commands to suggest. upgrade/uninstall are stored in full because the verbs aren't uniform across managers (brew upgrades with "brew upgrade" but Scoop uses "scoop update"; both uninstall with "uninstall").
func DetectPackageManager ¶
func DetectPackageManager(exePath string) (pm PkgManager, ok bool)
DetectPackageManager reports whether the binary at exePath was installed by a package manager that owns its lifecycle. Self-replacing or self-deleting such a binary would desync it from the manager's metadata, so both the update and uninstall paths defer to the manager instead. Detection is a path-substring heuristic on the symlink-resolved executable path (ResolveExecutablePath already calls EvalSymlinks): Homebrew installs land under a ".../Cellar/..." prefix on both Intel (/usr/local/Cellar) and ARM (/opt/homebrew/Cellar) layouts; Scoop installs live under a "scoop" directory. ok is false for binaries placed by curl, `go install`, or a manual download.