Documentation
¶
Overview ¶
Package selfupdate implements `brain update`: check GitHub for a newer release, verify it actually runs on this machine, then replace the running binary.
This is the one place in the codebase that makes a network call on its own initiative rather than because a user typed a command that needs one — and even here, only when the user typed `brain update` specifically. It never runs on a schedule, from doctor, or in the background, and the request it makes carries no vault path, no machine identifier, no telemetry: a bare GET with a User-Agent naming this binary and nothing else. See Update's doc comment for the verification chain that runs before anything is replaced.
Index ¶
- func AssetName(version, goos, goarch string) string
- func ExtractBinary(archive []byte, goos string) ([]byte, error)
- func IsDevBuild(version string) bool
- func VerifyChecksum(sums []byte, name string, data []byte) error
- type Asset
- type Client
- type Error
- type InstallKind
- type Options
- type Release
- type Result
- type Step
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AssetName ¶
AssetName is what scripts/release.sh names one platform's archive: brain_<version>_<goos>_<goarch>.tar.gz, or .zip on Windows. Go's own GOOS/GOARCH spellings are what the script uses directly — no npm-style x64 translation is needed here.
func ExtractBinary ¶
ExtractBinary pulls the brain executable out of a release archive. The archive holds it one directory down (brain_<version>_<goos>_<goarch>/brain), so this matches on suffix rather than an exact path.
func IsDevBuild ¶
IsDevBuild reports whether version is the unstamped default a plain `go build` produces. Updating one would silently replace a local build with a release binary — a footgun this refuses outright rather than warns about.
Types ¶
type Client ¶
type Client struct {
HTTP *http.Client
APIBase string
Repo string
// Agent is the User-Agent sent on every request. It names the binary and
// nothing else — no hostname, no vault path, no user identifier.
Agent string
}
Client talks to GitHub. Every field is overridable so tests point this at an httptest.Server instead of the real API — nothing in this package should ever need real network access to be exercised.
func NewClient ¶
NewClient is what `brain update` uses. version is stamped into the User-Agent so a look at GitHub's own request logs identifies which release is asking, nothing more.
type Error ¶
Error names the step that failed. Every path out of Update that is not a clean success or "already current" returns one of these — invariant 4: a failure is reported, never swallowed into a success-shaped result.
type InstallKind ¶
type InstallKind int
InstallKind is how this binary got onto the machine, which decides whether `brain update` has anything to replace.
const ( // Standalone is a binary in an ordinary place — go install, a release // tarball extracted by hand, a plain reinstall. Replacing it in place is // exactly what the user wants. Standalone InstallKind = iota // NPX resolves a fresh copy from the registry on every invocation. There // is nothing durable here to replace. NPX // NPMManaged is installed through npm's per-platform package mechanism // (global or local). Replacing the binary works, but npm's own version // bookkeeping will not reflect it. NPMManaged )
func DetectInstall ¶
func DetectInstall(path string) InstallKind
DetectInstall classifies a resolved executable path. Callers should run it through filepath.EvalSymlinks first.
type Options ¶
type Options struct {
Client *Client
Verify func(path, wantVersion string) error
Executable func() (string, error)
}
Options lets tests substitute the network client, the "does this binary actually run" check, and how the running executable is resolved — so the whole flow is exercisable against an httptest.Server and a fake verify function, never a real GitHub API or a real exec. The zero value is what `brain update` uses.
type Release ¶
Release is what the GitHub releases/latest endpoint returns, trimmed to what this package needs.
type Result ¶
Result is what a successful Update did, printed verbatim by the CLI. To == From (both set, Asset empty) means the check ran and nothing needed doing.
func Update ¶
Update is the whole flow, in the order that matters:
- Refuse outright on an unstamped dev build.
- Resolve the running executable. If it resolves to an npx cache, refuse with no network call at all — there is nothing to check.
- Ask GitHub what the latest release is. If it is what we already are, stop here; nothing downloaded, nothing written.
- Confirm the executable's directory is writable, so a permission failure is reported before a byte is downloaded.
- Download the archive and SHA256SUMS, and verify the archive's checksum before touching anything else.
- Extract the binary, write it into the executable's own directory (so the final rename is same-filesystem), and run it to confirm it reports the version it claims to. Only a binary that passes this is ever installed.
- Swap it in.
Every failure names the step it failed at (see Error) rather than a bare "could not update", and nothing is replaced until step 6 has actually run the new binary — a checksum proves transport, not that the bytes work on this machine.