install_cli.rs

 1use anyhow::{Result, anyhow};
 2use gpui::{AsyncApp, actions};
 3use std::path::{Path, PathBuf};
 4use util::ResultExt;
 5
 6actions!(cli, [Install, RegisterZedScheme]);
 7
 8pub async fn install_cli(cx: &AsyncApp) -> Result<PathBuf> {
 9    let cli_path = cx.update(|cx| cx.path_for_auxiliary_executable("cli"))??;
10    let link_path = Path::new("/usr/local/bin/zed");
11    let bin_dir_path = link_path.parent().unwrap();
12
13    // Don't re-create symlink if it points to the same CLI binary.
14    if smol::fs::read_link(link_path).await.ok().as_ref() == Some(&cli_path) {
15        return Ok(link_path.into());
16    }
17
18    // If the symlink is not there or is outdated, first try replacing it
19    // without escalating.
20    smol::fs::remove_file(link_path).await.log_err();
21    // todo("windows")
22    #[cfg(not(windows))]
23    {
24        if smol::fs::unix::symlink(&cli_path, link_path)
25            .await
26            .log_err()
27            .is_some()
28        {
29            return Ok(link_path.into());
30        }
31    }
32
33    // The symlink could not be created, so use osascript with admin privileges
34    // to create it.
35    let status = smol::process::Command::new("/usr/bin/osascript")
36        .args([
37            "-e",
38            &format!(
39                "do shell script \" \
40                    mkdir -p \'{}\' && \
41                    ln -sf \'{}\' \'{}\' \
42                \" with administrator privileges",
43                bin_dir_path.to_string_lossy(),
44                cli_path.to_string_lossy(),
45                link_path.to_string_lossy(),
46            ),
47        ])
48        .stdout(smol::process::Stdio::inherit())
49        .stderr(smol::process::Stdio::inherit())
50        .output()
51        .await?
52        .status;
53    if status.success() {
54        Ok(link_path.into())
55    } else {
56        Err(anyhow!("error running osascript"))
57    }
58}