diff --git a/crates/dap/src/transport.rs b/crates/dap/src/transport.rs index 5121d4c285..c869364a94 100644 --- a/crates/dap/src/transport.rs +++ b/crates/dap/src/transport.rs @@ -658,9 +658,13 @@ impl StdioTransport { .stderr(Stdio::piped()) .kill_on_drop(true); - let mut process = command - .spawn() - .with_context(|| "failed to spawn command.")?; + let mut process = command.spawn().with_context(|| { + format!( + "failed to spawn command `{} {}`.", + binary.command, + binary.arguments.join(" ") + ) + })?; let stdin = process.stdin.take().context("Failed to open stdin")?; let stdout = process.stdout.take().context("Failed to open stdout")?; diff --git a/crates/dap_adapters/src/dap_adapters.rs b/crates/dap_adapters/src/dap_adapters.rs index 5dbcb7058d..414d0a91a3 100644 --- a/crates/dap_adapters/src/dap_adapters.rs +++ b/crates/dap_adapters/src/dap_adapters.rs @@ -37,7 +37,7 @@ pub fn init(cx: &mut App) { registry.add_adapter(Arc::from(PhpDebugAdapter::default())); registry.add_adapter(Arc::from(JsDebugAdapter::default())); registry.add_adapter(Arc::from(RubyDebugAdapter)); - registry.add_adapter(Arc::from(GoDebugAdapter)); + registry.add_adapter(Arc::from(GoDebugAdapter::default())); registry.add_adapter(Arc::from(GdbDebugAdapter)); #[cfg(any(test, feature = "test-support"))] diff --git a/crates/dap_adapters/src/go.rs b/crates/dap_adapters/src/go.rs index dc63201be9..6cba3ab465 100644 --- a/crates/dap_adapters/src/go.rs +++ b/crates/dap_adapters/src/go.rs @@ -1,22 +1,87 @@ use anyhow::{Context as _, anyhow, bail}; use dap::{ StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest, - adapters::DebugTaskDefinition, + adapters::{ + DebugTaskDefinition, DownloadedFileType, download_adapter_from_github, + latest_github_release, + }, }; use gpui::{AsyncApp, SharedString}; use language::LanguageName; -use std::{collections::HashMap, ffi::OsStr, path::PathBuf}; +use std::{collections::HashMap, env::consts, ffi::OsStr, path::PathBuf, sync::OnceLock}; use util; use crate::*; #[derive(Default, Debug)] -pub(crate) struct GoDebugAdapter; +pub(crate) struct GoDebugAdapter { + shim_path: OnceLock, +} impl GoDebugAdapter { const ADAPTER_NAME: &'static str = "Delve"; - const DEFAULT_TIMEOUT_MS: u64 = 60000; + async fn fetch_latest_adapter_version( + delegate: &Arc, + ) -> Result { + let release = latest_github_release( + &"zed-industries/delve-shim-dap", + true, + false, + delegate.http_client(), + ) + .await?; + + let os = match consts::OS { + "macos" => "apple-darwin", + "linux" => "unknown-linux-gnu", + "windows" => "pc-windows-msvc", + other => bail!("Running on unsupported os: {other}"), + }; + let suffix = if consts::OS == "windows" { + ".zip" + } else { + ".tar.gz" + }; + let asset_name = format!("delve-shim-dap-{}-{os}{suffix}", consts::ARCH); + let asset = release + .assets + .iter() + .find(|asset| asset.name == asset_name) + .with_context(|| format!("no asset found matching `{asset_name:?}`"))?; + + Ok(AdapterVersion { + tag_name: release.tag_name, + url: asset.browser_download_url.clone(), + }) + } + async fn install_shim(&self, delegate: &Arc) -> anyhow::Result { + if let Some(path) = self.shim_path.get().cloned() { + return Ok(path); + } + + let asset = Self::fetch_latest_adapter_version(delegate).await?; + let ty = if consts::OS == "windows" { + DownloadedFileType::Zip + } else { + DownloadedFileType::GzipTar + }; + download_adapter_from_github( + "delve-shim-dap".into(), + asset.clone(), + ty, + delegate.as_ref(), + ) + .await?; + + let path = paths::debug_adapters_dir() + .join("delve-shim-dap") + .join(format!("delve-shim-dap{}", asset.tag_name)) + .join("delve-shim-dap"); + self.shim_path.set(path.clone()).ok(); + + Ok(path) + } } #[async_trait(?Send)] @@ -384,16 +449,10 @@ impl DebugAdapter for GoDebugAdapter { adapter_path.join("dlv").to_string_lossy().to_string() }; + let minidelve_path = self.install_shim(delegate).await?; + let tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default(); - let mut tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default(); - - if tcp_connection.timeout.is_none() - || tcp_connection.timeout.unwrap_or(0) < Self::DEFAULT_TIMEOUT_MS - { - tcp_connection.timeout = Some(Self::DEFAULT_TIMEOUT_MS); - } - - let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?; + let (host, port, _) = crate::configure_tcp_connection(tcp_connection).await?; let cwd = task_definition .config @@ -404,6 +463,7 @@ impl DebugAdapter for GoDebugAdapter { let arguments = if cfg!(windows) { vec![ + delve_path, "dap".into(), "--listen".into(), format!("{}:{}", host, port), @@ -411,6 +471,7 @@ impl DebugAdapter for GoDebugAdapter { ] } else { vec![ + delve_path, "dap".into(), "--listen".into(), format!("{}:{}", host, port), @@ -418,15 +479,11 @@ impl DebugAdapter for GoDebugAdapter { }; Ok(DebugAdapterBinary { - command: delve_path, + command: minidelve_path.to_string_lossy().into_owned(), arguments, cwd: Some(cwd), envs: HashMap::default(), - connection: Some(adapters::TcpArguments { - host, - port, - timeout, - }), + connection: None, request_args: StartDebuggingRequestArguments { configuration: task_definition.config.clone(), request: self.validate_config(&task_definition.config)?,