feat(update): one-click desktop self-update (AppImage, .deb, Windows)
update_apply used to flatly refuse to run for the GUI binary and point
the user to a manual download instead. Since both desktop apps already
elevate to root/administrator before showing their window, the
process applying the update already has everything it needs — no
second authentication round is required.
- New guara_core::update::apply_desktop[_with_progress], alongside the
existing CLI-only apply() (left untouched): detects the install kind
at runtime (AppImage via the APPIMAGE env var — current_exe() is
unreliable there, same FUSE-mount issue elevated_exe() already works
around and this reuses; Deb otherwise on Linux; WindowsInstaller on
Windows), matches the right release asset by the GUI bundle naming
(_amd64/_aarch64.AppImage, _amd64/_arm64.deb, _x64-setup.exe — a
different suffix convention than the CLI tarballs), verifies SHA-256
when a sidecar is published, and installs:
- AppImage: downloads to a temp file in the same directory (same
filesystem, atomic rename), renames over the running file, execs
it in place (same PID, same already-root privileges — no elevation
dance needed).
- .deb: runs `dpkg -i` directly (already root), then execs
current_exe() again now that dpkg replaced it on disk.
- Windows: runs the downloaded installer with /S (silent) detached,
then exits immediately to release the file lock on our own .exe.
Does NOT claim to relaunch the app afterwards — there is no
documented NSIS or Tauri flag for that (verified against NSIS's
and Tauri's own docs: Tauri's own updater restarts the app from its
own Rust code after the installer exits, not via a command-line
switch), and blocking here on the installer's exit status risks a
self-deadlock if its script waits for this process to close before
it can overwrite the running .exe. Needs a real Windows machine to
confirm the actual post-install behavior.
- Engine::update_apply_desktop wires it into the Tauri `update_apply`
command, which now also takes AppHandle and emits `update-progress`
events (downloading/verifying/installing/restarting) for the UI.
- Sabiá: the existing #btnUpdate handler changed the button's label to
"update to X" but never actually called apply — wired it for real,
with the same progress feedback.
- Guará: restored the "Update now" action in the update card (removed
during the updater-unification migration), wired to the new command.
- scripts/build-gui.sh: generates a .sha256 next to every file in
dist-gui/, matching the existing convention for CLI release
archives, so apply_desktop can verify downloads the same way CLI
update --apply already does.
- 3 new unit tests per repo: install-kind detection, GUI asset suffix
matching against real release naming, and the existing CLI-refusal
test still passes unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
This commit is contained in:
1 parent
21eb4eafae
commit
cdda2bc45f
6 files changed
+424
-7
No files matched your search
@@ -28,8 +28,19 @@ fn update_check(state: tauri::State<'_, State>) -> Result<serde_json::Value, Str
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn update_apply(state: tauri::State<'_, State>) -> Result<String, String> {
|
||||
state.0.update_apply().map_err(|e| e.to_string())
|
||||
fn update_apply(app: tauri::AppHandle, state: tauri::State<'_, State>) -> Result<String, String> {
|
||||
use tauri::Emitter;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
let exe = elevated_exe().unwrap_or_else(|_| std::env::current_exe().unwrap_or_default());
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
let exe = std::env::current_exe().unwrap_or_default();
|
||||
|
||||
state
|
||||
.0
|
||||
.update_apply_desktop(&exe, move |phase| {
|
||||
let _ = app.emit("update-progress", serde_json::json!({ "phase": phase }));
|
||||
})
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// `true` when the process already has sufficient privileges to read raw disks.
|
||||
|
||||
Reference in new issue
Block a user