Browse Source

feat(core): restart() handles binary name change for macOS (#11002)

Lucas Fernandes Nogueira 10 months ago
parent
commit
5eb036f339

+ 5 - 0
.changes/restart-handle-binary-name-change.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch:enhance
+---
+
+Handle macOS binary name change on the `process::restart` function.

+ 1 - 0
Cargo.lock

@@ -7031,6 +7031,7 @@ dependencies = [
  "muda",
  "objc",
  "percent-encoding",
+ "plist",
  "proptest",
  "quickcheck",
  "quickcheck_macros",

+ 1 - 0
crates/tauri/Cargo.toml

@@ -103,6 +103,7 @@ webkit2gtk = { version = "=2.0.1", features = ["v2_40"] }
 
 [target."cfg(target_os = \"macos\")".dependencies]
 embed_plist = "1.2"
+plist = "1"
 cocoa = "0.26"
 objc = "0.2"
 window-vibrancy = "0.5"

+ 50 - 3
crates/tauri/src/process.rs

@@ -75,12 +75,59 @@ pub fn restart(env: &Env) -> ! {
   use std::process::{exit, Command};
 
   if let Ok(path) = current_binary(env) {
-    Command::new(path)
-      // first arg is the binary name, must skip it
+    // on macOS on updates the binary name might have changed
+    // so we'll read the Contents/Info.plist file to determine the binary path
+    #[cfg(target_os = "macos")]
+    restart_macos_app(&path, env);
+
+    if let Err(e) = Command::new(path)
       .args(env.args_os.iter().skip(1).collect::<Vec<_>>())
       .spawn()
-      .expect("application failed to start");
+    {
+      log::error!("failed to restart app: {e}");
+    }
   }
 
   exit(0);
 }
+
+#[cfg(target_os = "macos")]
+fn restart_macos_app(current_binary: &PathBuf, env: &Env) {
+  use std::process::{exit, Command};
+
+  if let Some(macos_directory) = current_binary.parent() {
+    if macos_directory.components().last()
+      != Some(std::path::Component::Normal(std::ffi::OsStr::new("MacOS")))
+    {
+      return;
+    }
+
+    if let Some(contents_directory) = macos_directory.parent() {
+      if contents_directory.components().last()
+        != Some(std::path::Component::Normal(std::ffi::OsStr::new(
+          "Contents",
+        )))
+      {
+        return;
+      }
+
+      if let Ok(info_plist) =
+        plist::from_file::<_, plist::Dictionary>(contents_directory.join("Info.plist"))
+      {
+        if let Some(binary_name) = info_plist
+          .get("CFBundleExecutable")
+          .and_then(|v| v.as_string())
+        {
+          if let Err(e) = Command::new(macos_directory.join(binary_name))
+            .args(env.args_os.iter().skip(1).collect::<Vec<_>>())
+            .spawn()
+          {
+            log::error!("failed to restart app: {e}");
+          }
+
+          exit(0);
+        }
+      }
+    }
+  }
+}