diff --git a/plugins/updater/src/updater.rs b/plugins/updater/src/updater.rs index 526acd49..bf86816d 100644 --- a/plugins/updater/src/updater.rs +++ b/plugins/updater/src/updater.rs @@ -840,15 +840,9 @@ impl Update { /// MacOS #[cfg(target_os = "macos")] impl Update { - /// ### Expected structure: - /// ├── [AppName]_[version]_x64.app.tar.gz # GZ generated by tauri-bundler - /// │ └──[AppName].app # Main application - /// │ └── Contents # Application contents... - /// │ └── ... - /// └── ... fn install_inner(&self, bytes: &[u8]) -> Result<()> { use flate2::read::GzDecoder; - + let cursor = Cursor::new(bytes); let mut extracted_files: Vec = Vec::new(); @@ -856,45 +850,40 @@ impl Update { let tmp_backup_dir = tempfile::Builder::new() .prefix("tauri_current_app") .tempdir()?; - + let tmp_extract_dir = tempfile::Builder::new() .prefix("tauri_updated_app") - .tempdir()? - .into_path(); + .tempdir()?; let decoder = GzDecoder::new(cursor); let mut archive = tar::Archive::new(decoder); - std::fs::create_dir(&tmp_extract_dir)?; - // Extract files to temporary directory for entry in archive.entries()? { let mut entry = entry?; let collected_path: PathBuf = entry.path()?.iter().skip(1).collect(); - let extraction_path = tmp_extract_dir.join(&collected_path); + let extraction_path = tmp_extract_dir.path().join(&collected_path); + + // Ensure parent directories exist + if let Some(parent) = extraction_path.parent() { + std::fs::create_dir_all(parent)?; + } if let Err(err) = entry.unpack(&extraction_path) { // Cleanup on error - for file in &extracted_files { - if file.is_dir() { - std::fs::remove_dir(file)?; - } else { - std::fs::remove_file(file)?; - } - } - std::fs::remove_dir_all(&tmp_extract_dir).ok(); + std::fs::remove_dir_all(tmp_extract_dir.path()).ok(); return Err(err.into()); } extracted_files.push(extraction_path); } // Try to move the current app to backup - let move_result = std::fs::rename(&self.extract_path, tmp_backup_dir.path()); + let move_result = std::fs::rename(&self.extract_path, tmp_backup_dir.path().join("current_app")); let need_authorization = if let Err(err) = move_result { if err.kind() == std::io::ErrorKind::PermissionDenied { true } else { - std::fs::remove_dir_all(&tmp_extract_dir).ok(); + std::fs::remove_dir_all(tmp_extract_dir.path()).ok(); return Err(err.into()); } } else { @@ -904,26 +893,29 @@ impl Update { if need_authorization { // Use AppleScript to perform moves with admin privileges let script = format!( - "do shell script \"mv -f '{src}' '{backup}' && mv -f '{new}' '{src}'\" with administrator privileges", + "do shell script \"rm -rf '{src}' && mv -f '{new}' '{src}'\" with administrator privileges", src = self.extract_path.display(), - backup = tmp_backup_dir.path().display(), - new = tmp_extract_dir.display() + new = tmp_extract_dir.path().display() ); - + let mut osascript = std::process::Command::new("osascript"); osascript.arg("-e").arg(script); - + let status = osascript.status()?; if !status.success() { - std::fs::remove_dir_all(&tmp_extract_dir).ok(); + std::fs::remove_dir_all(tmp_extract_dir.path()).ok(); return Err(Error::Io(std::io::Error::new( std::io::ErrorKind::PermissionDenied, "Failed to move the new app into place", ))); } } else { - // Move the new app to the target path if we didn't need admin rights - std::fs::rename(&tmp_extract_dir, &self.extract_path)?; + // Remove existing directory if it exists + if self.extract_path.exists() { + std::fs::remove_dir_all(&self.extract_path)?; + } + // Move the new app to the target path + std::fs::rename(tmp_extract_dir.path(), &self.extract_path)?; } let _ = std::process::Command::new("touch")