selfupdate

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package selfupdate replaces the running binary with the newest published release, doing every step that touches the network through a curl subprocess.

ADR-0026 puts the socket in curl rather than in this binary: the Go code here builds arguments, compares a checksum, unpacks an archive and performs the atomic replacement, and nothing in it opens a connection. The one file that runs a subprocess is curl.go, so the property is checkable by reading it.

Every literal below — the redirect form, the archive name, the checksum file and the download base — is the one install.sh already uses (ADR-0026: reuse its steps rather than reinvent them). curl_test.go asserts they still match.

Index

Constants

View Source
const LatestReleaseURL = "https://github.com/" + Repo + "/releases/latest"

LatestReleaseURL redirects to the newest release's page; the tag is the last segment of the URL it lands on. install.sh resolves the version the same way.

View Source
const Repo = "SupermodularAI/agents-wake"

Repo is the GitHub repository releases are published to.

Variables

View Source
var ErrCurlMissing = errors.New("curl is not installed: wake update needs curl on PATH to reach the network")

ErrCurlMissing reports that curl is not installed. Update is the only feature with a prerequisite beyond the binary itself (ADR-0026), so the refusal names it rather than surfacing an exec error.

Functions

func IsUntagged

func IsUntagged(running string) bool

IsUntagged reports whether running is the un-injected sentinel a build outside the release pipelines carries (version.Untagged).

Types

type CurlFetcher

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

CurlFetcher is the production Fetcher: one curl subprocess per call.

func NewCurlFetcher

func NewCurlFetcher() (CurlFetcher, error)

NewCurlFetcher locates curl on PATH, returning ErrCurlMissing when it is absent.

func (CurlFetcher) Download

func (c CurlFetcher) Download(url, dest string) error

Download writes url's body to dest.

curl's own diagnostics are included in the failure, because a refusal that says only "exit status 22" leaves the user with nothing to act on. Nothing here reads a transcript, so the only strings that can appear are release-asset URLs and curl's messages.

func (CurlFetcher) EffectiveURL

func (c CurlFetcher) EffectiveURL(url string) (string, error)

EffectiveURL resolves url's redirects, printing the URL it lands on and discarding the body.

type Fetcher

type Fetcher interface {
	// EffectiveURL follows url's redirects and returns the URL it lands on,
	// downloading no body.
	EffectiveURL(url string) (string, error)
	// Download writes url's body to dest, replacing whatever is there.
	Download(url, dest string) error
}

Fetcher performs the two network steps update needs. Production is curl; a test substitutes a fake, which is why no in-process HTTP client exists here or in any test in this package (ADR-0026).

type Result

type Result struct {
	// Tag is the latest published tag, whether or not it was installed.
	Tag string
	// Replaced is false when the running binary was already that tag, in which
	// case nothing was downloaded and nothing was written.
	Replaced bool
}

Result reports what Apply did.

type Status

type Status int

Status is the outcome of comparing the running version against the latest tag.

const (
	// StatusUntagged means the running binary carries no release tag, so there
	// is nothing to compare it against.
	StatusUntagged Status = iota
	// StatusCurrent means the running binary already is the latest release.
	StatusCurrent
	// StatusOutdated means the latest release is not the running version.
	StatusOutdated
)

func Compare

func Compare(running, latest string) Status

Compare places the running version against the latest published tag.

A string comparison and nothing more: ADR-0026 makes --check a string compare, so no ordering is inferred from two tags. Anything that is not the latest tag and not the untagged sentinel is reported as outdated, which is the honest answer for a hand-built binary carrying some other string too.

type Updater

type Updater struct {
	// Fetch performs the network steps. Required.
	Fetch Fetcher
	// GOOS and GOARCH select the release asset.
	GOOS, GOARCH string
	// Running is the version the current binary reports (version.Version).
	Running string
	// Executable is the path of the binary Apply replaces. Required by Apply,
	// unused by Latest.
	Executable string
}

Updater performs one update, or one check, for a single running binary.

Every field is explicit rather than read from the process: the resolve → verify → replace sequence is the part that must be exercisable from a test without a network, a release, or a binary the test is willing to overwrite.

func (Updater) Apply

func (u Updater) Apply() (Result, error)

Apply installs the latest release over the running binary, or reports that it is already installed.

The order is the guarantee: refuse an unsupported platform, resolve the tag, stop when it is the one already running, download the archive and the checksums, verify, unpack, and only then replace. Anything that fails before the last step leaves the existing binary exactly as it was.

Callers handle StatusUntagged themselves; Apply treats any Running that is not the latest tag as out of date.

func (Updater) Latest

func (u Updater) Latest() (string, error)

Latest resolves the newest published tag from LatestReleaseURL's redirect, downloading nothing.

The platform refusal comes first, before the network: a machine with no published asset must be told that plainly rather than be shown an available release it cannot install, or a raw 404 from curl (ADR-0021).

Jump to

Keyboard shortcuts

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