Documentation
¶
Overview ¶
Package autoupdate tells a user that a newer release exists, and nothing else.
It never installs. goselfupdate.Update installs, and the command wrapping it is where errors are printed; a failure here is recorded in the state file and swallowed. That single rule is what keeps a development build from printing an update failure on every invocation.
session := autoupdate.Start(ctx, autoupdate.Config{
Update: goselfupdate.Config{Owner: "you", Repo: "tool", Binary: "tool", Version: version},
})
err := rootCmd.ExecuteContext(ctx)
session.Finish()
The check runs concurrently with the caller's own work and the notice is printed afterwards, so the line is not buried in the command's output. A command that outlasts the check pays nothing for it. One that finishes first waits in Session.Finish for at most Config.Timeout.
A separate package from goselfupdate so that a program wanting only the update half links none of this.
Index ¶
Constants ¶
const DefaultInterval = 24 * time.Hour
DefaultInterval is how long a check is good for.
const DefaultTimeout = 5 * time.Second
DefaultTimeout bounds the check. Start gives the check a context with this deadline, and Finish waits at most this long for a check still in flight. A command that outlasts the check never waits for it.
const Schema = 1
Schema is the version of the on-disk state format.
The same schema is written by pyselfupdate and bashselfupdate, so any tool can read any other tool's state and one dashboard can glob ~/.local/state/*/autoupdate-*.json with no per-tool knowledge. Adding a field is safe; renaming or repurposing one breaks the other two.
Variables ¶
This section is empty.
Functions ¶
func CanonicalMachine ¶ added in v0.10.0
CanonicalMachine reduces a hostname from any source to the form Machine records.
A hostname reaches a reader fully qualified as often as bare, so a comparison against a recorded name has to canonicalize both sides or it fails on every host.
func Machine ¶ added in v0.10.0
func Machine() string
Machine identifies the box this process is running on: the bare hostname, lowercased, with any domain suffix dropped.
pyselfupdate and bashselfupdate derive it the same way, so the three write interleaved files a single reader can enumerate.
func StateFilename ¶
StateFilename is the file one machine writes inside a tool's state directory.
The machine is part of the name because a state directory is a synced directory on some installations, and Syncthing has no merge: two boxes writing one path leaves one winner plus a conflict copy nobody reads. Both fields this file carries — the version installed here and the instant this box last checked — describe one machine, so the split costs nothing and makes the collision unreachable.
Types ¶
type Config ¶
type Config struct {
// Update is the underlying update configuration. Required.
Update goselfupdate.Config
// Tool names the state directory and the per-tool environment variables.
// Defaults to Update.Binary.
Tool string
// Interval between checks. Zero means DefaultInterval.
Interval time.Duration
// Timeout bounds the check. Zero means DefaultTimeout.
Timeout time.Duration
// Out receives the one line this package is allowed to print. Defaults to
// os.Stderr.
Out io.Writer
// Interactive overrides terminal detection. Nil detects. Set it to false
// from a program that already knows it is writing somewhere a human will
// not read -- into a pager, a log, a structured-output mode -- since
// nothing about the streams themselves reveals that.
Interactive *bool
// Suppress skips the check unconditionally. Intended for a command that
// must never trigger one: an update command, a shell-completion callback
// firing on every TAB press, anything a script parses.
Suppress bool
// StateDir overrides where state is written. Defaults to [StateHome].
StateDir string
// Clock supplies the current time. Defaults to time.Now.
Clock func() time.Time
// Environ looks up an environment variable, as os.LookupEnv does.
Environ func(string) (string, bool)
}
Config describes one updatable tool.
type Outcome ¶
Outcome reports what happened. Returned for tests and dashboards, not for control flow: a caller has nothing useful to do with it.
func (Outcome) UpdateAvailable ¶
UpdateAvailable reports whether the check found a newer release.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session is an in-flight check.
func Start ¶
Start runs the gate and, if it passes, begins a check in the background.
It returns immediately and never blocks the command about to run. Call Session.Finish once that command has finished.
func (*Session) Finish ¶
Finish waits for a check still in flight, for at most Config.Timeout, then prints the notice, if there is one, and returns what happened.
It never returns an error and never panics: an update notice must not be able to break the command the user actually typed. Safe to call more than once.
type Skip ¶
type Skip string
Skip explains why a check did not happen.
func Enabled ¶
Enabled reports whether the tool checks at all, and the Skip reason when it does not, which is what explains a missing notice. It runs every step of Start's gate except the interval: it answers "is this tool opted in", not "is it due", as pyselfupdate and bashselfupdate do. It reads no clock, no state file and no network.
type State ¶
type State struct {
Schema int `json:"schema"`
Tool string `json:"tool"`
CheckedAt string `json:"checked_at"`
// CheckedAtEpoch is the same instant as CheckedAt. Redundant on purpose:
// BSD date on macOS cannot parse ISO-8601 without -j -f gymnastics, and the
// bash implementation has to do interval arithmetic with jq and date +%s
// alone. One duplicated field buys a portable bash sibling.
CheckedAtEpoch int64 `json:"checked_at_epoch"`
CurrentVersion string `json:"current_version"`
LatestVersion string `json:"latest_version"`
// LastError is non-empty when the last check failed. There is deliberately
// no separate "skip reason" field: a gate that declines to check does not
// write this file at all, which is what makes the absence of a state file
// observable proof that the network was never touched.
LastError string `json:"last_error"`
}
State is one tool's record of its last update check.
This is state, not configuration and not cache: it persists across runs, it is not authored by the user, and deleting it changes behavior rather than merely costing a recompute. That is XDG_STATE_HOME by the Base Directory specification, and it is where gh puts the same thing.