remote: Recognize WSL interop to open browser for codex web login (#44136)
Closes #41521 Release Notes: - Fixed codex web login not working on wsl remotes if no browser is installed Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
This commit is contained in:
co-authored by
Ben Brandt
parent
c978db8626
commit
a33e881906
@@ -1723,6 +1723,10 @@ impl ProtoClient for Client {
|
||||
fn is_via_collab(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn has_wsl_interop(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// prefix for the zed:// url scheme
|
||||
|
||||
@@ -453,7 +453,9 @@ impl AgentServerStore {
|
||||
.clone()
|
||||
.and_then(|settings| settings.custom_command()),
|
||||
http_client: http_client.clone(),
|
||||
is_remote: downstream_client.is_some(),
|
||||
no_browser: downstream_client
|
||||
.as_ref()
|
||||
.is_some_and(|(_, client)| !client.has_wsl_interop()),
|
||||
}),
|
||||
);
|
||||
self.external_agents.insert(
|
||||
@@ -1355,7 +1357,7 @@ struct LocalCodex {
|
||||
project_environment: Entity<ProjectEnvironment>,
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
custom_command: Option<AgentServerCommand>,
|
||||
is_remote: bool,
|
||||
no_browser: bool,
|
||||
}
|
||||
|
||||
impl ExternalAgentServer for LocalCodex {
|
||||
@@ -1375,7 +1377,7 @@ impl ExternalAgentServer for LocalCodex {
|
||||
.map(|root_dir| Path::new(root_dir))
|
||||
.unwrap_or(paths::home_dir())
|
||||
.into();
|
||||
let is_remote = self.is_remote;
|
||||
let no_browser = self.no_browser;
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let mut env = project_environment
|
||||
@@ -1388,7 +1390,7 @@ impl ExternalAgentServer for LocalCodex {
|
||||
})?
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
if is_remote {
|
||||
if no_browser {
|
||||
env.insert("NO_BROWSER".to_owned(), "1".to_owned());
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ urlencoding.workspace = true
|
||||
util.workspace = true
|
||||
which.workspace = true
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
fs = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -328,8 +328,15 @@ impl RemoteClient {
|
||||
let (incoming_tx, incoming_rx) = mpsc::unbounded::<Envelope>();
|
||||
let (connection_activity_tx, connection_activity_rx) = mpsc::channel::<()>(1);
|
||||
|
||||
let client =
|
||||
cx.update(|cx| ChannelClient::new(incoming_rx, outgoing_tx, cx, "client"))?;
|
||||
let client = cx.update(|cx| {
|
||||
ChannelClient::new(
|
||||
incoming_rx,
|
||||
outgoing_tx,
|
||||
cx,
|
||||
"client",
|
||||
remote_connection.has_wsl_interop(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let path_style = remote_connection.path_style();
|
||||
let this = cx.new(|_| Self {
|
||||
@@ -420,8 +427,9 @@ impl RemoteClient {
|
||||
outgoing_tx: mpsc::UnboundedSender<Envelope>,
|
||||
cx: &App,
|
||||
name: &'static str,
|
||||
has_wsl_interop: bool,
|
||||
) -> AnyProtoClient {
|
||||
ChannelClient::new(incoming_rx, outgoing_tx, cx, name).into()
|
||||
ChannelClient::new(incoming_rx, outgoing_tx, cx, name, has_wsl_interop).into()
|
||||
}
|
||||
|
||||
pub fn shutdown_processes<T: RequestMessage>(
|
||||
@@ -921,8 +929,8 @@ impl RemoteClient {
|
||||
});
|
||||
let (outgoing_tx, _) = mpsc::unbounded::<Envelope>();
|
||||
let (_, incoming_rx) = mpsc::unbounded::<Envelope>();
|
||||
let server_client =
|
||||
server_cx.update(|cx| ChannelClient::new(incoming_rx, outgoing_tx, cx, "fake-server"));
|
||||
let server_client = server_cx
|
||||
.update(|cx| ChannelClient::new(incoming_rx, outgoing_tx, cx, "fake-server", false));
|
||||
let connection: Arc<dyn RemoteConnection> = Arc::new(fake::FakeRemoteConnection {
|
||||
connection_options: opts.clone(),
|
||||
server_cx: fake::SendableCx::new(server_cx),
|
||||
@@ -1140,6 +1148,7 @@ pub trait RemoteConnection: Send + Sync {
|
||||
fn path_style(&self) -> PathStyle;
|
||||
fn shell(&self) -> String;
|
||||
fn default_system_shell(&self) -> String;
|
||||
fn has_wsl_interop(&self) -> bool;
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fn simulate_disconnect(&self, _: &AsyncApp) {}
|
||||
@@ -1188,6 +1197,7 @@ struct ChannelClient {
|
||||
name: &'static str,
|
||||
task: Mutex<Task<Result<()>>>,
|
||||
remote_started: Signal<()>,
|
||||
has_wsl_interop: bool,
|
||||
}
|
||||
|
||||
impl ChannelClient {
|
||||
@@ -1196,6 +1206,7 @@ impl ChannelClient {
|
||||
outgoing_tx: mpsc::UnboundedSender<Envelope>,
|
||||
cx: &App,
|
||||
name: &'static str,
|
||||
has_wsl_interop: bool,
|
||||
) -> Arc<Self> {
|
||||
Arc::new_cyclic(|this| Self {
|
||||
outgoing_tx: Mutex::new(outgoing_tx),
|
||||
@@ -1211,6 +1222,7 @@ impl ChannelClient {
|
||||
&cx.to_async(),
|
||||
)),
|
||||
remote_started: Signal::new(cx),
|
||||
has_wsl_interop,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1489,6 +1501,10 @@ impl ProtoClient for ChannelClient {
|
||||
fn is_via_collab(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn has_wsl_interop(&self) -> bool {
|
||||
self.has_wsl_interop
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
@@ -1652,6 +1668,10 @@ mod fake {
|
||||
fn default_system_shell(&self) -> String {
|
||||
"sh".to_owned()
|
||||
}
|
||||
|
||||
fn has_wsl_interop(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Delegate;
|
||||
|
||||
@@ -131,11 +131,7 @@ async fn build_remote_server_from_source(
|
||||
let build_remote_server =
|
||||
std::env::var("ZED_BUILD_REMOTE_SERVER").unwrap_or("nocompress".into());
|
||||
|
||||
if build_remote_server == "false"
|
||||
|| build_remote_server == "no"
|
||||
|| build_remote_server == "off"
|
||||
|| build_remote_server == "0"
|
||||
{
|
||||
if let "false" | "no" | "off" | "0" = &*build_remote_server {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
||||
@@ -394,6 +394,10 @@ impl RemoteConnection for SshRemoteConnection {
|
||||
fn path_style(&self) -> PathStyle {
|
||||
self.ssh_path_style
|
||||
}
|
||||
|
||||
fn has_wsl_interop(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl SshRemoteConnection {
|
||||
|
||||
@@ -47,6 +47,7 @@ pub(crate) struct WslRemoteConnection {
|
||||
shell: String,
|
||||
shell_kind: ShellKind,
|
||||
default_system_shell: String,
|
||||
has_wsl_interop: bool,
|
||||
connection_options: WslConnectionOptions,
|
||||
}
|
||||
|
||||
@@ -71,6 +72,7 @@ impl WslRemoteConnection {
|
||||
shell: String::new(),
|
||||
shell_kind: ShellKind::Posix,
|
||||
default_system_shell: String::from("/bin/sh"),
|
||||
has_wsl_interop: false,
|
||||
};
|
||||
delegate.set_status(Some("Detecting WSL environment"), cx);
|
||||
this.shell = this
|
||||
@@ -79,6 +81,15 @@ impl WslRemoteConnection {
|
||||
.context("failed detecting shell")?;
|
||||
log::info!("Remote shell discovered: {}", this.shell);
|
||||
this.shell_kind = ShellKind::new(&this.shell, false);
|
||||
this.has_wsl_interop = this.detect_has_wsl_interop().await.unwrap_or_default();
|
||||
log::info!(
|
||||
"Remote has wsl interop {}",
|
||||
if this.has_wsl_interop {
|
||||
"enabled"
|
||||
} else {
|
||||
"disabled"
|
||||
}
|
||||
);
|
||||
this.platform = this
|
||||
.detect_platform()
|
||||
.await
|
||||
@@ -115,6 +126,14 @@ impl WslRemoteConnection {
|
||||
.unwrap_or_else(|| "/bin/sh".to_string()))
|
||||
}
|
||||
|
||||
async fn detect_has_wsl_interop(&self) -> Result<bool> {
|
||||
Ok(self
|
||||
.run_wsl_command_with_output("cat", &["/proc/sys/fs/binfmt_misc/WSLInterop"])
|
||||
.await
|
||||
.inspect_err(|err| log::error!("Failed to detect wsl interop: {err}"))?
|
||||
.contains("enabled"))
|
||||
}
|
||||
|
||||
async fn windows_path_to_wsl_path(&self, source: &Path) -> Result<String> {
|
||||
windows_path_to_wsl_path_impl(&self.connection_options, source).await
|
||||
}
|
||||
@@ -317,6 +336,7 @@ impl RemoteConnection for WslRemoteConnection {
|
||||
proxy_args.push(format!("{}={}", env_var, value));
|
||||
}
|
||||
}
|
||||
|
||||
proxy_args.push(remote_binary_path.display(PathStyle::Posix).into_owned());
|
||||
proxy_args.push("proxy".to_owned());
|
||||
proxy_args.push("--identifier".to_owned());
|
||||
@@ -489,6 +509,10 @@ impl RemoteConnection for WslRemoteConnection {
|
||||
fn default_system_shell(&self) -> String {
|
||||
self.default_system_shell.clone()
|
||||
}
|
||||
|
||||
fn has_wsl_interop(&self) -> bool {
|
||||
self.has_wsl_interop
|
||||
}
|
||||
}
|
||||
|
||||
/// `wslpath` is a executable available in WSL, it's a linux binary.
|
||||
|
||||
@@ -199,6 +199,7 @@ fn start_server(
|
||||
listeners: ServerListeners,
|
||||
log_rx: Receiver<Vec<u8>>,
|
||||
cx: &mut App,
|
||||
is_wsl_interop: bool,
|
||||
) -> AnyProtoClient {
|
||||
// This is the server idle timeout. If no connection comes in this timeout, the server will shut down.
|
||||
const IDLE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10 * 60);
|
||||
@@ -318,7 +319,7 @@ fn start_server(
|
||||
})
|
||||
.detach();
|
||||
|
||||
RemoteClient::proto_client_from_channels(incoming_rx, outgoing_tx, cx, "server")
|
||||
RemoteClient::proto_client_from_channels(incoming_rx, outgoing_tx, cx, "server", is_wsl_interop)
|
||||
}
|
||||
|
||||
fn init_paths() -> anyhow::Result<()> {
|
||||
@@ -407,8 +408,15 @@ pub fn execute_run(
|
||||
|
||||
HeadlessProject::init(cx);
|
||||
|
||||
let is_wsl_interop = if cfg!(target_os = "linux") {
|
||||
// See: https://learn.microsoft.com/en-us/windows/wsl/filesystems#disable-interoperability
|
||||
matches!(std::fs::read_to_string("/proc/sys/fs/binfmt_misc/WSLInterop"), Ok(s) if s.contains("enabled"))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
log::info!("gpui app started, initializing server");
|
||||
let session = start_server(listeners, log_rx, cx);
|
||||
let session = start_server(listeners, log_rx, cx, is_wsl_interop);
|
||||
|
||||
GitHostingProviderRegistry::set_global(git_hosting_provider_registry, cx);
|
||||
git_hosting_providers::init(cx);
|
||||
|
||||
@@ -59,6 +59,7 @@ pub trait ProtoClient: Send + Sync {
|
||||
fn message_handler_set(&self) -> &parking_lot::Mutex<ProtoMessageHandlerSet>;
|
||||
|
||||
fn is_via_collab(&self) -> bool;
|
||||
fn has_wsl_interop(&self) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -510,6 +511,10 @@ impl AnyProtoClient {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn has_wsl_interop(&self) -> bool {
|
||||
self.0.client.has_wsl_interop()
|
||||
}
|
||||
}
|
||||
|
||||
fn to_any_envelope<T: EnvelopedMessage>(
|
||||
|
||||
Reference in New Issue
Block a user