debugger: Mark DebugAdapterBinary::program as optional (#32534)
This allows us to support debugging with a debug adapter not managed by Zed. Note that this is not a user facing change, as DebugAdapterBinary is used to determine how to spawn a debugger. Thus, this should not break any configs or anything like that. Closes #ISSUE Release Notes: - N/A
This commit is contained in:
parent
a3cc063107
commit
6c4728f00f
14 changed files with 80 additions and 53 deletions
|
@ -671,7 +671,7 @@ async fn test_remote_server_debugger(
|
||||||
});
|
});
|
||||||
|
|
||||||
session.update(cx_a, |session, _| {
|
session.update(cx_a, |session, _| {
|
||||||
assert_eq!(session.binary().command, "ssh");
|
assert_eq!(session.binary().command.as_deref(), Some("ssh"));
|
||||||
});
|
});
|
||||||
|
|
||||||
let shutdown_session = workspace.update(cx_a, |workspace, cx| {
|
let shutdown_session = workspace.update(cx_a, |workspace, cx| {
|
||||||
|
|
|
@ -181,7 +181,7 @@ impl DebugTaskDefinition {
|
||||||
/// Created from a [DebugTaskDefinition], this struct describes how to spawn the debugger to create a previously-configured debug session.
|
/// Created from a [DebugTaskDefinition], this struct describes how to spawn the debugger to create a previously-configured debug session.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct DebugAdapterBinary {
|
pub struct DebugAdapterBinary {
|
||||||
pub command: String,
|
pub command: Option<String>,
|
||||||
pub arguments: Vec<String>,
|
pub arguments: Vec<String>,
|
||||||
pub envs: HashMap<String, String>,
|
pub envs: HashMap<String, String>,
|
||||||
pub cwd: Option<PathBuf>,
|
pub cwd: Option<PathBuf>,
|
||||||
|
@ -437,7 +437,7 @@ impl DebugAdapter for FakeAdapter {
|
||||||
_: &mut AsyncApp,
|
_: &mut AsyncApp,
|
||||||
) -> Result<DebugAdapterBinary> {
|
) -> Result<DebugAdapterBinary> {
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: "command".into(),
|
command: Some("command".into()),
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
connection: None,
|
connection: None,
|
||||||
envs: HashMap::default(),
|
envs: HashMap::default(),
|
||||||
|
|
|
@ -297,7 +297,7 @@ mod tests {
|
||||||
let client = DebugAdapterClient::start(
|
let client = DebugAdapterClient::start(
|
||||||
crate::client::SessionId(1),
|
crate::client::SessionId(1),
|
||||||
DebugAdapterBinary {
|
DebugAdapterBinary {
|
||||||
command: "command".into(),
|
command: Some("command".into()),
|
||||||
arguments: Default::default(),
|
arguments: Default::default(),
|
||||||
envs: Default::default(),
|
envs: Default::default(),
|
||||||
connection: None,
|
connection: None,
|
||||||
|
@ -367,7 +367,7 @@ mod tests {
|
||||||
let client = DebugAdapterClient::start(
|
let client = DebugAdapterClient::start(
|
||||||
crate::client::SessionId(1),
|
crate::client::SessionId(1),
|
||||||
DebugAdapterBinary {
|
DebugAdapterBinary {
|
||||||
command: "command".into(),
|
command: Some("command".into()),
|
||||||
arguments: Default::default(),
|
arguments: Default::default(),
|
||||||
envs: Default::default(),
|
envs: Default::default(),
|
||||||
connection: None,
|
connection: None,
|
||||||
|
@ -420,7 +420,7 @@ mod tests {
|
||||||
let client = DebugAdapterClient::start(
|
let client = DebugAdapterClient::start(
|
||||||
crate::client::SessionId(1),
|
crate::client::SessionId(1),
|
||||||
DebugAdapterBinary {
|
DebugAdapterBinary {
|
||||||
command: "command".into(),
|
command: Some("command".into()),
|
||||||
arguments: Default::default(),
|
arguments: Default::default(),
|
||||||
envs: Default::default(),
|
envs: Default::default(),
|
||||||
connection: None,
|
connection: None,
|
||||||
|
|
|
@ -85,10 +85,12 @@ impl Transport {
|
||||||
TcpTransport::start(binary, cx)
|
TcpTransport::start(binary, cx)
|
||||||
.await
|
.await
|
||||||
.map(|(transports, tcp)| (transports, Self::Tcp(tcp)))
|
.map(|(transports, tcp)| (transports, Self::Tcp(tcp)))
|
||||||
|
.context("Tried to connect to a debug adapter via TCP transport layer")
|
||||||
} else {
|
} else {
|
||||||
StdioTransport::start(binary, cx)
|
StdioTransport::start(binary, cx)
|
||||||
.await
|
.await
|
||||||
.map(|(transports, stdio)| (transports, Self::Stdio(stdio)))
|
.map(|(transports, stdio)| (transports, Self::Stdio(stdio)))
|
||||||
|
.context("Tried to connect to a debug adapter via stdin/stdout transport layer")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,7 +569,7 @@ pub struct TcpTransport {
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
pub host: Ipv4Addr,
|
pub host: Ipv4Addr,
|
||||||
pub timeout: u64,
|
pub timeout: u64,
|
||||||
process: Mutex<Child>,
|
process: Option<Mutex<Child>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TcpTransport {
|
impl TcpTransport {
|
||||||
|
@ -596,17 +598,23 @@ impl TcpTransport {
|
||||||
let host = connection_args.host;
|
let host = connection_args.host;
|
||||||
let port = connection_args.port;
|
let port = connection_args.port;
|
||||||
|
|
||||||
let mut command = util::command::new_std_command(&binary.command);
|
let mut process = if let Some(command) = &binary.command {
|
||||||
|
let mut command = util::command::new_std_command(&command);
|
||||||
|
|
||||||
if let Some(cwd) = &binary.cwd {
|
if let Some(cwd) = &binary.cwd {
|
||||||
command.current_dir(cwd);
|
command.current_dir(cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
command.args(&binary.arguments);
|
command.args(&binary.arguments);
|
||||||
command.envs(&binary.envs);
|
command.envs(&binary.envs);
|
||||||
|
|
||||||
let mut process = Child::spawn(command, Stdio::null())
|
Some(
|
||||||
.with_context(|| "failed to start debug adapter.")?;
|
Child::spawn(command, Stdio::null())
|
||||||
|
.with_context(|| "failed to start debug adapter.")?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let address = SocketAddrV4::new(host, port);
|
let address = SocketAddrV4::new(host, port);
|
||||||
|
|
||||||
|
@ -624,15 +632,18 @@ impl TcpTransport {
|
||||||
match TcpStream::connect(address).await {
|
match TcpStream::connect(address).await {
|
||||||
Ok(stream) => return Ok((process, stream.split())),
|
Ok(stream) => return Ok((process, stream.split())),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
if let Ok(Some(_)) = process.try_status() {
|
if let Some(p) = &mut process {
|
||||||
let output = process.into_inner().output().await?;
|
if let Ok(Some(_)) = p.try_status() {
|
||||||
let output = if output.stderr.is_empty() {
|
let output = process.take().unwrap().into_inner().output().await?;
|
||||||
String::from_utf8_lossy(&output.stdout).to_string()
|
let output = if output.stderr.is_empty() {
|
||||||
} else {
|
String::from_utf8_lossy(&output.stdout).to_string()
|
||||||
String::from_utf8_lossy(&output.stderr).to_string()
|
} else {
|
||||||
};
|
String::from_utf8_lossy(&output.stderr).to_string()
|
||||||
anyhow::bail!("{output}\nerror: process exited before debugger attached.");
|
};
|
||||||
|
anyhow::bail!("{output}\nerror: process exited before debugger attached.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.background_executor().timer(Duration::from_millis(100)).await;
|
cx.background_executor().timer(Duration::from_millis(100)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,13 +656,13 @@ impl TcpTransport {
|
||||||
host,
|
host,
|
||||||
port
|
port
|
||||||
);
|
);
|
||||||
let stdout = process.stdout.take();
|
let stdout = process.as_mut().and_then(|p| p.stdout.take());
|
||||||
let stderr = process.stderr.take();
|
let stderr = process.as_mut().and_then(|p| p.stderr.take());
|
||||||
|
|
||||||
let this = Self {
|
let this = Self {
|
||||||
port,
|
port,
|
||||||
host,
|
host,
|
||||||
process: Mutex::new(process),
|
process: process.map(Mutex::new),
|
||||||
timeout,
|
timeout,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -670,14 +681,18 @@ impl TcpTransport {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn kill(&self) {
|
async fn kill(&self) {
|
||||||
let mut process = self.process.lock().await;
|
if let Some(process) = &self.process {
|
||||||
Child::kill(&mut process);
|
let mut process = process.lock().await;
|
||||||
|
Child::kill(&mut process);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TcpTransport {
|
impl Drop for TcpTransport {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.process.get_mut().kill();
|
if let Some(mut p) = self.process.take() {
|
||||||
|
p.get_mut().kill();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,7 +703,12 @@ pub struct StdioTransport {
|
||||||
impl StdioTransport {
|
impl StdioTransport {
|
||||||
#[allow(dead_code, reason = "This is used in non test builds of Zed")]
|
#[allow(dead_code, reason = "This is used in non test builds of Zed")]
|
||||||
async fn start(binary: &DebugAdapterBinary, _: AsyncApp) -> Result<(TransportPipe, Self)> {
|
async fn start(binary: &DebugAdapterBinary, _: AsyncApp) -> Result<(TransportPipe, Self)> {
|
||||||
let mut command = util::command::new_std_command(&binary.command);
|
let Some(binary_command) = &binary.command else {
|
||||||
|
bail!(
|
||||||
|
"When using the `stdio` transport, the path to a debug adapter binary must be set by Zed."
|
||||||
|
);
|
||||||
|
};
|
||||||
|
let mut command = util::command::new_std_command(&binary_command);
|
||||||
|
|
||||||
if let Some(cwd) = &binary.cwd {
|
if let Some(cwd) = &binary.cwd {
|
||||||
command.current_dir(cwd);
|
command.current_dir(cwd);
|
||||||
|
@ -700,7 +720,7 @@ impl StdioTransport {
|
||||||
let mut process = Child::spawn(command, Stdio::piped()).with_context(|| {
|
let mut process = Child::spawn(command, Stdio::piped()).with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"failed to spawn command `{} {}`.",
|
"failed to spawn command `{} {}`.",
|
||||||
binary.command,
|
binary_command,
|
||||||
binary.arguments.join(" ")
|
binary.arguments.join(" ")
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
@ -715,7 +735,7 @@ impl StdioTransport {
|
||||||
if stderr.is_none() {
|
if stderr.is_none() {
|
||||||
bail!(
|
bail!(
|
||||||
"Failed to connect to stderr for debug adapter command {}",
|
"Failed to connect to stderr for debug adapter command {}",
|
||||||
&binary.command
|
&binary_command
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -359,7 +359,7 @@ impl DebugAdapter for CodeLldbDebugAdapter {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: command.unwrap(),
|
command: Some(command.unwrap()),
|
||||||
cwd: Some(delegate.worktree_root_path().to_path_buf()),
|
cwd: Some(delegate.worktree_root_path().to_path_buf()),
|
||||||
arguments: vec![
|
arguments: vec![
|
||||||
"--settings".into(),
|
"--settings".into(),
|
||||||
|
|
|
@ -183,7 +183,7 @@ impl DebugAdapter for GdbDebugAdapter {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: gdb_path,
|
command: Some(gdb_path),
|
||||||
arguments: vec!["-i=dap".into()],
|
arguments: vec!["-i=dap".into()],
|
||||||
envs: HashMap::default(),
|
envs: HashMap::default(),
|
||||||
cwd: Some(delegate.worktree_root_path().to_path_buf()),
|
cwd: Some(delegate.worktree_root_path().to_path_buf()),
|
||||||
|
|
|
@ -463,7 +463,7 @@ impl DebugAdapter for GoDebugAdapter {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: minidelve_path.to_string_lossy().into_owned(),
|
command: Some(minidelve_path.to_string_lossy().into_owned()),
|
||||||
arguments,
|
arguments,
|
||||||
cwd: Some(cwd),
|
cwd: Some(cwd),
|
||||||
envs: HashMap::default(),
|
envs: HashMap::default(),
|
||||||
|
|
|
@ -69,12 +69,14 @@ impl JsDebugAdapter {
|
||||||
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||||
|
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: delegate
|
command: Some(
|
||||||
.node_runtime()
|
delegate
|
||||||
.binary_path()
|
.node_runtime()
|
||||||
.await?
|
.binary_path()
|
||||||
.to_string_lossy()
|
.await?
|
||||||
.into_owned(),
|
.to_string_lossy()
|
||||||
|
.into_owned(),
|
||||||
|
),
|
||||||
arguments: vec![
|
arguments: vec![
|
||||||
adapter_path
|
adapter_path
|
||||||
.join(Self::ADAPTER_PATH)
|
.join(Self::ADAPTER_PATH)
|
||||||
|
|
|
@ -72,12 +72,14 @@ impl PhpDebugAdapter {
|
||||||
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||||
|
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: delegate
|
command: Some(
|
||||||
.node_runtime()
|
delegate
|
||||||
.binary_path()
|
.node_runtime()
|
||||||
.await?
|
.binary_path()
|
||||||
.to_string_lossy()
|
.await?
|
||||||
.into_owned(),
|
.to_string_lossy()
|
||||||
|
.into_owned(),
|
||||||
|
),
|
||||||
arguments: vec![
|
arguments: vec![
|
||||||
adapter_path
|
adapter_path
|
||||||
.join(Self::ADAPTER_PATH)
|
.join(Self::ADAPTER_PATH)
|
||||||
|
|
|
@ -187,7 +187,7 @@ impl PythonDebugAdapter {
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: python_command,
|
command: Some(python_command),
|
||||||
arguments,
|
arguments,
|
||||||
connection: Some(adapters::TcpArguments {
|
connection: Some(adapters::TcpArguments {
|
||||||
host,
|
host,
|
||||||
|
|
|
@ -175,7 +175,7 @@ impl DebugAdapter for RubyDebugAdapter {
|
||||||
arguments.extend(ruby_config.args);
|
arguments.extend(ruby_config.args);
|
||||||
|
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: rdbg_path.to_string_lossy().to_string(),
|
command: Some(rdbg_path.to_string_lossy().to_string()),
|
||||||
arguments,
|
arguments,
|
||||||
connection: Some(dap::adapters::TcpArguments {
|
connection: Some(dap::adapters::TcpArguments {
|
||||||
host,
|
host,
|
||||||
|
|
|
@ -50,7 +50,7 @@ interface dap {
|
||||||
}
|
}
|
||||||
|
|
||||||
record debug-adapter-binary {
|
record debug-adapter-binary {
|
||||||
command: string,
|
command: option<string>,
|
||||||
arguments: list<string>,
|
arguments: list<string>,
|
||||||
envs: env-vars,
|
envs: env-vars,
|
||||||
cwd: option<string>,
|
cwd: option<string>,
|
||||||
|
|
|
@ -258,14 +258,17 @@ impl DapStore {
|
||||||
|
|
||||||
let (program, args) = wrap_for_ssh(
|
let (program, args) = wrap_for_ssh(
|
||||||
&ssh_command,
|
&ssh_command,
|
||||||
Some((&binary.command, &binary.arguments)),
|
binary
|
||||||
|
.command
|
||||||
|
.as_ref()
|
||||||
|
.map(|command| (command, &binary.arguments)),
|
||||||
binary.cwd.as_deref(),
|
binary.cwd.as_deref(),
|
||||||
binary.envs,
|
binary.envs,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(DebugAdapterBinary {
|
Ok(DebugAdapterBinary {
|
||||||
command: program,
|
command: Some(program),
|
||||||
arguments: args,
|
arguments: args,
|
||||||
envs: HashMap::default(),
|
envs: HashMap::default(),
|
||||||
cwd: None,
|
cwd: None,
|
||||||
|
|
|
@ -496,7 +496,7 @@ message GetDebugAdapterBinary {
|
||||||
}
|
}
|
||||||
|
|
||||||
message DebugAdapterBinary {
|
message DebugAdapterBinary {
|
||||||
string command = 1;
|
optional string command = 1;
|
||||||
repeated string arguments = 2;
|
repeated string arguments = 2;
|
||||||
map<string, string> envs = 3;
|
map<string, string> envs = 3;
|
||||||
optional string cwd = 4;
|
optional string cwd = 4;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue