From d23359e19a413a075da5cda3744161e84ac131a3 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 4 Jun 2025 01:37:25 +0200 Subject: [PATCH] debugger: Fix issues with running Zed-installed debugpy + hangs when downloading (#32034) Closes #32018 Release Notes: - Fixed issues with launching Python debug adapter downloaded by Zed. You might need to clear the old install of Debugpy from `$HOME/.local/share/zed/debug_adapters/Debugpy` (Linux) or `$HOME/Library/Application Support/Zed/debug_adapters/Debugpy` (Mac). --- crates/dap/src/adapters.rs | 18 -------- crates/dap_adapters/src/python.rs | 75 ++++++++++++++++++------------- 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/crates/dap/src/adapters.rs b/crates/dap/src/adapters.rs index ac15d6fefa..ce42a9776d 100644 --- a/crates/dap/src/adapters.rs +++ b/crates/dap/src/adapters.rs @@ -333,24 +333,6 @@ pub async fn download_adapter_from_github( Ok(version_path) } -pub async fn fetch_latest_adapter_version_from_github( - github_repo: GithubRepo, - delegate: &dyn DapDelegate, -) -> Result { - let release = latest_github_release( - &format!("{}/{}", github_repo.repo_owner, github_repo.repo_name), - false, - false, - delegate.http_client(), - ) - .await?; - - Ok(AdapterVersion { - tag_name: release.tag_name, - url: release.zipball_url, - }) -} - #[async_trait(?Send)] pub trait DebugAdapter: 'static + Send + Sync { fn name(&self) -> DebugAdapterName; diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs index 343f999aa1..c3d5cada56 100644 --- a/crates/dap_adapters/src/python.rs +++ b/crates/dap_adapters/src/python.rs @@ -1,7 +1,8 @@ use crate::*; use anyhow::Context as _; +use dap::adapters::latest_github_release; use dap::{DebugRequest, StartDebuggingRequestArguments, adapters::DebugTaskDefinition}; -use gpui::{AsyncApp, SharedString}; +use gpui::{AppContext, AsyncApp, SharedString}; use json_dotpath::DotPaths; use language::{LanguageName, Toolchain}; use serde_json::Value; @@ -21,12 +22,13 @@ pub(crate) struct PythonDebugAdapter { impl PythonDebugAdapter { const ADAPTER_NAME: &'static str = "Debugpy"; + const DEBUG_ADAPTER_NAME: DebugAdapterName = + DebugAdapterName(SharedString::new_static(Self::ADAPTER_NAME)); const ADAPTER_PACKAGE_NAME: &'static str = "debugpy"; const ADAPTER_PATH: &'static str = "src/debugpy/adapter"; const LANGUAGE_NAME: &'static str = "Python"; async fn generate_debugpy_arguments( - &self, host: &Ipv4Addr, port: u16, user_installed_path: Option<&Path>, @@ -54,7 +56,7 @@ impl PythonDebugAdapter { format!("--port={}", port), ]) } else { - let adapter_path = paths::debug_adapters_dir().join(self.name().as_ref()); + let adapter_path = paths::debug_adapters_dir().join(Self::DEBUG_ADAPTER_NAME.as_ref()); let file_name_prefix = format!("{}_", Self::ADAPTER_NAME); let debugpy_dir = @@ -107,22 +109,21 @@ impl PythonDebugAdapter { repo_owner: "microsoft".into(), }; - adapters::fetch_latest_adapter_version_from_github(github_repo, delegate.as_ref()).await + fetch_latest_adapter_version_from_github(github_repo, delegate.as_ref()).await } async fn install_binary( - &self, + adapter_name: DebugAdapterName, version: AdapterVersion, - delegate: &Arc, + delegate: Arc, ) -> Result<()> { let version_path = adapters::download_adapter_from_github( - self.name(), + adapter_name, version, - adapters::DownloadedFileType::Zip, + adapters::DownloadedFileType::GzipTar, delegate.as_ref(), ) .await?; - // only needed when you install the latest version for the first time if let Some(debugpy_dir) = util::fs::find_file_name_in_dir(version_path.as_path(), |file_name| { @@ -171,14 +172,13 @@ impl PythonDebugAdapter { let python_command = python_path.context("failed to find binary path for Python")?; log::debug!("Using Python executable: {}", python_command); - let arguments = self - .generate_debugpy_arguments( - &host, - port, - user_installed_path.as_deref(), - installed_in_venv, - ) - .await?; + let arguments = Self::generate_debugpy_arguments( + &host, + port, + user_installed_path.as_deref(), + installed_in_venv, + ) + .await?; log::debug!( "Starting debugpy adapter with command: {} {}", @@ -204,7 +204,7 @@ impl PythonDebugAdapter { #[async_trait(?Send)] impl DebugAdapter for PythonDebugAdapter { fn name(&self) -> DebugAdapterName { - DebugAdapterName(Self::ADAPTER_NAME.into()) + Self::DEBUG_ADAPTER_NAME } fn adapter_language_name(&self) -> Option { @@ -635,7 +635,9 @@ impl DebugAdapter for PythonDebugAdapter { if self.checked.set(()).is_ok() { delegate.output_to_console(format!("Checking latest version of {}...", self.name())); if let Some(version) = self.fetch_latest_adapter_version(delegate).await.log_err() { - self.install_binary(version, delegate).await?; + cx.background_spawn(Self::install_binary(self.name(), version, delegate.clone())) + .await + .context("Failed to install debugpy")?; } } @@ -644,6 +646,24 @@ impl DebugAdapter for PythonDebugAdapter { } } +async fn fetch_latest_adapter_version_from_github( + github_repo: GithubRepo, + delegate: &dyn DapDelegate, +) -> Result { + let release = latest_github_release( + &format!("{}/{}", github_repo.repo_owner, github_repo.repo_name), + false, + false, + delegate.http_client(), + ) + .await?; + + Ok(AdapterVersion { + tag_name: release.tag_name, + url: release.tarball_url, + }) +} + #[cfg(test)] mod tests { use super::*; @@ -651,20 +671,18 @@ mod tests { #[gpui::test] async fn test_debugpy_install_path_cases() { - let adapter = PythonDebugAdapter::default(); let host = Ipv4Addr::new(127, 0, 0, 1); let port = 5678; // Case 1: User-defined debugpy path (highest precedence) let user_path = PathBuf::from("/custom/path/to/debugpy"); - let user_args = adapter - .generate_debugpy_arguments(&host, port, Some(&user_path), false) - .await - .unwrap(); + let user_args = + PythonDebugAdapter::generate_debugpy_arguments(&host, port, Some(&user_path), false) + .await + .unwrap(); // Case 2: Venv-installed debugpy (uses -m debugpy.adapter) - let venv_args = adapter - .generate_debugpy_arguments(&host, port, None, true) + let venv_args = PythonDebugAdapter::generate_debugpy_arguments(&host, port, None, true) .await .unwrap(); @@ -679,9 +697,4 @@ mod tests { // Note: Case 3 (GitHub-downloaded debugpy) is not tested since this requires mocking the Github API. } - - #[test] - fn test_adapter_path_constant() { - assert_eq!(PythonDebugAdapter::ADAPTER_PATH, "src/debugpy/adapter"); - } }