From 72a4670ac54c6e5c348bc4ac6d334b0f29620652 Mon Sep 17 00:00:00 2001 From: jLynx Date: Fri, 1 Nov 2024 12:32:51 +1300 Subject: [PATCH] Added deb update support --- plugins/updater/src/error.rs | 2 ++ plugins/updater/src/updater.rs | 60 ++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/plugins/updater/src/error.rs b/plugins/updater/src/error.rs index 1f5d6a15..6f90bcfc 100644 --- a/plugins/updater/src/error.rs +++ b/plugins/updater/src/error.rs @@ -63,6 +63,8 @@ pub enum Error { TempDirNotOnSameMountPoint, #[error("binary for the current target not found in the archive")] BinaryNotFoundInArchive, + #[error("Failed to install .deb package")] + DebInstallFailed, #[error("invalid updater binary format")] InvalidUpdaterFormat, #[error(transparent)] diff --git a/plugins/updater/src/updater.rs b/plugins/updater/src/updater.rs index b1dadd6d..1396e5b9 100644 --- a/plugins/updater/src/updater.rs +++ b/plugins/updater/src/updater.rs @@ -748,7 +748,7 @@ impl Update { } } -/// Linux (AppImage) +/// Linux (AppImage and Deb) #[cfg(any( target_os = "linux", target_os = "dragonfly", @@ -760,13 +760,18 @@ impl Update { /// ### Expected structure: /// ├── [AppName]_[version]_amd64.AppImage.tar.gz # GZ generated by tauri-bundler /// │ └──[AppName]_[version]_amd64.AppImage # Application AppImage + /// ├── [AppName]_[version]_amd64.deb.tar.gz # GZ generated by tauri-bundler + /// │ └──[AppName]_[version]_amd64.deb # Debian package /// └── ... - /// - /// We should have an AppImage already installed to be able to copy and install - /// the extract_path is the current AppImage path - /// tmp_dir is where our new AppImage is found fn install_inner(&self, bytes: &[u8]) -> Result<()> { use std::os::unix::fs::{MetadataExt, PermissionsExt}; + + // Check if it's a .deb package by examining the file extension + if self.extract_path.extension() == Some(OsStr::new("deb")) { + return self.install_deb(bytes); + } + + // Existing AppImage installation logic let extract_path_metadata = self.extract_path.metadata()?; let tmp_dir_locations = vec![ @@ -797,24 +802,20 @@ impl Update { #[cfg(feature = "zip")] if infer::archive::is_gz(bytes) { // extract the buffer to the tmp_dir - // we extract our signed archive into our final directory without any temp file let archive = Cursor::new(bytes); let decoder = flate2::read::GzDecoder::new(archive); let mut archive = tar::Archive::new(decoder); for mut entry in archive.entries()?.flatten() { if let Ok(path) = entry.path() { if path.extension() == Some(OsStr::new("AppImage")) { - // if something went wrong during the extraction, we should restore previous app if let Err(err) = entry.unpack(&self.extract_path) { std::fs::rename(tmp_app_image, &self.extract_path)?; return Err(err.into()); } - // early finish we have everything we need here return Ok(()); } } } - // if we have not returned early we should restore the backup std::fs::rename(tmp_app_image, &self.extract_path)?; return Err(Error::BinaryNotFoundInArchive); } @@ -823,7 +824,6 @@ impl Update { .and_then(|_| std::fs::set_permissions(&self.extract_path, permissions)) { Err(err) => { - // if something went wrong during the extraction, we should restore previous app std::fs::rename(tmp_app_image, &self.extract_path)?; Err(err.into()) } @@ -835,6 +835,46 @@ impl Update { Err(Error::TempDirNotOnSameMountPoint) } + + fn install_deb(&self, bytes: &[u8]) -> Result<()> { + use std::process::Command; + + // Create a temporary directory to store the .deb file + let tmp_dir = tempfile::Builder::new() + .prefix("tauri_deb_update") + .tempdir()?; + + let deb_path = tmp_dir.path().join("package.deb"); + + // Write the .deb file to the temporary directory + std::fs::write(&deb_path, bytes)?; + + // First, try using pkexec (graphical sudo prompt) + let status = Command::new("pkexec") + .arg("dpkg") + .arg("-i") + .arg(&deb_path) + .status(); + + match status { + Ok(exit_status) if exit_status.success() => Ok(()), + _ => { + // If pkexec fails, try with regular sudo + // Note: This requires the user to have a terminal open + let status = Command::new("sudo") + .arg("dpkg") + .arg("-i") + .arg(&deb_path) + .status()?; + + if status.success() { + Ok(()) + } else { + Err(Error::DebInstallFailed) + } + } + } + } } /// MacOS