Files
craft-launcher/crates/native/src/self_update.rs
T
Dylan M. Taylor e2b1b73a08 refactor: delegate self-update functionality to craft-update (#871)
* refactor: delegate self_update to craft-update

* ci: point craft-update patch to dylanmtaylor/craft-libs branch

* nix: set allowBuiltinFetchGit for git dependencies

* chore(deps): update craft-update commit

* build: pin craft-update to storytold/craft-libs fe61243 and drop the temporary patch

* fix(update): share craft_update::Stop so pause and cancel reach the self-update

* build: pin craft-update to the dirs-free, zip 9 build

Satisfies cargo-deny: no MPL-2.0 option-ext, no zip 8 advisories, and a versioned git dependency instead of a wildcard.

* build: pin craft-update to craft-libs main (b9ba47f)
2026-10-25 13:40:46 -04:00

134 lines
4.9 KiB
Rust

//! ArtCraft Launcher updating itself.
//!
//! Delegated to [`craft_update::self_update`].
use std::ffi::OsString;
use artcraft_launcher_core::platform::Platform;
use artcraft_launcher_core::protocol::JobPhase;
use artcraft_launcher_core::release::Release;
use artcraft_launcher_core::version::Version;
use crate::http::{Http, Stop};
use crate::paths::Paths;
pub use craft_update::self_update::{FINISH_FLAG, Install, PRETEND_VAR, is_self_updating};
/// The version this launcher counts as (see [`PRETEND_VAR`]).
pub fn current_version() -> Option<Version> {
craft_update::self_update::current_version(&craft_update::suite::LAUNCHER, env!("CARGO_PKG_VERSION"))
}
/// How this copy is installed, if it's one the launcher knows how to replace.
pub fn current() -> Option<Install> {
craft_update::self_update::current(&craft_update::suite::LAUNCHER)
}
fn to_update_paths(paths: &Paths) -> craft_update::Paths {
craft_update::Paths { data: paths.data.clone(), cache: paths.cache.clone() }
}
fn to_update_release(release: &Release) -> craft_update::Release {
craft_update::Release {
tag: release.tag.clone(),
version: release.version.clone(),
name: release.name.clone(),
published_at: release.published_at,
html_url: release.html_url.clone(),
notes: release.notes.clone(),
prerelease: release.prerelease,
assets: release
.assets
.iter()
.map(|a| craft_update::Asset { name: a.name.clone(), size: a.size, url: a.url.clone(), sha256: a.sha256.clone() })
.collect(),
}
}
fn to_update_platform(platform: Platform) -> craft_update::Platform {
craft_update::Platform {
os: match platform.os {
artcraft_launcher_core::Os::Windows => craft_update::Os::Windows,
artcraft_launcher_core::Os::MacOs => craft_update::Os::MacOs,
artcraft_launcher_core::Os::Linux => craft_update::Os::Linux,
artcraft_launcher_core::Os::FreeBsd => craft_update::Os::FreeBsd,
},
arch: match platform.arch {
artcraft_launcher_core::Arch::X64 => craft_update::Arch::X64,
artcraft_launcher_core::Arch::Arm64 => craft_update::Arch::Arm64,
artcraft_launcher_core::Arch::X86 => craft_update::Arch::X86,
artcraft_launcher_core::Arch::Riscv64 => craft_update::Arch::Riscv64,
},
}
}
/// Whether `release` is the version this launcher just updated itself to.
pub fn just_updated_to(paths: &Paths, release: &Release) -> bool {
let update_paths = to_update_paths(paths);
let update_release = to_update_release(release);
craft_update::self_update::just_updated_to(&update_paths, &update_release)
}
/// The error of the last update, if it failed, once.
pub fn take_failure(paths: &Paths) -> Option<String> {
let update_paths = to_update_paths(paths);
craft_update::self_update::take_failure(&update_paths)
}
/// Downloads `release` for `platform`, puts it in place and starts the helper that relaunches
/// it once this process has exited. On success the caller must quit promptly. `last` is called
/// once the download is ready and returns when the launcher may replace itself and restart.
#[allow(clippy::too_many_arguments)]
pub fn update(
install: &Install,
release: &Release,
platform: Platform,
_http: &Http,
paths: &Paths,
stop: &Stop,
phase: &mut dyn FnMut(JobPhase),
last: &dyn Fn() -> Result<(), String>,
) -> Result<(), String> {
let update_release = to_update_release(release);
let update_platform = to_update_platform(platform);
let update_paths = to_update_paths(paths);
let update_http = craft_update::Http::new("ArtCraft-Launcher/SelfUpdate")?;
let mut update_phase = |p: craft_update::JobPhase| {
phase(match p {
craft_update::JobPhase::Downloading { done, total } => JobPhase::Downloading { done, total },
craft_update::JobPhase::Reconnecting { done, total } => JobPhase::Reconnecting { done, total },
craft_update::JobPhase::Waiting => JobPhase::Waiting,
craft_update::JobPhase::Verifying => JobPhase::Verifying,
craft_update::JobPhase::Installing => JobPhase::Installing,
craft_update::JobPhase::Removing => JobPhase::Removing,
});
};
craft_update::self_update::update(
&craft_update::suite::LAUNCHER,
install,
&update_release,
update_platform,
&update_http,
&update_paths,
stop,
&mut update_phase,
last,
Some(env!("CARGO_PKG_VERSION")),
)
}
/// Finishes an update when this program was started as the update helper.
pub fn finish(args: &[OsString]) -> Option<Result<(), String>> {
craft_update::self_update::finish(&craft_update::suite::LAUNCHER, args)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_development_build_does_not_update_itself() {
assert_eq!(current(), None);
}
}