瀏覽代碼

fix(bundler/macos): clean up .app bundle if only .dmg is enabled #7081 (#7116)

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
fcfangcc 2 年之前
父節點
當前提交
3327dd641d

+ 5 - 0
.changes/cleanup-app-bundle.md

@@ -0,0 +1,5 @@
+---
+"tauri-bundler": patch
+---
+
+Remove macOS app bundles from the output if they are not requested by the user.

+ 45 - 2
tooling/bundler/src/bundle.rs

@@ -24,6 +24,8 @@ pub use self::{
     Settings, SettingsBuilder, UpdaterSettings,
   },
 };
+#[cfg(target_os = "macos")]
+use anyhow::Context;
 use log::{info, warn};
 pub use settings::{NsisSettings, WindowsSettings, WixLanguage, WixLanguageConfig, WixSettings};
 
@@ -41,7 +43,7 @@ pub struct Bundle {
 /// Bundles the project.
 /// Returns the list of paths where the bundles can be found.
 pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
-  let mut bundles = Vec::new();
+  let mut bundles: Vec<Bundle> = Vec::new();
   let package_types = settings.package_types()?;
 
   let target_os = settings
@@ -56,6 +58,11 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
   }
 
   for package_type in &package_types {
+    // bundle was already built! e.g. DMG already built .app
+    if bundles.iter().any(|b| b.package_type == *package_type) {
+      continue;
+    }
+
     let bundle_paths = match package_type {
       #[cfg(target_os = "macos")]
       PackageType::MacOsBundle => macos::app::bundle_project(&settings)?,
@@ -63,7 +70,16 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
       PackageType::IosBundle => macos::ios::bundle_project(&settings)?,
       // dmg is dependant of MacOsBundle, we send our bundles to prevent rebuilding
       #[cfg(target_os = "macos")]
-      PackageType::Dmg => macos::dmg::bundle_project(&settings, &bundles)?,
+      PackageType::Dmg => {
+        let bundled = macos::dmg::bundle_project(&settings, &bundles)?;
+        if !bundled.app.is_empty() {
+          bundles.push(Bundle {
+            package_type: PackageType::MacOsBundle,
+            bundle_paths: bundled.app,
+          });
+        }
+        bundled.dmg
+      }
 
       #[cfg(target_os = "windows")]
       PackageType::WindowsMsi => windows::msi::bundle_project(&settings, false)?,
@@ -90,6 +106,33 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
     });
   }
 
+  #[cfg(target_os = "macos")]
+  {
+    // Clean up .app if only building dmg or updater
+    if !package_types.contains(&PackageType::MacOsBundle) {
+      if let Some(app_bundle_paths) = bundles
+        .iter()
+        .position(|b| b.package_type == PackageType::MacOsBundle)
+        .map(|i| bundles.remove(i))
+        .map(|b| b.bundle_paths)
+      {
+        for app_bundle_path in &app_bundle_paths {
+          info!(action = "Cleaning"; "{}", app_bundle_path.display());
+          match app_bundle_path.is_dir() {
+            true => std::fs::remove_dir_all(app_bundle_path),
+            false => std::fs::remove_file(app_bundle_path),
+          }
+          .with_context(|| {
+            format!(
+              "Failed to clean the app bundle at {}",
+              app_bundle_path.display()
+            )
+          })?
+        }
+      }
+    }
+  }
+
   let pluralised = if bundles.len() == 1 {
     "bundle"
   } else {

+ 3 - 3
tooling/bundler/src/bundle/macos/app.rs

@@ -219,7 +219,7 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
     return Ok(());
   }
   let dest_dir = bundle_directory.join("Frameworks");
