Ver Fonte

refactor(bundler): use the `plist` crate to create and merge Info.plist (#4412)

Lucas Fernandes Nogueira há 3 anos atrás
pai
commit
45076b3ede

+ 5 - 0
.changes/refactor-bundler-plist.md

@@ -0,0 +1,5 @@
+---
+"tauri-bundler": patch
+---
+
+Use the plist crate instead of the `PlistBuddy` binary to merge user Info.plist file.

+ 1 - 0
tooling/bundler/Cargo.toml

@@ -51,6 +51,7 @@ zip = "0.6"
 [target."cfg(target_os = \"macos\")".dependencies]
 icns = "0.3"
 time = { version = "0.3", features = [ "formatting" ] }
+plist = "1"
 
 [target."cfg(any(target_os = \"macos\", target_os = \"windows\"))".dependencies]
 regex = "1"

+ 57 - 114
tooling/bundler/src/bundle/macos/app.rs

@@ -26,16 +26,14 @@ use super::{
   icon::create_icns_file,
   sign::{notarize, notarize_auth_args, sign},
 };
-use crate::{bundle::common::CommandExt, Settings};
+use crate::Settings;
 
 use anyhow::Context;
 use log::{info, warn};
 
 use std::{
   fs,
-  io::prelude::*,
   path::{Path, PathBuf},
-  process::Command,
 };
 
 /// Bundles the project.
@@ -124,130 +122,75 @@ fn create_info_plist(
     .format(&format)
     .map_err(time::error::Error::from)?;
 
-  let bundle_plist_path = bundle_dir.join("Info.plist");
-  let file = &mut common::create_file(&bundle_plist_path)?;
-  write!(
-    file,
-    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-     <!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \
-     \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\
-     <plist version=\"1.0\">\n\
-     <dict>\n"
-  )?;
-  write!(
-    file,
-    "  <key>CFBundleDevelopmentRegion</key>\n  \
-     <string>English</string>\n"
-  )?;
-  write!(
-    file,
-    "  <key>CFBundleDisplayName</key>\n  <string>{}</string>\n",
-    settings.product_name()
-  )?;
-  write!(
-    file,
-    "  <key>CFBundleExecutable</key>\n  <string>{}</string>\n",
-    settings.main_binary_name()
-  )?;
+  let mut plist = plist::Dictionary::new();
+  plist.insert("CFBundleDevelopmentRegion".into(), "English".into());
+  plist.insert("CFBundleDisplayName".into(), settings.product_name().into());
+  plist.insert(
+    "CFBundleExecutable".into(),
+    settings.main_binary_name().into(),
+  );
   if let Some(path) = bundle_icon_file {
-    write!(
-      file,
-      "  <key>CFBundleIconFile</key>\n  <string>{}</string>\n",
-      path.file_name().expect("No file name").to_string_lossy()
-    )?;
+    plist.insert(
+      "CFBundleIconFile".into(),
+      path
+        .file_name()
+        .expect("No file name")
+        .to_string_lossy()
+        .into_owned()
+        .into(),
+    );
   }
-  write!(
-    file,
-    "  <key>CFBundleIdentifier</key>\n  <string>{}</string>\n",
-    settings.bundle_identifier()
-  )?;
-  write!(
-    file,
-    "  <key>CFBundleInfoDictionaryVersion</key>\n  \
-     <string>6.0</string>\n"
-  )?;
-  write!(
-    file,
-    "  <key>CFBundleName</key>\n  <string>{}</string>\n",
-    settings.product_name()
-  )?;
-  write!(
-    file,
-    "  <key>CFBundlePackageType</key>\n  <string>APPL</string>\n"
-  )?;
-  write!(
-    file,
-    "  <key>CFBundleShortVersionString</key>\n  <string>{}</string>\n",
-    settings.version_string()
-  )?;
-  write!(
-    file,
-    "  <key>CFBundleVersion</key>\n  <string>{}</string>\n",
-    build_number
-  )?;
-  write!(file, "  <key>CSResourcesFileMapped</key>\n  <true/>\n")?;
+  plist.insert(
+    "CFBundleIdentifier".into(),
+    settings.bundle_identifier().into(),
+  );
+  plist.insert("CFBundleInfoDictionaryVersion".into(), "6.0".into());
+  plist.insert("CFBundleName".into(), settings.product_name().into());
+  plist.insert("CFBundlePackageType".into(), "APPL".into());
+  plist.insert(
+    "CFBundleShortVersionString".into(),
+    settings.version_string().into(),
+  );
+  plist.insert("CFBundleVersion".into(), build_number.into());
+  plist.insert("CSResourcesFileMapped".into(), true.into());
   if let Some(category) = settings.app_category() {
-    write!(
-      file,
-      "  <key>LSApplicationCategoryType</key>\n  \
-       <string>{}</string>\n",
-      category.macos_application_category_type()
-    )?;
+    plist.insert(
+      "LSApplicationCategoryType".into(),
+      category.macos_application_category_type().into(),
+    );
   }
-  if let Some(version) = &settings.macos().minimum_system_version {
-    write!(
-      file,
-      "  <key>LSMinimumSystemVersion</key>\n  \
-       <string>{}</string>\n",
-      version
-    )?;
+  if let Some(version) = settings.macos().minimum_system_version.clone() {
+    plist.insert("LSMinimumSystemVersion".into(), version.into());
   }
-  write!(file, "  <key>LSRequiresCarbon</key>\n  <true/>\n")?;
-  write!(file, "  <key>NSHighResolutionCapable</key>\n  <true/>\n")?;
+  plist.insert("LSRequiresCarbon".into(), true.into());
+  plist.insert("NSHighResolutionCapable".into(), true.into());
   if let Some(copyright) = settings.copyright_string() {
-    write!(
-      file,
-      "  <key>NSHumanReadableCopyright</key>\n  \
-       <string>{}</string>\n",
-      copyright
-    )?;
+    plist.insert("NSHumanReadableCopyright".into(), copyright.into());
   }
 
-  if let Some(exception_domain) = &settings.macos().exception_domain {
-    write!(
-      file,
-      "  <key>NSAppTransportSecurity</key>\n  \
-      <dict>\n  \
-          <key>NSExceptionDomains</key>\n  \
-          <dict>\n  \
-              <key>{}</key>\n  \
-              <dict>\n  \
-                  <key>NSExceptionAllowsInsecureHTTPLoads</key>\n  \
-                  <true/>\n  \
-                  <key>NSIncludesSubdomains</key>\n  \
-                  <true/>\n  \
-              </dict>\n  \
-          </dict>\n  \
-      </dict>",
-      exception_domain
-    )?;
-  }
+  if let Some(exception_domain) = settings.macos().exception_domain.clone() {
+    let mut security = plist::Dictionary::new();
+    let mut domain = plist::Dictionary::new();
+    domain.insert("NSExceptionAllowsInsecureHTTPLoads".into(), true.into());
+    domain.insert("NSIncludesSubdomains".into(), true.into());
 
-  write!(file, "</dict>\n</plist>\n")?;
-  file.flush()?;
+    let mut exception_domains = plist::Dictionary::new();
+    exception_domains.insert(exception_domain, domain.into());
+    security.insert("NSExceptionDomains".into(), exception_domains.into());
+    plist.insert("NSAppTransportSecurity".into(), security.into());
+  }
 
   if let Some(user_plist_path) = &settings.macos().info_plist_path {
-    // TODO: use the plist crate instead
-    Command::new("/usr/libexec/PlistBuddy")
-      .args(&[
-        "-c".into(),
-        format!("Merge {}", user_plist_path.display()),
-        bundle_plist_path.display().to_string(),
-      ])
-      .output_ok()
-      .context("error running PlistBuddy")?;
+    let user_plist = plist::Value::from_file(user_plist_path)?;
+    if let Some(dict) = user_plist.into_dictionary() {
+      for (key, value) in dict {
+        plist.insert(key, value);
+      }
+    }
   }
 
+  plist::Value::Dictionary(plist).to_file_xml(bundle_dir.join("Info.plist"))?;
+
   Ok(())
 }
 

+ 4 - 0
tooling/bundler/src/error.rs

@@ -106,6 +106,10 @@ pub enum Error {
   #[cfg(target_os = "macos")]
   #[error("`{0}`")]
   TimeError(#[from] time::error::Error),
+  /// Plist error.
+  #[cfg(target_os = "macos")]
+  #[error(transparent)]
+  Plist(#[from] plist::Error),
 }
 
 /// Convenient type alias of Result type.

+ 36 - 0
tooling/cli/Cargo.lock

@@ -1325,6 +1325,15 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "line-wrap"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
+dependencies = [
+ "safemem",
+]
+
 [[package]]
 name = "lock_api"
 version = "0.4.7"
@@ -1972,6 +1981,20 @@ version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
 
+[[package]]
+name = "plist"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225"
+dependencies = [
+ "base64",
+ "indexmap",
+ "line-wrap",
+ "serde",
+ "time 0.3.9",
+ "xml-rs",
+]
+
 [[package]]
 name = "png"
 version = "0.16.8"
@@ -2287,6 +2310,12 @@ version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
 
+[[package]]
+name = "safemem"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+
 [[package]]
 name = "salsa20"
 version = "0.9.0"
@@ -2706,6 +2735,7 @@ dependencies = [
  "libflate",
  "log",
  "md5",
+ "plist",
  "regex",
  "serde",
  "serde_json",
@@ -3388,6 +3418,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "xml-rs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
+
 [[package]]
 name = "zeroize"
 version = "1.5.5"

+ 1 - 1
tooling/cli/schema.json

@@ -607,7 +607,7 @@
           "type": "boolean"
         },
         "theme": {
-          "description": "The initial window theme. Defaults to the system theme. Only implemented on Windows and macOs 10.14+.",
+          "description": "The initial window theme. Defaults to the system theme. Only implemented on Windows and macOS 10.14+.",
           "anyOf": [
             {
               "$ref": "#/definitions/Theme"

+ 2 - 1
tooling/cli/src/build.rs

@@ -5,7 +5,7 @@
 use crate::helpers::{
   app_paths::{app_dir, tauri_dir},
   command_env,
-  config::{get as get_config, AppUrl, ShellAllowlistOpen, WindowUrl},
+  config::{get as get_config, AppUrl, WindowUrl},
   manifest::rewrite_manifest,
   updater_signature::sign_file_from_env_variables,
 };
@@ -314,6 +314,7 @@ pub fn command(options: Options) -> Result<()> {
     // set env vars used by the bundler
     #[cfg(target_os = "linux")]
     {
+      use crate::helpers::config::ShellAllowlistOpen;
       if matches!(
         config_.tauri.allowlist.shell.open,
         ShellAllowlistOpen::Flag(true) | ShellAllowlistOpen::Validate(_)