install_cli.rs

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