Skip to main content

Mountain/IPC/WindServiceHandlers/NativeHost/
UninstallShellCommand.rs

1
2//! `nativeHost:uninstallShellCommand` - remove the `land` symlink from
3//! `/usr/local/bin`. Mirrors VS Code's "Uninstall 'code' command from PATH".
4
5use std::path::PathBuf;
6
7use serde_json::Value;
8
9use crate::dev_log;
10
11const CLI_NAME:&str = "land";
12
13const SYMLINK_DIR:&str = "/usr/local/bin";
14
15pub async fn Fn(_Arguments:Vec<Value>) -> Result<Value, String> {
16	let Target = PathBuf::from(SYMLINK_DIR).join(CLI_NAME);
17
18	dev_log!("shell-cmd", "uninstallShellCommand: removing {}", Target.display());
19
20	match std::fs::remove_file(&Target) {
21		Ok(()) => {
22			dev_log!("shell-cmd", "uninstallShellCommand: removed");
23
24			Ok(Value::Bool(true))
25		},
26
27		Err(E) if E.kind() == std::io::ErrorKind::NotFound => Ok(Value::Bool(true)),
28
29		Err(E) if E.kind() == std::io::ErrorKind::PermissionDenied => {
30			#[cfg(target_os = "macos")]
31			{
32				// Pass path via env var; use AppleScript's `quoted form of` for
33				// safe shell quoting - no interpolation into script source.
34				let Status = tokio::process::Command::new("osascript")
35					.env("SH_TARGET", Target.as_os_str())
36					.args([
37						"-e",
38						"do shell script (\"rm -f \" & quoted form of (system attribute \"SH_TARGET\")) with \
39						 administrator privileges",
40					])
41					.status()
42					.await
43					.map_err(|E| format!("uninstallShellCommand: osascript failed: {E}"))?;
44
45				if Status.success() {
46					return Ok(Value::Bool(true));
47				}
48			}
49
50			Err(format!("uninstallShellCommand: permission denied"))
51		},
52
53		Err(E) => Err(format!("uninstallShellCommand: {E}")),
54	}
55}