Skip to content

rtb-update

Self-update for tools built on this family: select a release, download it, verify it, swap the running binary. Registers the update command into BUILTIN_COMMANDS, gated on Feature::Update, and a pre-run hook into BUILTIN_PRERUN_HOOKS.

What it composes, and what it adds

Three existing pieces do the heavy lifting:

Piece Job
rtb-forge Release metadata and asset bytes from GitHub, GitLab, Bitbucket, Gitea, Codeberg or a direct URL
minisign-verify Signature verification
self-replace Replacing a running executable

The crate's own contribution is the flow: the order those steps run in, what is checked before each, and the guarantee that falls out of it — the binary on disk is always either the old version or the fully verified new one, never anything between. What a self-update trusts covers why that ordering is what it is.

The library API goes further than the CLI

update check and update run are thin wrappers over Updater. Three parts of the type have no CLI surface at all:

  • Updater::run_from_file — verify and swap from a locally staged archive, with no provider access. The airgap path. No subcommand calls it.
  • swap_fn and self_test_fn — builder overrides that replace the two steps which are hard to exercise for real. They are how the flow is tested end to end without a test run actually replacing the test binary.
  • cache_dir — per-invocation staging isolation, for CI runners or parallel test processes.

A tool that needs an offline install path writes a command over run_from_file rather than waiting for one.

Why check and run are separate

check fetches metadata and compares versions. It downloads no assets, verifies nothing, and cannot fail the way run can. That makes it cheap enough to run on a throttle from a pre-run hook, which is exactly what the update policy does.

CheckOutcome has three variants rather than a boolean, and the third is the interesting one. Older — the running version is newer than anything upstream reports — is almost always a tool-author mistake: a Cargo.toml version that ran ahead of the release tags, or a release source pointing at the wrong project. The updater never auto-downgrades; it reports and lets the caller decide.

Why progress is a callback

RunOptions::progress is an Option<Arc<dyn Fn(ProgressEvent) + Send + Sync>>, and None means silent. The crate prints nothing on its own.

A CLI wants lines on stderr; a TUI wants a progress bar; a library caller wants neither. Emitting events and letting the caller render them keeps all three possible without the crate knowing which one it is in. The --progress flag is just the CLI's own sink.

Where to go next