auto_update: Unmount update disk image in the background (#38867)

Lukas Wirth created

Release Notes:

- Fixed potentially temporarily hanging on macOS when updating the app

Change summary

crates/auto_update/src/auto_update.rs | 53 ++++++++++++++++------------
1 file changed, 31 insertions(+), 22 deletions(-)

Detailed changes

crates/auto_update/src/auto_update.rs 🔗

@@ -3,7 +3,8 @@ use client::{Client, TelemetrySettings};
 use db::RELEASE_CHANNEL;
 use db::kvp::KEY_VALUE_STORE;
 use gpui::{
-    App, AppContext as _, AsyncApp, Context, Entity, Global, SemanticVersion, Task, Window, actions,
+    App, AppContext as _, AsyncApp, BackgroundExecutor, Context, Entity, Global, SemanticVersion,
+    Task, Window, actions,
 };
 use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
 use paths::remote_servers_dir;
@@ -13,6 +14,7 @@ use serde::{Deserialize, Serialize};
 use settings::{Settings, SettingsKey, SettingsSources, SettingsStore, SettingsUi};
 use smol::{fs, io::AsyncReadExt};
 use smol::{fs::File, process::Command};
+use std::mem;
 use std::{
     env::{
         self,
@@ -85,31 +87,37 @@ pub struct JsonRelease {
     pub url: String,
 }
 
-struct MacOsUnmounter {
+struct MacOsUnmounter<'a> {
     mount_path: PathBuf,
+    background_executor: &'a BackgroundExecutor,
 }
 
-impl Drop for MacOsUnmounter {
+impl Drop for MacOsUnmounter<'_> {
     fn drop(&mut self) {
-        let unmount_output = std::process::Command::new("hdiutil")
-            .args(["detach", "-force"])
-            .arg(&self.mount_path)
-            .output();
-
-        match unmount_output {
-            Ok(output) if output.status.success() => {
-                log::info!("Successfully unmounted the disk image");
-            }
-            Ok(output) => {
-                log::error!(
-                    "Failed to unmount disk image: {:?}",
-                    String::from_utf8_lossy(&output.stderr)
-                );
-            }
-            Err(error) => {
-                log::error!("Error while trying to unmount disk image: {:?}", error);
-            }
-        }
+        let mount_path = mem::take(&mut self.mount_path);
+        self.background_executor
+            .spawn(async move {
+                let unmount_output = Command::new("hdiutil")
+                    .args(["detach", "-force"])
+                    .arg(&mount_path)
+                    .output()
+                    .await;
+                match unmount_output {
+                    Ok(output) if output.status.success() => {
+                        log::info!("Successfully unmounted the disk image");
+                    }
+                    Ok(output) => {
+                        log::error!(
+                            "Failed to unmount disk image: {:?}",
+                            String::from_utf8_lossy(&output.stderr)
+                        );
+                    }
+                    Err(error) => {
+                        log::error!("Error while trying to unmount disk image: {:?}", error);
+                    }
+                }
+            })
+            .detach();
     }
 }
 
@@ -929,6 +937,7 @@ async fn install_release_macos(
     // Create an MacOsUnmounter that will be dropped (and thus unmount the disk) when this function exits
     let _unmounter = MacOsUnmounter {
         mount_path: mount_path.clone(),
+        background_executor: cx.background_executor(),
     };
 
     let output = Command::new("rsync")