@@ -38,12 +38,14 @@ impl From<settings::WslConnection> for WslConnectionOptions {
}
}
+#[derive(Debug)]
pub(crate) struct WslRemoteConnection {
remote_binary_path: Option<Arc<RelPath>>,
platform: RemotePlatform,
shell: String,
default_system_shell: String,
connection_options: WslConnectionOptions,
+ can_exec: bool,
}
impl WslRemoteConnection {
@@ -71,18 +73,48 @@ impl WslRemoteConnection {
platform: RemotePlatform { os: "", arch: "" },
shell: String::new(),
default_system_shell: String::from("/bin/sh"),
+ can_exec: true,
};
delegate.set_status(Some("Detecting WSL environment"), cx);
+ this.can_exec = this.detect_can_exec().await?;
this.platform = this.detect_platform().await?;
this.shell = this.detect_shell().await?;
this.remote_binary_path = Some(
this.ensure_server_binary(&delegate, release_channel, version, commit, cx)
.await?,
);
+ log::debug!("Detected WSL environment: {this:#?}");
Ok(this)
}
+ async fn detect_can_exec(&self) -> Result<bool> {
+ let options = &self.connection_options;
+ let program = "uname";
+ let args = &["-m"];
+ let output = wsl_command_impl(options, program, args, true)
+ .output()
+ .await?;
+
+ if !output.status.success() {
+ let output = wsl_command_impl(options, program, args, false)
+ .output()
+ .await?;
+
+ if !output.status.success() {
+ return Err(anyhow!(
+ "Command '{}' failed: {}",
+ program,
+ String::from_utf8_lossy(&output.stderr).trim()
+ ));
+ }
+
+ Ok(false)
+ } else {
+ Ok(true)
+ }
+ }
+
async fn detect_platform(&self) -> Result<RemotePlatform> {
let arch_str = self.run_wsl_command("uname", &["-m"]).await?;
let arch_str = arch_str.trim().to_string();
@@ -103,15 +135,15 @@ impl WslRemoteConnection {
}
async fn windows_path_to_wsl_path(&self, source: &Path) -> Result<String> {
- windows_path_to_wsl_path_impl(&self.connection_options, source).await
+ windows_path_to_wsl_path_impl(&self.connection_options, source, self.can_exec).await
}
fn wsl_command(&self, program: &str, args: &[impl AsRef<OsStr>]) -> process::Command {
- wsl_command_impl(&self.connection_options, program, args)
+ wsl_command_impl(&self.connection_options, program, args, self.can_exec)
}
async fn run_wsl_command(&self, program: &str, args: &[&str]) -> Result<String> {
- run_wsl_command_impl(&self.connection_options, program, args).await
+ run_wsl_command_impl(&self.connection_options, program, args, self.can_exec).await
}
async fn ensure_server_binary(
@@ -296,7 +328,10 @@ impl RemoteConnection for WslRemoteConnection {
let mut proxy_args = vec![];
for env_var in ["RUST_LOG", "RUST_BACKTRACE", "ZED_GENERATE_MINIDUMPS"] {
if let Some(value) = std::env::var(env_var).ok() {
- proxy_args.push(format!("{}='{}'", env_var, value));
+ // We don't quote the value here as it seems excessive and may result in invalid envs for the
+ // proxy server. For example, `RUST_LOG='debug'` will result in a warning "invalid logging spec 'debug'', ignoring it"
+ // in the proxy server. Therefore, we pass the env vars as is.
+ proxy_args.push(format!("{}={}", env_var, value));
}
}
proxy_args.push(remote_binary_path.display(PathStyle::Posix).into_owned());
@@ -335,19 +370,25 @@ impl RemoteConnection for WslRemoteConnection {
) -> Task<Result<()>> {
cx.background_spawn({
let options = self.connection_options.clone();
+ let can_exec = self.can_exec;
async move {
- let wsl_src = windows_path_to_wsl_path_impl(&options, &src_path).await?;
-
- run_wsl_command_impl(&options, "cp", &["-r", &wsl_src, &dest_path.to_string()])
- .await
- .map_err(|e| {
- anyhow!(
- "failed to upload directory {} -> {}: {}",
- src_path.display(),
- dest_path.to_string(),
- e
- )
- })?;
+ let wsl_src = windows_path_to_wsl_path_impl(&options, &src_path, can_exec).await?;
+
+ run_wsl_command_impl(
+ &options,
+ "cp",
+ &["-r", &wsl_src, &dest_path.to_string()],
+ can_exec,
+ )
+ .await
+ .map_err(|e| {
+ anyhow!(
+ "failed to upload directory {} -> {}: {}",
+ src_path.display(),
+ dest_path.to_string(),
+ e
+ )
+ })?;
Ok(())
}
@@ -463,17 +504,21 @@ async fn sanitize_path(path: &Path) -> Result<String> {
async fn windows_path_to_wsl_path_impl(
options: &WslConnectionOptions,
source: &Path,
+ exec: bool,
) -> Result<String> {
let source = sanitize_path(source).await?;
- run_wsl_command_impl(options, "wslpath", &["-u", &source]).await
+ run_wsl_command_impl(options, "wslpath", &["-u", &source], exec).await
}
async fn run_wsl_command_impl(
options: &WslConnectionOptions,
program: &str,
args: &[&str],
+ exec: bool,
) -> Result<String> {
- let output = wsl_command_impl(options, program, args).output().await?;
+ let output = wsl_command_impl(options, program, args, exec)
+ .output()
+ .await?;
if !output.status.success() {
return Err(anyhow!(
@@ -493,6 +538,7 @@ fn wsl_command_impl(
options: &WslConnectionOptions,
program: &str,
args: &[impl AsRef<OsStr>],
+ exec: bool,
) -> process::Command {
let mut command = util::command::new_smol_command("wsl.exe");
@@ -507,10 +553,13 @@ fn wsl_command_impl(
.arg("--distribution")
.arg(&options.distro_name)
.arg("--cd")
- .arg("~")
- .arg("--exec")
- .arg(program)
- .args(args);
+ .arg("~");
+
+ if exec {
+ command.arg("--exec");
+ }
+
+ command.arg(program).args(args);
log::debug!("wsl {:?}", command);
command