Added deb update support

pull/1991/head
jLynx 9 months ago
parent fd785ab5de
commit 72a4670ac5

@ -63,6 +63,8 @@ pub enum Error {
TempDirNotOnSameMountPoint, TempDirNotOnSameMountPoint,
#[error("binary for the current target not found in the archive")] #[error("binary for the current target not found in the archive")]
BinaryNotFoundInArchive, BinaryNotFoundInArchive,
#[error("Failed to install .deb package")]
DebInstallFailed,
#[error("invalid updater binary format")] #[error("invalid updater binary format")]
InvalidUpdaterFormat, InvalidUpdaterFormat,
#[error(transparent)] #[error(transparent)]

@ -748,7 +748,7 @@ impl Update {
} }
} }
/// Linux (AppImage) /// Linux (AppImage and Deb)
#[cfg(any( #[cfg(any(
target_os = "linux", target_os = "linux",
target_os = "dragonfly", target_os = "dragonfly",
@ -760,13 +760,18 @@ impl Update {
/// ### Expected structure: /// ### Expected structure:
/// ├── [AppName]_[version]_amd64.AppImage.tar.gz # GZ generated by tauri-bundler /// ├── [AppName]_[version]_amd64.AppImage.tar.gz # GZ generated by tauri-bundler
/// │ └──[AppName]_[version]_amd64.AppImage # Application AppImage /// │ └──[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<()> { fn install_inner(&self, bytes: &[u8]) -> Result<()> {
use std::os::unix::fs::{MetadataExt, PermissionsExt}; 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 extract_path_metadata = self.extract_path.metadata()?;
let tmp_dir_locations = vec![ let tmp_dir_locations = vec![
@ -797,24 +802,20 @@ impl Update {
#[cfg(feature = "zip")] #[cfg(feature = "zip")]
if infer::archive::is_gz(bytes) { if infer::archive::is_gz(bytes) {
// extract the buffer to the tmp_dir // 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 archive = Cursor::new(bytes);
let decoder = flate2::read::GzDecoder::new(archive); let decoder = flate2::read::GzDecoder::new(archive);
let mut archive = tar::Archive::new(decoder); let mut archive = tar::Archive::new(decoder);
for mut entry in archive.entries()?.flatten() { for mut entry in archive.entries()?.flatten() {
if let Ok(path) = entry.path() { if let Ok(path) = entry.path() {
if path.extension() == Some(OsStr::new("AppImage")) { 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) { if let Err(err) = entry.unpack(&self.extract_path) {
std::fs::rename(tmp_app_image, &self.extract_path)?; std::fs::rename(tmp_app_image, &self.extract_path)?;
return Err(err.into()); return Err(err.into());
} }
// early finish we have everything we need here
return Ok(()); return Ok(());
} }
} }
} }
// if we have not returned early we should restore the backup
std::fs::rename(tmp_app_image, &self.extract_path)?; std::fs::rename(tmp_app_image, &self.extract_path)?;
return Err(Error::BinaryNotFoundInArchive); return Err(Error::BinaryNotFoundInArchive);
} }
@ -823,7 +824,6 @@ impl Update {
.and_then(|_| std::fs::set_permissions(&self.extract_path, permissions)) .and_then(|_| std::fs::set_permissions(&self.extract_path, permissions))
{ {
Err(err) => { Err(err) => {
// if something went wrong during the extraction, we should restore previous app
std::fs::rename(tmp_app_image, &self.extract_path)?; std::fs::rename(tmp_app_image, &self.extract_path)?;
Err(err.into()) Err(err.into())
} }
@ -835,6 +835,46 @@ impl Update {
Err(Error::TempDirNotOnSameMountPoint) 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 /// MacOS

Loading…
Cancel
Save