Expand description
Self-contained, in-place self-updates for Rust applications.
update-rs lets a Rust application replace its own binary on disk with a
newer release and relaunch into it — without an installer, package manager,
or external updater process. It was extracted from the Sierra Softworks
Git-Tool project, where it
powers the gt update command.
§The three-phase update
A running executable can’t reliably overwrite itself (Windows holds an exclusive lock on a running image), so the update is performed across three phases, each running from a different binary and relaunching the next:
- Prepare — the running application downloads the new release to a temporary file next to it, marks it executable (on Unix), and launches that temporary binary to perform the next phase.
- Replace — the temporary binary deletes the original application file and copies itself over it (retrying while the old process exits), then launches the freshly replaced original.
- Cleanup — the updated original deletes the leftover temporary binary and returns control to the application.
The phases are threaded together by relaunching the binary with
RESUME_FLAG followed by a serialized UpdateState. This design is
described in more detail in
Building self-updating applications.
§Quick start
Build an UpdateManager around a Source (the crate ships
GitHubSource), detect the RESUME_FLAG before any other argument
parsing, and otherwise offer the newest release. The asset to download is
chosen by a glob pattern; the naming helpers build one for the current
platform.
use update_rs::{naming, GitHubSource, Release, UpdateManager, RESUME_FLAG};
#[tokio::main]
async fn main() -> Result<(), update_rs::Error> {
let manager = UpdateManager::new(
// e.g. matches "yourapp-linux-amd64", "yourapp-windows-amd64.exe", ...
GitHubSource::new("yourorg/yourapp", naming::go("yourapp"))
.with_release_tag_prefix("v"), // strips the leading v in vX.Y.Z tags
);
// The updater relaunches your application between phases, passing the
// serialized update state after `RESUME_FLAG`. Detect it first and hand
// control back to the library.
let args: Vec<String> = std::env::args().collect();
if let Some(i) = args.iter().position(|a| a == RESUME_FLAG) {
if manager.resume_from_arg(&args[i + 1]).await? {
return Ok(()); // a phase was launched; exit so it can take over
}
}
// Otherwise, look for the newest release with a binary for this platform.
let releases = manager.get_releases().await?;
let latest = Release::get_latest(releases.iter().filter(|r| r.get_variant().is_some()));
if let Some(latest) = latest {
if manager.update(latest).await? {
println!("Shutting down to complete the update.");
return Ok(()); // exit promptly so the new binary can take over
}
}
// ... your normal application logic ...
Ok(())
}§Selecting the release asset
GitHubSource::new takes a glob pattern (* and ? wildcards) that is
matched against each release’s asset file names, so your project can name its
assets however it likes. Build the pattern by hand —
format!("yourapp-{OS}-{ARCH}{EXE_SUFFIX}") using std::env::consts — or
with a naming helper: naming::go for Go-style names
(yourapp-linux-amd64) or naming::rust for the Rust target triple
(yourapp-x86_64-unknown-linux-gnu).
§Windows: avoiding UAC / Error 740
Because the temporary binary is named like yourapp-<tag>.exe, Windows’
installer-detection heuristic can decide it’s an installer and demand UAC
elevation — which fails the relaunch with ERROR_ELEVATION_REQUIRED
(Win32 error 740). The fix is to ship your binary with an asInvoker
application manifest. This is a property of the consuming binary (a library
can’t embed a manifest), so update-rs ships a ready-to-copy build.rs and
manifest template under examples/windows-manifest/; see the project README
for details.
Modules§
- naming
- Helpers for building release-asset name patterns for the current platform.
Structs§
- Error
- The fundamental error type used by this library.
- GitHub
Source - A
Sourcewhich lists and downloads releases from a GitHub repository’s releases API. - Release
- A single release published by a
Source, along with the binary (variant) selected for it by the source’s configured asset selection. - Release
Variant - A downloadable binary belonging to a
Release— a single release asset. - Update
Manager - Drives the three-phase, in-place self-update of an application binary.
- Update
State - The serializable state which is threaded through the three phases of an
update by relaunching the application with the
RESUME_FLAGfollowed by this value as JSON.
Enums§
- Update
Phase - The phase of the three-phase update process which an
UpdateStateis in.
Constants§
- RESUME_
FLAG - The command-line flag the library uses to relaunch the consuming binary between update phases.
- TARGET
- The Rust target triple this crate was compiled for (e.g.
x86_64-unknown-linux-gnu), captured at build time. Used bynaming::rustto build release asset names.
Traits§
- Source
- A source of application releases which the
UpdateManagercan list and download binaries from.