1use clap::Parser;
2use remote_server::Commands;
3use std::path::PathBuf;
4
5#[derive(Parser)]
6#[command(disable_version_flag = true)]
7struct Cli {
8 #[command(subcommand)]
9 command: Option<Commands>,
10 /// Used for SSH/Git password authentication, to remove the need for netcat as a dependency,
11 /// by having Zed act like netcat communicating over a Unix socket.
12 #[arg(long, hide = true)]
13 askpass: Option<String>,
14 /// Used for recording minidumps on crashes by having the server run a separate
15 /// process communicating over a socket.
16 #[arg(long, hide = true)]
17 crash_handler: Option<PathBuf>,
18 /// Used for loading the environment from the project.
19 #[arg(long, hide = true)]
20 printenv: bool,
21}
22
23fn main() -> anyhow::Result<()> {
24 let cli = Cli::parse();
25
26 if let Some(socket_path) = &cli.askpass {
27 askpass::main(socket_path);
28 return Ok(());
29 }
30
31 if let Some(socket) = &cli.crash_handler {
32 crashes::crash_server(socket.as_path());
33 return Ok(());
34 }
35
36 if cli.printenv {
37 util::shell_env::print_env();
38 return Ok(());
39 }
40
41 #[cfg(not(windows))]
42 if let Some(command) = cli.command {
43 use remote_server::unix::ExecuteProxyError;
44
45 let res = remote_server::run(command);
46 if let Err(e) = &res
47 && let Some(e) = e.downcast_ref::<ExecuteProxyError>()
48 {
49 eprintln!("{e:#}");
50 // It is important for us to report the proxy spawn exit code here
51 // instead of the generic 1 that result returns
52 // The client reads the exit code to determine if the server process has died when trying to reconnect
53 // signaling that it needs to try spawning a new server
54 std::process::exit(e.to_exit_code());
55 }
56 res
57 } else {
58 eprintln!("usage: remote <run|proxy|version>");
59 std::process::exit(1);
60 }
61
62 #[cfg(windows)]
63 if let Some(_) = cli.command {
64 eprintln!("run is not supported on Windows");
65 std::process::exit(2);
66 } else {
67 eprintln!("usage: remote <run|proxy|version>");
68 std::process::exit(1);
69 }
70}