From 8674f1013f3fe71bc6534e6e2f44324a678f5b96 Mon Sep 17 00:00:00 2001 From: Anthony Eid Date: Sun, 20 Oct 2024 03:47:18 -0400 Subject: [PATCH 1/5] Get debugpy version to work --- Cargo.lock | 1 + crates/dap_adapters/Cargo.toml | 1 + crates/dap_adapters/src/python.rs | 65 ++++++++++++++----------------- crates/util/src/fs.rs | 23 ++++++++++- 4 files changed, 53 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9973b2ece813d..6c917f9df1e47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3388,6 +3388,7 @@ dependencies = [ "serde_json", "smol", "task", + "util", ] [[package]] diff --git a/crates/dap_adapters/Cargo.toml b/crates/dap_adapters/Cargo.toml index d6515c69b8a41..44f516763c484 100644 --- a/crates/dap_adapters/Cargo.toml +++ b/crates/dap_adapters/Cargo.toml @@ -21,6 +21,7 @@ fs.workspace = true futures.workspace = true gpui.workspace = true http_client.workspace = true +util.workspace = true task.workspace = true smol.workspace = true serde.workspace = true diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs index 12b16280f0de0..9a4b9ddf76f7e 100644 --- a/crates/dap_adapters/src/python.rs +++ b/crates/dap_adapters/src/python.rs @@ -33,9 +33,15 @@ impl DebugAdapter for PythonDebugAdapter { ) -> Result { let adapter_path = paths::debug_adapters_dir().join(self.name()); + let debugpy_dir = util::fs::find_file_name_in_dir(adapter_path.as_path(), |file_name| { + file_name.starts_with("debugpy_") + }) + .await + .ok_or_else(|| anyhow!("Debugpy directory not found"))?; + Ok(DebugAdapterBinary { command: "python3".to_string(), - arguments: Some(vec![adapter_path.join(Self::ADAPTER_PATH).into()]), + arguments: Some(vec![debugpy_dir.join(Self::ADAPTER_PATH).into()]), envs: None, }) } @@ -58,7 +64,7 @@ impl DebugAdapter for PythonDebugAdapter { let release = latest_github_release("microsoft/debugpy", false, false, http_client.clone()) .await?; - let asset_name = format!("{}.zip", release.tag_name); + let asset_name = format!("{}_{}.zip", self.name(), release.tag_name); let zip_path = debugpy_dir.join(asset_name); @@ -78,42 +84,29 @@ impl DebugAdapter for PythonDebugAdapter { .await? .status; - let mut ls = process::Command::new("ls") - .current_dir(&debugpy_dir) - .stdout(Stdio::piped()) - .spawn()?; - - let std = ls - .stdout - .take() - .ok_or(anyhow!("Failed to list directories"))? - .into_stdio() - .await?; - - let file_name = String::from_utf8( - process::Command::new("grep") - .arg("microsoft-debugpy") - .stdin(std) - .output() - .await? - .stdout, - )?; - - let file_name = file_name.trim_end(); - process::Command::new("sh") - .current_dir(&debugpy_dir) - .arg("-c") - .arg(format!("mv {file_name}/* .")) - .output() + let file_name = + util::fs::find_file_name_in_dir(&debugpy_dir.as_path(), |file_name| { + file_name.starts_with("microsoft-debugpy-") + }) + .await + .ok_or_else(|| anyhow!("Debugpy unzipped directory not found"))?; + + fs.rename( + file_name.as_path(), + debugpy_dir + .join(format!("{}_{}", self.name(), release.tag_name)) + .as_path(), + Default::default(), + ) + .await?; + + fs.remove_file(&zip_path.as_path(), Default::default()) .await?; - process::Command::new("rm") - .current_dir(&debugpy_dir) - .arg("-rf") - .arg(file_name) - .arg(zip_path) - .output() - .await?; + // if !unzip_status.success() { + // dbg!(unzip_status); + // Err(anyhow!("failed to unzip debugpy archive"))?; + // } return Ok(()); } diff --git a/crates/util/src/fs.rs b/crates/util/src/fs.rs index f235753e8b2af..93340729df2b4 100644 --- a/crates/util/src/fs.rs +++ b/crates/util/src/fs.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::ResultExt; use async_fs as fs; @@ -26,3 +26,24 @@ where } } } + +pub async fn find_file_name_in_dir(dir: &Path, predicate: F) -> Option +where + F: Fn(&str) -> bool, +{ + if let Some(mut entries) = fs::read_dir(dir).await.log_err() { + while let Some(entry) = entries.next().await { + if let Some(entry) = entry.log_err() { + let entry_path = entry.path(); + + if let Some(file_name) = entry_path.file_name() { + if predicate(file_name.to_str().unwrap_or("")) { + return Some(entry_path); + } + } + } + } + } + + None +} From aa8ba375a54f38104407eda4d2a360711e5f9921 Mon Sep 17 00:00:00 2001 From: Anthony Eid Date: Tue, 22 Oct 2024 00:11:53 -0400 Subject: [PATCH 2/5] Get dap adapter downloads to use generic trait fn for python --- Cargo.lock | 2 + crates/dap/Cargo.toml | 2 + crates/dap/src/adapters.rs | 101 +++++++++++++++++++++++- crates/dap_adapters/src/custom.rs | 4 + crates/dap_adapters/src/dap_adapters.rs | 2 +- crates/dap_adapters/src/javascript.rs | 9 +++ crates/dap_adapters/src/lldb.rs | 11 ++- crates/dap_adapters/src/php.rs | 9 +++ crates/dap_adapters/src/python.rs | 76 ++---------------- 9 files changed, 139 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c917f9df1e47..00d2d7f6bc5fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3354,12 +3354,14 @@ dependencies = [ "log", "node_runtime", "parking_lot", + "paths", "schemars", "serde", "serde_json", "settings", "smol", "task", + "util", ] [[package]] diff --git a/crates/dap/Cargo.toml b/crates/dap/Cargo.toml index 33971d417bfd1..0e10c401aae94 100644 --- a/crates/dap/Cargo.toml +++ b/crates/dap/Cargo.toml @@ -19,9 +19,11 @@ http_client.workspace = true log.workspace = true node_runtime.workspace = true parking_lot.workspace = true +paths.workspace = true schemars.workspace = true serde.workspace = true serde_json.workspace = true settings.workspace = true smol.workspace = true task.workspace = true +util.workspace = true diff --git a/crates/dap/src/adapters.rs b/crates/dap/src/adapters.rs index 236297eba0151..e8ad9e9f4c943 100644 --- a/crates/dap/src/adapters.rs +++ b/crates/dap/src/adapters.rs @@ -1,14 +1,15 @@ use crate::client::TransportParams; use ::fs::Fs; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use async_trait::async_trait; use futures::AsyncReadExt; use gpui::AsyncAppContext; -use http_client::HttpClient; +use http_client::{github::latest_github_release, HttpClient}; use node_runtime::NodeRuntime; use serde_json::Value; use smol::{ self, + fs::File, io::BufReader, net::{TcpListener, TcpStream}, process, @@ -174,12 +175,96 @@ pub struct DebugAdapterBinary { pub envs: Option>, } +pub enum DebugAdapterDownloadKind { + Github(GithubRepo), + Custom, +} + +async fn download_adapter_from_github( + adapter_name: DebugAdapterName, + github_repo: GithubRepo, + delegate: &dyn DapDelegate, +) -> Result<()> { + let adapter_path = paths::debug_adapters_dir().join(&adapter_name); + let fs = delegate.fs(); + + if fs.is_dir(adapter_path.as_path()).await { + return Ok(()); + } + + if let Some(http_client) = delegate.http_client() { + if !adapter_path.exists() { + fs.create_dir(&adapter_path.as_path()).await?; + } + + let repo_name_with_owner = format!("{}/{}", github_repo.repo_owner, github_repo.repo_name); + let release = + latest_github_release(&repo_name_with_owner, false, false, http_client.clone()).await?; + + let asset_name = format!("{}_{}.zip", &adapter_name, release.tag_name); + let zip_path = adapter_path.join(&asset_name); + + if smol::fs::metadata(&zip_path).await.is_err() { + let mut response = http_client + .get(&release.zipball_url, Default::default(), true) + .await + .context("Error downloading release")?; + + let mut file = File::create(&zip_path).await?; + futures::io::copy(response.body_mut(), &mut file).await?; + + let _unzip_status = process::Command::new("unzip") + .current_dir(&adapter_path) + .arg(&zip_path) + .output() + .await? + .status; + + fs.remove_file(&zip_path.as_path(), Default::default()) + .await?; + + let file_name = util::fs::find_file_name_in_dir(&adapter_path.as_path(), |file_name| { + file_name.contains(&adapter_name.to_string()) + }) + .await + .ok_or_else(|| anyhow!("Unzipped directory not found")); + + let file_name = file_name?; + + fs.rename( + file_name.as_path(), + adapter_path + .join(format!("{}_{}", adapter_name, release.tag_name)) + .as_path(), + Default::default(), + ) + .await?; + + // if !unzip_status.success() { + // dbg!(unzip_status); + // Err(anyhow!("failed to unzip downloaded dap archive"))?; + // } + + return Ok(()); + } + } + + bail!("Install failed to download & counldn't preinstalled dap") +} + +pub struct GithubRepo { + pub repo_name: String, + pub repo_owner: String, +} + #[async_trait(?Send)] pub trait DebugAdapter: 'static + Send + Sync { fn id(&self) -> String { "".to_string() } + fn download_kind(&self) -> DebugAdapterDownloadKind; + fn name(&self) -> DebugAdapterName; async fn connect( @@ -191,7 +276,17 @@ pub trait DebugAdapter: 'static + Send + Sync { /// Installs the binary for the debug adapter. /// This method is called when the adapter binary is not found or needs to be updated. /// It should download and install the necessary files for the debug adapter to function. - async fn install_binary(&self, delegate: &dyn DapDelegate) -> Result<()>; + async fn install_binary(&self, delegate: &dyn DapDelegate) -> Result<()> { + let adapter_name = self.name(); + let download_kind = self.download_kind(); + + match download_kind { + DebugAdapterDownloadKind::Github(github_repo) => { + download_adapter_from_github(adapter_name, github_repo, delegate).await + } + DebugAdapterDownloadKind::Custom => Ok(()), + } + } async fn fetch_binary( &self, diff --git a/crates/dap_adapters/src/custom.rs b/crates/dap_adapters/src/custom.rs index a33e1802839b5..9a0f8f2c04a22 100644 --- a/crates/dap_adapters/src/custom.rs +++ b/crates/dap_adapters/src/custom.rs @@ -24,6 +24,10 @@ impl DebugAdapter for CustomDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } + fn download_kind(&self) -> DebugAdapterDownloadKind { + DebugAdapterDownloadKind::Custom + } + async fn connect( &self, adapter_binary: &DebugAdapterBinary, diff --git a/crates/dap_adapters/src/dap_adapters.rs b/crates/dap_adapters/src/dap_adapters.rs index fac4f3c77c737..80491f2d7c041 100644 --- a/crates/dap_adapters/src/dap_adapters.rs +++ b/crates/dap_adapters/src/dap_adapters.rs @@ -15,7 +15,7 @@ use async_trait::async_trait; use dap::{ adapters::{ create_stdio_client, create_tcp_client, DapDelegate, DebugAdapter, DebugAdapterBinary, - DebugAdapterName, + DebugAdapterDownloadKind, DebugAdapterName, GithubRepo, }, client::TransportParams, }; diff --git a/crates/dap_adapters/src/javascript.rs b/crates/dap_adapters/src/javascript.rs index 185a785a6ff4c..405fbc5e1664b 100644 --- a/crates/dap_adapters/src/javascript.rs +++ b/crates/dap_adapters/src/javascript.rs @@ -18,6 +18,15 @@ impl DebugAdapter for JsDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } + fn download_kind(&self) -> DebugAdapterDownloadKind { + let repo_name = "microsoft".to_string(); + let repo_owner = "vscode-js-debug".to_string(); + DebugAdapterDownloadKind::Github(GithubRepo { + repo_name, + repo_owner, + }) + } + async fn connect( &self, adapter_binary: &DebugAdapterBinary, diff --git a/crates/dap_adapters/src/lldb.rs b/crates/dap_adapters/src/lldb.rs index 56cda6750a275..3b4164ca616b6 100644 --- a/crates/dap_adapters/src/lldb.rs +++ b/crates/dap_adapters/src/lldb.rs @@ -21,6 +21,13 @@ impl DebugAdapter for LldbDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } + fn download_kind(&self) -> DebugAdapterDownloadKind { + DebugAdapterDownloadKind::Github(GithubRepo { + repo_name: "llvm-project".to_string(), + repo_owner: "llvm".to_string(), + }) + } + async fn connect( &self, adapter_binary: &DebugAdapterBinary, @@ -29,10 +36,6 @@ impl DebugAdapter for LldbDebugAdapter { create_stdio_client(adapter_binary) } - async fn install_binary(&self, _: &dyn DapDelegate) -> Result<()> { - bail!("Install or fetch not implemented for lldb debug adapter (yet)") - } - async fn fetch_binary( &self, _: &dyn DapDelegate, diff --git a/crates/dap_adapters/src/php.rs b/crates/dap_adapters/src/php.rs index 62ecb16506bb8..b8ebf9905be75 100644 --- a/crates/dap_adapters/src/php.rs +++ b/crates/dap_adapters/src/php.rs @@ -18,6 +18,15 @@ impl DebugAdapter for PhpDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } + fn download_kind(&self) -> DebugAdapterDownloadKind { + let repo_name = "xdebug".to_string(); + let repo_owner = "vscode-php-debug".to_string(); + DebugAdapterDownloadKind::Github(GithubRepo { + repo_name, + repo_owner, + }) + } + async fn connect( &self, adapter_binary: &DebugAdapterBinary, diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs index 9a4b9ddf76f7e..dba24435a0170 100644 --- a/crates/dap_adapters/src/python.rs +++ b/crates/dap_adapters/src/python.rs @@ -18,6 +18,13 @@ impl DebugAdapter for PythonDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } + fn download_kind(&self) -> DebugAdapterDownloadKind { + DebugAdapterDownloadKind::Github(GithubRepo { + repo_name: "debugpy".to_string(), + repo_owner: "microsoft".to_string(), + }) + } + async fn connect( &self, adapter_binary: &DebugAdapterBinary, @@ -46,75 +53,6 @@ impl DebugAdapter for PythonDebugAdapter { }) } - async fn install_binary(&self, delegate: &dyn DapDelegate) -> Result<()> { - let adapter_path = paths::debug_adapters_dir().join(self.name()); - let fs = delegate.fs(); - - if fs.is_dir(adapter_path.as_path()).await { - return Ok(()); - } - - if let Some(http_client) = delegate.http_client() { - let debugpy_dir = paths::debug_adapters_dir().join("debugpy"); - - if !debugpy_dir.exists() { - fs.create_dir(&debugpy_dir.as_path()).await?; - } - - let release = - latest_github_release("microsoft/debugpy", false, false, http_client.clone()) - .await?; - let asset_name = format!("{}_{}.zip", self.name(), release.tag_name); - - let zip_path = debugpy_dir.join(asset_name); - - if fs::metadata(&zip_path).await.is_err() { - let mut response = http_client - .get(&release.zipball_url, Default::default(), true) - .await - .context("Error downloading release")?; - - let mut file = File::create(&zip_path).await?; - futures::io::copy(response.body_mut(), &mut file).await?; - - let _unzip_status = process::Command::new("unzip") - .current_dir(&debugpy_dir) - .arg(&zip_path) - .output() - .await? - .status; - - let file_name = - util::fs::find_file_name_in_dir(&debugpy_dir.as_path(), |file_name| { - file_name.starts_with("microsoft-debugpy-") - }) - .await - .ok_or_else(|| anyhow!("Debugpy unzipped directory not found"))?; - - fs.rename( - file_name.as_path(), - debugpy_dir - .join(format!("{}_{}", self.name(), release.tag_name)) - .as_path(), - Default::default(), - ) - .await?; - - fs.remove_file(&zip_path.as_path(), Default::default()) - .await?; - - // if !unzip_status.success() { - // dbg!(unzip_status); - // Err(anyhow!("failed to unzip debugpy archive"))?; - // } - - return Ok(()); - } - } - - bail!("Install or fetch not implemented for Python debug adapter (yet)"); - } - fn request_args(&self, config: &DebugAdapterConfig) -> Value { json!({"program": config.program, "subProcess": true}) } From f5c186a2f0e8e34963badd0cb3bd8571806d5a56 Mon Sep 17 00:00:00 2001 From: Anthony Eid Date: Tue, 22 Oct 2024 01:38:08 -0400 Subject: [PATCH 3/5] Get lldb-dap working when on macos --- crates/dap_adapters/src/lldb.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/dap_adapters/src/lldb.rs b/crates/dap_adapters/src/lldb.rs index 5a9bb9edd71b9..923dabce4b956 100644 --- a/crates/dap_adapters/src/lldb.rs +++ b/crates/dap_adapters/src/lldb.rs @@ -38,7 +38,25 @@ impl DebugAdapter for LldbDebugAdapter { _: &dyn DapDelegate, _: &DebugAdapterConfig, ) -> Result { - bail!("Install or fetch not implemented for lldb debug adapter (yet)") + #[cfg(target_os = "macos")] + { + let output = std::process::Command::new("xcrun") + .args(&["-f", "lldb-dap"]) + .output()?; + let lldb_dap_path = String::from_utf8(output.stdout)?.trim().to_string(); + + Ok(DebugAdapterBinary { + command: lldb_dap_path, + arguments: None, + envs: None, + }) + } + #[cfg(not(target_os = "macos"))] + { + Err(anyhow::anyhow!( + "LLDB-DAP is only supported on macOS (Right now)" + )) + } } fn request_args(&self, config: &DebugAdapterConfig) -> Value { From fb3375c1d262db3671116c9040748542bff59d3d Mon Sep 17 00:00:00 2001 From: Anthony Eid Date: Wed, 23 Oct 2024 03:28:53 -0400 Subject: [PATCH 4/5] Add release tag to name of downloaded DAPs --- crates/dap/src/adapters.rs | 44 +++------ crates/dap_adapters/src/custom.rs | 4 - crates/dap_adapters/src/dap_adapters.rs | 12 +-- crates/dap_adapters/src/javascript.rs | 123 +++++------------------- crates/dap_adapters/src/lldb.rs | 11 +-- crates/dap_adapters/src/php.rs | 121 +++++------------------ crates/dap_adapters/src/python.rs | 16 +-- 7 files changed, 79 insertions(+), 252 deletions(-) diff --git a/crates/dap/src/adapters.rs b/crates/dap/src/adapters.rs index 33f0da6315ecd..02e221088972f 100644 --- a/crates/dap/src/adapters.rs +++ b/crates/dap/src/adapters.rs @@ -6,7 +6,13 @@ use http_client::{github::latest_github_release, HttpClient}; use node_runtime::NodeRuntime; use serde_json::Value; use smol::{self, fs::File, process}; -use std::{collections::HashMap, ffi::OsString, fmt::Debug, path::Path, sync::Arc}; +use std::{ + collections::HashMap, + ffi::OsString, + fmt::Debug, + path::{Path, PathBuf}, + sync::Arc, +}; use task::DebugAdapterConfig; pub trait DapDelegate { @@ -36,23 +42,14 @@ pub struct DebugAdapterBinary { pub envs: Option>, } -pub enum DebugAdapterDownloadKind { - Github(GithubRepo), - Custom, -} - -async fn download_adapter_from_github( +pub async fn download_adapter_from_github( adapter_name: DebugAdapterName, github_repo: GithubRepo, delegate: &dyn DapDelegate, -) -> Result<()> { +) -> Result { let adapter_path = paths::debug_adapters_dir().join(&adapter_name); let fs = delegate.fs(); - if fs.is_dir(adapter_path.as_path()).await { - return Ok(()); - } - if let Some(http_client) = delegate.http_client() { if !adapter_path.exists() { fs.create_dir(&adapter_path.as_path()).await?; @@ -91,12 +88,13 @@ async fn download_adapter_from_github( .ok_or_else(|| anyhow!("Unzipped directory not found")); let file_name = file_name?; + let downloaded_path = adapter_path + .join(format!("{}_{}", adapter_name, release.tag_name)) + .to_owned(); fs.rename( file_name.as_path(), - adapter_path - .join(format!("{}_{}", adapter_name, release.tag_name)) - .as_path(), + downloaded_path.as_path(), Default::default(), ) .await?; @@ -106,7 +104,7 @@ async fn download_adapter_from_github( // Err(anyhow!("failed to unzip downloaded dap archive"))?; // } - return Ok(()); + return Ok(downloaded_path); } } @@ -124,8 +122,6 @@ pub trait DebugAdapter: 'static + Send + Sync { "".to_string() } - fn download_kind(&self) -> DebugAdapterDownloadKind; - fn name(&self) -> DebugAdapterName; fn transport(&self) -> Box; @@ -133,17 +129,7 @@ pub trait DebugAdapter: 'static + Send + Sync { /// Installs the binary for the debug adapter. /// This method is called when the adapter binary is not found or needs to be updated. /// It should download and install the necessary files for the debug adapter to function. - async fn install_binary(&self, delegate: &dyn DapDelegate) -> Result<()> { - let adapter_name = self.name(); - let download_kind = self.download_kind(); - - match download_kind { - DebugAdapterDownloadKind::Github(github_repo) => { - download_adapter_from_github(adapter_name, github_repo, delegate).await - } - DebugAdapterDownloadKind::Custom => Ok(()), - } - } + async fn install_binary(&self, delegate: &dyn DapDelegate) -> Result<()>; async fn fetch_binary( &self, diff --git a/crates/dap_adapters/src/custom.rs b/crates/dap_adapters/src/custom.rs index 3aca4aa10dc48..2ad9cd9750074 100644 --- a/crates/dap_adapters/src/custom.rs +++ b/crates/dap_adapters/src/custom.rs @@ -25,10 +25,6 @@ impl DebugAdapter for CustomDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn download_kind(&self) -> DebugAdapterDownloadKind { - DebugAdapterDownloadKind::Custom - } - fn transport(&self) -> Box { match &self.custom_args.connection { DebugConnectionType::STDIO => Box::new(StdioTransport::new()), diff --git a/crates/dap_adapters/src/dap_adapters.rs b/crates/dap_adapters/src/dap_adapters.rs index 796a732202d08..39edd6dfae3dd 100644 --- a/crates/dap_adapters/src/dap_adapters.rs +++ b/crates/dap_adapters/src/dap_adapters.rs @@ -4,24 +4,18 @@ mod lldb; mod php; mod python; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{anyhow, bail, Result}; use async_trait::async_trait; use custom::CustomDebugAdapter; use dap::adapters::{ - DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterDownloadKind, DebugAdapterName, - GithubRepo, + self, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, GithubRepo, }; -use http_client::github::latest_github_release; use javascript::JsDebugAdapter; use lldb::LldbDebugAdapter; use php::PhpDebugAdapter; use python::PythonDebugAdapter; use serde_json::{json, Value}; -use smol::{ - fs::{self, File}, - process, -}; -use std::{fmt::Debug, process::Stdio}; +use std::fmt::Debug; use task::{CustomArgs, DebugAdapterConfig, DebugAdapterKind, DebugConnectionType, TCPHost}; pub fn build_adapter(adapter_config: &DebugAdapterConfig) -> Result> { diff --git a/crates/dap_adapters/src/javascript.rs b/crates/dap_adapters/src/javascript.rs index 1925e8ea253d7..dc4f4d02bd9f9 100644 --- a/crates/dap_adapters/src/javascript.rs +++ b/crates/dap_adapters/src/javascript.rs @@ -20,13 +20,6 @@ impl DebugAdapter for JsDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn download_kind(&self) -> DebugAdapterDownloadKind { - DebugAdapterDownloadKind::Github(GithubRepo { - repo_name: "vscode-js-debug".into(), - repo_owner: "microsoft".into(), - }) - } - fn transport(&self) -> Box { Box::new(TcpTransport::new(TCPHost { port: Some(8133), @@ -45,6 +38,11 @@ impl DebugAdapter for JsDebugAdapter { .ok_or(anyhow!("Couldn't get npm runtime"))?; let adapter_path = paths::debug_adapters_dir().join(self.name()); + let adapter_path = util::fs::find_file_name_in_dir(adapter_path.as_path(), |file_name| { + file_name.starts_with("vscode-js-debug_") + }) + .await + .ok_or_else(|| anyhow!("Couldn't find javascript dap directory"))?; Ok(DebugAdapterBinary { command: node_runtime @@ -61,102 +59,29 @@ impl DebugAdapter for JsDebugAdapter { } async fn install_binary(&self, delegate: &dyn DapDelegate) -> Result<()> { - let adapter_path = paths::debug_adapters_dir().join(self.name()); - let fs = delegate.fs(); - - if fs.is_dir(adapter_path.as_path()).await { - return Ok(()); - } - - if let Some(http_client) = delegate.http_client() { - if !adapter_path.exists() { - fs.create_dir(&adapter_path.as_path()).await?; - } - - let release = latest_github_release( - "microsoft/vscode-js-debug", - false, - false, - http_client.clone(), - ) - .await?; - - let asset_name = format!("{}-{}", self.name(), release.tag_name); - let zip_path = adapter_path.join(asset_name); - - if fs::metadata(&zip_path).await.is_err() { - let mut response = http_client - .get(&release.zipball_url, Default::default(), true) - .await - .context("Error downloading release")?; + let github_repo = GithubRepo { + repo_name: "vscode-js-debug".to_string(), + repo_owner: "microsoft".to_string(), + }; - let mut file = File::create(&zip_path).await?; - futures::io::copy(response.body_mut(), &mut file).await?; + let adapter_path = + adapters::download_adapter_from_github(self.name(), github_repo, delegate).await?; - let _unzip_status = process::Command::new("unzip") - .current_dir(&adapter_path) - .arg(&zip_path) - .output() - .await? - .status; - - let mut ls = process::Command::new("ls") - .current_dir(&adapter_path) - .stdout(Stdio::piped()) - .spawn()?; - - let std = ls - .stdout - .take() - .ok_or(anyhow!("Failed to list directories"))? - .into_stdio() - .await?; - - let file_name = String::from_utf8( - process::Command::new("grep") - .arg("microsoft-vscode-js-debug") - .stdin(std) - .output() - .await? - .stdout, - )?; - - let file_name = file_name.trim_end(); - - process::Command::new("sh") - .current_dir(&adapter_path) - .arg("-c") - .arg(format!("mv {file_name}/* .")) - .output() - .await?; - - process::Command::new("rm") - .current_dir(&adapter_path) - .arg("-rf") - .arg(file_name) - .arg(zip_path) - .output() - .await?; - - let _ = delegate - .node_runtime() - .ok_or(anyhow!("Couldn't get npm runtime"))? - .run_npm_subcommand(&adapter_path, "install", &[]) - .await - .ok(); - - let _ = delegate - .node_runtime() - .ok_or(anyhow!("Couldn't get npm runtime"))? - .run_npm_subcommand(&adapter_path, "run", &["compile"]) - .await - .ok(); + let _ = delegate + .node_runtime() + .ok_or(anyhow!("Couldn't get npm runtime"))? + .run_npm_subcommand(&adapter_path, "install", &[]) + .await + .ok(); - return Ok(()); - } - } + let _ = delegate + .node_runtime() + .ok_or(anyhow!("Couldn't get npm runtime"))? + .run_npm_subcommand(&adapter_path, "run", &["compile"]) + .await + .ok(); - bail!("Install or fetch not implemented for Javascript debug adapter (yet)"); + return Ok(()); } fn request_args(&self, config: &DebugAdapterConfig) -> Value { diff --git a/crates/dap_adapters/src/lldb.rs b/crates/dap_adapters/src/lldb.rs index 923dabce4b956..0911597e0490c 100644 --- a/crates/dap_adapters/src/lldb.rs +++ b/crates/dap_adapters/src/lldb.rs @@ -22,17 +22,14 @@ impl DebugAdapter for LldbDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn download_kind(&self) -> DebugAdapterDownloadKind { - DebugAdapterDownloadKind::Github(GithubRepo { - repo_name: "llvm-project".to_string(), - repo_owner: "llvm".to_string(), - }) - } - fn transport(&self) -> Box { Box::new(StdioTransport::new()) } + async fn install_binary(&self, _delegate: &dyn DapDelegate) -> Result<()> { + bail!("Install binary is not support for install_binary (yet)") + } + async fn fetch_binary( &self, _: &dyn DapDelegate, diff --git a/crates/dap_adapters/src/php.rs b/crates/dap_adapters/src/php.rs index ad4950bc4749e..f9cf3860018ca 100644 --- a/crates/dap_adapters/src/php.rs +++ b/crates/dap_adapters/src/php.rs @@ -20,15 +20,6 @@ impl DebugAdapter for PhpDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn download_kind(&self) -> DebugAdapterDownloadKind { - let repo_name = "xdebug".to_string(); - let repo_owner = "vscode-php-debug".to_string(); - DebugAdapterDownloadKind::Github(GithubRepo { - repo_name, - repo_owner, - }) - } - fn transport(&self) -> Box { Box::new(TcpTransport::new(TCPHost { port: Some(8132), @@ -47,6 +38,11 @@ impl DebugAdapter for PhpDebugAdapter { .ok_or(anyhow!("Couldn't get npm runtime"))?; let adapter_path = paths::debug_adapters_dir().join(self.name()); + let adapter_path = util::fs::find_file_name_in_dir(adapter_path.as_path(), |file_name| { + file_name.starts_with("vscode-php-debug_") + }) + .await + .ok_or_else(|| anyhow!("Couldn't find javascript dap directory"))?; Ok(DebugAdapterBinary { command: node_runtime @@ -63,98 +59,29 @@ impl DebugAdapter for PhpDebugAdapter { } async fn install_binary(&self, delegate: &dyn DapDelegate) -> Result<()> { - let adapter_path = paths::debug_adapters_dir().join(self.name()); - let fs = delegate.fs(); - - if fs.is_dir(adapter_path.as_path()).await { - return Ok(()); - } - - if let Some(http_client) = delegate.http_client() { - if !adapter_path.exists() { - fs.create_dir(&adapter_path.as_path()).await?; - } - - let release = - latest_github_release("xdebug/vscode-php-debug", false, false, http_client.clone()) - .await?; - - let asset_name = format!("{}-{}", self.name(), release.tag_name); - let zip_path = adapter_path.join(asset_name); - - if fs::metadata(&zip_path).await.is_err() { - let mut response = http_client - .get(&release.zipball_url, Default::default(), true) - .await - .context("Error downloading release")?; + let github_repo = GithubRepo { + repo_name: "vscode-php-debug".to_string(), + repo_owner: "xdebug".to_string(), + }; - let mut file = File::create(&zip_path).await?; - futures::io::copy(response.body_mut(), &mut file).await?; + let adapter_path = + adapters::download_adapter_from_github(self.name(), github_repo, delegate).await?; - let _unzip_status = process::Command::new("unzip") - .current_dir(&adapter_path) - .arg(&zip_path) - .output() - .await? - .status; - - let mut ls = process::Command::new("ls") - .current_dir(&adapter_path) - .stdout(Stdio::piped()) - .spawn()?; - - let std = ls - .stdout - .take() - .ok_or(anyhow!("Failed to list directories"))? - .into_stdio() - .await?; - - let file_name = String::from_utf8( - process::Command::new("grep") - .arg("xdebug-vscode-php-debug") - .stdin(std) - .output() - .await? - .stdout, - )?; - - let file_name = file_name.trim_end(); - - process::Command::new("sh") - .current_dir(&adapter_path) - .arg("-c") - .arg(format!("mv {file_name}/* .")) - .output() - .await?; - - process::Command::new("rm") - .current_dir(&adapter_path) - .arg("-rf") - .arg(file_name) - .arg(zip_path) - .output() - .await?; - - let _ = delegate - .node_runtime() - .ok_or(anyhow!("Couldn't get npm runtime"))? - .run_npm_subcommand(&adapter_path, "install", &[]) - .await - .is_ok(); - - let _ = delegate - .node_runtime() - .ok_or(anyhow!("Couldn't get npm runtime"))? - .run_npm_subcommand(&adapter_path, "run", &["build"]) - .await - .is_ok(); + let _ = delegate + .node_runtime() + .ok_or(anyhow!("Couldn't get npm runtime"))? + .run_npm_subcommand(&adapter_path, "install", &[]) + .await + .is_ok(); - return Ok(()); - } - } + let _ = delegate + .node_runtime() + .ok_or(anyhow!("Couldn't get npm runtime"))? + .run_npm_subcommand(&adapter_path, "run", &["build"]) + .await + .is_ok(); - bail!("Install or fetch not implemented for PHP debug adapter (yet)"); + Ok(()) } fn request_args(&self, config: &DebugAdapterConfig) -> Value { diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs index 3312ead931c69..e339289b8d0a5 100644 --- a/crates/dap_adapters/src/python.rs +++ b/crates/dap_adapters/src/python.rs @@ -20,17 +20,19 @@ impl DebugAdapter for PythonDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn download_kind(&self) -> DebugAdapterDownloadKind { - DebugAdapterDownloadKind::Github(GithubRepo { - repo_name: "debugpy".to_string(), - repo_owner: "microsoft".to_string(), - }) - } - fn transport(&self) -> Box { Box::new(StdioTransport::new()) } + async fn install_binary(&self, delegate: &dyn DapDelegate) -> Result<()> { + let github_repo = GithubRepo { + repo_name: "debugpy".into(), + repo_owner: "microsoft".into(), + }; + + adapters::download_adapter_from_github(self.name(), github_repo, delegate).await?; + Ok(()) + } async fn fetch_binary( &self, _: &dyn DapDelegate, From 62fd388c4db14f103a78a9468e07a66956f4e865 Mon Sep 17 00:00:00 2001 From: Anthony Eid Date: Wed, 23 Oct 2024 04:11:07 -0400 Subject: [PATCH 5/5] Check if adapter is already installed before installing one --- crates/project/src/dap_store.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/crates/project/src/dap_store.rs b/crates/project/src/dap_store.rs index 40a242a83d4ec..4966deaecc8a2 100644 --- a/crates/project/src/dap_store.rs +++ b/crates/project/src/dap_store.rs @@ -250,17 +250,22 @@ impl DapStore { .context("Creating debug adapter") .log_err()?, ); - let _ = adapter - .install_binary(&adapter_delegate) - .await - .context("Failed to install debug adapter binary") - .log_err()?; - let binary = adapter - .fetch_binary(&adapter_delegate, &config) - .await - .context("Failed to get debug adapter binary") - .log_err()?; + let mut binary = adapter.fetch_binary(&adapter_delegate, &config).await.ok(); + + if binary.is_none() { + let _ = adapter + .install_binary(&adapter_delegate) + .await + .context("Failed to install debug adapter binary") + .log_err()?; + + binary = adapter + .fetch_binary(&adapter_delegate, &config) + .await + .context("Failed to get debug adapter binary") + .log_err(); + } let mut request_args = json!({}); if let Some(config_args) = config.initialize_args.clone() { @@ -277,7 +282,7 @@ impl DapStore { client .start( - &binary, + &binary?, move |message, cx| { dap_store .update(cx, |_, cx| {