From 87ae696d7af01eb17b2cc8110a443a1a334c39cf Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Sat, 31 May 2025 12:31:16 +0400 Subject: [PATCH] refactor: make app_auto_updater use shared extraction logic --- src-tauri/src/app_auto_updater.rs | 101 ++++++++++++------------------ src-tauri/src/extraction.rs | 4 +- 2 files changed, 42 insertions(+), 63 deletions(-) diff --git a/src-tauri/src/app_auto_updater.rs b/src-tauri/src/app_auto_updater.rs index 311bbcf..f76f544 100644 --- a/src-tauri/src/app_auto_updater.rs +++ b/src-tauri/src/app_auto_updater.rs @@ -6,6 +6,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use tauri::Emitter; +use crate::extraction::Extractor; + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct AppReleaseAsset { pub name: String, @@ -370,73 +372,24 @@ impl AppAutoUpdater { Ok(file_path) } - /// Extract the update (DMG on macOS) + /// Extract the update using the extraction module async fn extract_update( &self, - dmg_path: &Path, + archive_path: &Path, dest_dir: &Path, ) -> Result> { - // For DMG files on macOS, we need to mount and copy the .app - let mount_point = dest_dir.join("mount"); - fs::create_dir_all(&mount_point)?; + let extractor = Extractor::new(); + + let extension = archive_path + .extension() + .and_then(|ext| ext.to_str()) + .unwrap_or(""); - // Mount the DMG - let output = Command::new("hdiutil") - .args([ - "attach", - "-nobrowse", - "-mountpoint", - mount_point.to_str().unwrap(), - dmg_path.to_str().unwrap(), - ]) - .output()?; - - if !output.status.success() { - return Err( - format!( - "Failed to mount DMG: {}", - String::from_utf8_lossy(&output.stderr) - ) - .into(), - ); + match extension { + "dmg" => extractor.extract_dmg(archive_path, dest_dir).await, + "zip" => extractor.extract_zip(archive_path, dest_dir).await, + _ => Err(format!("Unsupported archive format: {extension}").into()), } - - // Find the .app in the mount point - let app_entry = fs::read_dir(&mount_point)? - .filter_map(Result::ok) - .find(|entry| entry.path().extension().is_some_and(|ext| ext == "app")) - .ok_or("No .app found in DMG")?; - - let app_path = dest_dir.join("extracted_app"); - if app_path.exists() { - fs::remove_dir_all(&app_path)?; - } - - // Copy the .app to extraction directory - let output = Command::new("cp") - .args([ - "-R", - app_entry.path().to_str().unwrap(), - app_path.to_str().unwrap(), - ]) - .output()?; - - if !output.status.success() { - return Err( - format!( - "Failed to copy app: {}", - String::from_utf8_lossy(&output.stderr) - ) - .into(), - ); - } - - // Unmount the DMG - let _ = Command::new("hdiutil") - .args(["detach", mount_point.to_str().unwrap()]) - .output(); - - Ok(app_path) } /// Install the update by replacing the current app @@ -701,4 +654,30 @@ mod tests { let url = url.unwrap(); assert!(url.contains(".dmg")); } + + #[test] + fn test_extract_update_uses_extractor() { + // This test verifies that the extract_update method properly uses the Extractor + // We can't run the actual extraction in unit tests without real DMG files, + // but we can verify the method signature and basic logic + let updater = AppAutoUpdater::new(); + + // Test that unsupported formats would be rejected + let temp_dir = std::env::temp_dir(); + let unsupported_file = temp_dir.join("test.rar"); + + // Create a mock runtime to test the logic + let rt = tokio::runtime::Runtime::new().unwrap(); + + // This would fail because .rar is not supported, which proves + // our method is using the Extractor logic + let result = rt.block_on(async { + updater.extract_update(&unsupported_file, &temp_dir).await + }); + + // Should fail with unsupported format error + assert!(result.is_err()); + let error_msg = result.unwrap_err().to_string(); + assert!(error_msg.contains("Unsupported archive format: rar")); + } } diff --git a/src-tauri/src/extraction.rs b/src-tauri/src/extraction.rs index 33afbfa..a6fdffc 100644 --- a/src-tauri/src/extraction.rs +++ b/src-tauri/src/extraction.rs @@ -46,7 +46,7 @@ impl Extractor { } } - async fn extract_dmg( + pub async fn extract_dmg( &self, dmg_path: &Path, dest_dir: &Path, @@ -149,7 +149,7 @@ impl Extractor { Ok(app_path) } - async fn extract_zip( + pub async fn extract_zip( &self, zip_path: &Path, dest_dir: &Path,