selfupdate

package
v0.1.8 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package selfupdate replaces a running program with a newer release of itself: it finds the newest release of one binary stream, downloads that platform's archive, verifies it against the release's checksums.txt, and swaps the program and its companion executables in place.

It is mechanism only. Which repository, which tag prefix, which files to install, when to check and whether to ask first are the caller's decisions, so any command-line program released the way docsync is (archives named <binary>_<version>_<os>_<arch>.tar.gz, .zip on Windows, beside a checksums.txt of sha256 sums) can use it. It imports no command framework and keeps no state of its own: the throttle file in State lives wherever the caller says.

Index

Constants

View Source
const ChecksumsFile = "checksums.txt"

ChecksumsFile is the asset every release carries, one "<sha256> <asset>" line per archive.

Variables

View Source
var (
	// ErrNoRelease means the source has no published release in the stream.
	ErrNoRelease = errors.New("no release found")
	// ErrChecksum means the archive does not match the sum the release
	// published for it; nothing is installed.
	ErrChecksum = errors.New("checksum verification failed")
	// ErrNotInArchive means the archive lacks the program being updated.
	ErrNotInArchive = errors.New("not in the release archive")
)

Errors.

Functions

func AssetName

func AssetName(binary, version, os, arch string) string

AssetName is the archive a release carries for one platform: <binary>_<version>_<os>_<arch>.tar.gz, or .zip on Windows.

func Newer

func Newer(current, latest string) bool

Newer reports whether latest is a later version than current. Either being something other than a semantic version (a development build's "(devel)") reports false: nothing can be said to be newer than a build whose version is unknown.

Types

type GitHub

type GitHub struct {
	// Repo is "owner/name".
	Repo string
	// TagPrefix selects the stream in a repository that releases several
	// things: "ds/" for tags "ds/v0.1.7". Empty for plain "v0.1.7" tags.
	TagPrefix string
	// Token, when set, authenticates API calls, which otherwise share a
	// limit of 60 an hour per address.
	Token string
	// Client is the HTTP client; nil is http.DefaultClient.
	Client *http.Client
	// Web and API are the server roots; empty means github.com.
	Web, API string
}

GitHub is a Source for one tag-prefixed stream of a GitHub repository's releases.

func (GitHub) Download

func (g GitHub) Download(ctx context.Context, rel Release, asset string) (io.ReadCloser, error)

Download opens an asset of a release.

func (GitHub) Latest

func (g GitHub) Latest(ctx context.Context) (Release, error)

Latest asks the /releases/latest redirect first: it has no rate limit and names only a published, non-prerelease release. In a repository with several streams it names whichever was marked latest, so when that is not this stream the release list is read instead, which is rate limited.

func (GitHub) Release

func (g GitHub) Release(version string) Release

Release names a version of the stream.

type Install

type Install struct {
	Source  Source
	Release Release
	// Asset is the archive to fetch, usually AssetName(...).
	Asset string
	// Dir is the directory the files are installed in, normally the one
	// holding the running program.
	Dir string
	// Main is the program's file name inside the archive. It must be there.
	Main string
	// Want reports which other archive entries to install beside Main (the
	// program's plugins). Nil installs Main alone.
	Want func(name string) bool
}

Install is one update: which release, which archive, where to.

func (Install) Run

func (in Install) Run(ctx context.Context) (Result, error)

Run downloads the archive and checksums, verifies the archive, and moves every wanted file into Dir. Nothing in Dir changes until the archive has verified and every file has been extracted beside its destination.

type Release

type Release struct {
	// Tag is the git tag, with the stream's prefix: "ds/v0.1.7".
	Tag string `json:"tag"`
	// Version is the tag without the prefix: "v0.1.7".
	Version string `json:"version"`
	// URL is the release's web page, where its notes are.
	URL string `json:"url"`
}

Release is one published release of a binary stream.

type Result

type Result struct {
	// Bytes is the archive's size.
	Bytes int64 `json:"bytes"`
	// Installed names the files written into Dir, Main first.
	Installed []string `json:"installed"`
}

Result is what an Install did.

type Source

type Source interface {
	// Latest is the newest published release of the stream.
	Latest(ctx context.Context) (Release, error)
	// Release names a version of the stream without contacting anything;
	// a version that was never released fails at Download.
	Release(version string) Release
	// Download opens one asset of a release.
	Download(ctx context.Context, rel Release, asset string) (io.ReadCloser, error)
}

Source finds and fetches releases. GitHub is the implementation; a program released elsewhere supplies its own.

type State

type State struct {
	CheckedAt time.Time `json:"checked_at"`
	Latest    string    `json:"latest,omitempty"`
	Failed    string    `json:"failed,omitempty"`
}

State is what a caller remembers between runs to check at most once per interval: when it last asked, what it was told, and which version it already failed to install (so a read-only install directory is not re-downloaded on every run).

func LoadState

func LoadState(path string) State

LoadState reads a state file. A missing or unreadable file is the zero State, which is due at once: the worst a lost file costs is one check.

func (State) Due

func (s State) Due(now time.Time, every time.Duration) bool

Due reports whether a check is owed: never checked, checked longer than every ago, or a clock that has gone backwards past the last check.

func (State) Save

func (s State) Save(path string) error

Save writes the state file, creating its directory, through a rename so two programs saving at once leave one whole file.

Jump to

Keyboard shortcuts

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