-  fs::create_dir_all(&bundle_directory)
+  fs::create_dir_all(bundle_directory)
     .with_context(|| format!("Failed to create Frameworks directory at {:?}", dest_dir))?;
   for framework in frameworks.iter() {
     if framework.ends_with(".framework") {
@@ -227,7 +227,7 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
       let src_name = src_path
         .file_name()
         .expect("Couldn't get framework filename");
-      common::copy_dir(&src_path, &dest_dir.join(&src_name))?;
+      common::copy_dir(&src_path, &dest_dir.join(src_name))?;
       continue;
     } else if framework.ends_with(".dylib") {
       let src_path = PathBuf::from(framework);
@@ -238,7 +238,7 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
         )));
       }
       let src_name = src_path.file_name().expect("Couldn't get library filename");
-      common::copy_file(&src_path, &dest_dir.join(&src_name))?;
+      common::copy_file(&src_path, &dest_dir.join(src_name))?;
       continue;
     } else if framework.contains('/') {
       return Err(crate::Error::GenericError(format!(

+ 18 - 10
tooling/bundler/src/bundle/macos/dmg.rs

@@ -6,8 +6,7 @@
 use super::{app, icon::create_icns_file};
 use crate::{
   bundle::{common::CommandExt, Bundle},
-  PackageType::MacOsBundle,
-  Settings,
+  PackageType, Settings,
 };
 
 use anyhow::Context;
@@ -20,18 +19,23 @@ use std::{
   process::{Command, Stdio},
 };
 
+pub struct Bundled {
+  pub dmg: Vec<PathBuf>,
+  pub app: Vec<PathBuf>,
+}
+
 /// Bundles the project.
 /// Returns a vector of PathBuf that shows where the DMG was created.
-pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result<Vec<PathBuf>> {
+pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result<Bundled> {
   // generate the .app bundle if needed
-  if bundles
+  let app_bundle_paths = if !bundles
     .iter()
-    .filter(|bundle| bundle.package_type == MacOsBundle)
-    .count()
-    == 0
+    .any(|bundle| bundle.package_type == PackageType::MacOsBundle)
   {
-    app::bundle_project(settings)?;
-  }
+    app::bundle_project(settings)?
+  } else {
+    Vec::new()
+  };
 
   // get the target path
   let output_path = settings.project_out_directory().join("bundle/dmg");
@@ -151,5 +155,9 @@ pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result<
   if let Some(identity) = &settings.macos().signing_identity {
     super::sign::sign(dmg_path.clone(), identity, settings, false)?;
   }
-  Ok(vec![dmg_path])
+
+  Ok(Bundled {
+    dmg: vec![dmg_path],
+    app: app_bundle_paths,
+  })
 }

+ 5 - 9
tooling/bundler/src/bundle/macos/sign.rs

@@ -288,7 +288,7 @@ pub fn notarize(
     info!("notarization started; waiting for Apple response...");
 
     let uuid = uuid[1].to_string();
-    get_notarization_status(uuid, auth_args, settings)?;
+    get_notarization_status(uuid, auth_args)?;
     staple_app(app_bundle_path.clone())?;
   } else {
     return Err(
@@ -322,11 +322,7 @@ fn staple_app(mut app_bundle_path: PathBuf) -> crate::Result<()> {
   Ok(())
 }
 
-fn get_notarization_status(
-  uuid: String,
-  auth_args: Vec<String>,
-  settings: &Settings,
-) -> crate::Result<()> {
+fn get_notarization_status(uuid: String, auth_args: Vec<String>) -> crate::Result<()> {
   std::thread::sleep(std::time::Duration::from_secs(10));
   let result = Command::new("xcrun")
     .args(vec!["altool", "--notarization-info", &uuid])
@@ -345,7 +341,7 @@ fn get_notarization_status(
     {
       let status = status[1].to_string();
       if status == "in progress" {
-        get_notarization_status(uuid, auth_args, settings)
+        get_notarization_status(uuid, auth_args)
       } else if status == "invalid" {
         Err(
           anyhow::anyhow!(format!(
@@ -366,10 +362,10 @@ fn get_notarization_status(
         Ok(())
       }
     } else {
-      get_notarization_status(uuid, auth_args, settings)
+      get_notarization_status(uuid, auth_args)
     }
   } else {
-    get_notarization_status(uuid, auth_args, settings)
+    get_notarization_status(uuid, auth_args)
   }
 }