python: Use pip provided by our 'base' venv (#36414)
Closes #36218 Release Notes: - Debugger: Python debugger installation no longer assumes that pip is available in global Python installation
This commit is contained in:
parent
db31fa67f3
commit
9b78c46902
1 changed files with 48 additions and 10 deletions
|
@ -24,6 +24,7 @@ use util::{ResultExt, maybe};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct PythonDebugAdapter {
|
pub(crate) struct PythonDebugAdapter {
|
||||||
|
base_venv_path: OnceCell<Result<Arc<Path>, String>>,
|
||||||
debugpy_whl_base_path: OnceCell<Result<Arc<Path>, String>>,
|
debugpy_whl_base_path: OnceCell<Result<Arc<Path>, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,14 +92,12 @@ impl PythonDebugAdapter {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_wheel(delegate: &Arc<dyn DapDelegate>) -> Result<Arc<Path>, String> {
|
async fn fetch_wheel(&self, delegate: &Arc<dyn DapDelegate>) -> Result<Arc<Path>, String> {
|
||||||
let system_python = Self::system_python_name(delegate)
|
|
||||||
.await
|
|
||||||
.ok_or_else(|| String::from("Could not find a Python installation"))?;
|
|
||||||
let command: &OsStr = system_python.as_ref();
|
|
||||||
let download_dir = debug_adapters_dir().join(Self::ADAPTER_NAME).join("wheels");
|
let download_dir = debug_adapters_dir().join(Self::ADAPTER_NAME).join("wheels");
|
||||||
std::fs::create_dir_all(&download_dir).map_err(|e| e.to_string())?;
|
std::fs::create_dir_all(&download_dir).map_err(|e| e.to_string())?;
|
||||||
let installation_succeeded = util::command::new_smol_command(command)
|
let system_python = self.base_venv_path(delegate).await?;
|
||||||
|
|
||||||
|
let installation_succeeded = util::command::new_smol_command(system_python.as_ref())
|
||||||
.args([
|
.args([
|
||||||
"-m",
|
"-m",
|
||||||
"pip",
|
"pip",
|
||||||
|
@ -114,7 +113,7 @@ impl PythonDebugAdapter {
|
||||||
.status
|
.status
|
||||||
.success();
|
.success();
|
||||||
if !installation_succeeded {
|
if !installation_succeeded {
|
||||||
return Err("debugpy installation failed".into());
|
return Err("debugpy installation failed (could not fetch Debugpy's wheel)".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let wheel_path = std::fs::read_dir(&download_dir)
|
let wheel_path = std::fs::read_dir(&download_dir)
|
||||||
|
@ -139,7 +138,7 @@ impl PythonDebugAdapter {
|
||||||
Ok(Arc::from(wheel_path.path()))
|
Ok(Arc::from(wheel_path.path()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn maybe_fetch_new_wheel(delegate: &Arc<dyn DapDelegate>) {
|
async fn maybe_fetch_new_wheel(&self, delegate: &Arc<dyn DapDelegate>) {
|
||||||
let latest_release = delegate
|
let latest_release = delegate
|
||||||
.http_client()
|
.http_client()
|
||||||
.get(
|
.get(
|
||||||
|
@ -191,7 +190,7 @@ impl PythonDebugAdapter {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.ok()?;
|
.ok()?;
|
||||||
Self::fetch_wheel(delegate).await.ok()?;
|
self.fetch_wheel(delegate).await.ok()?;
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
})
|
})
|
||||||
|
@ -204,7 +203,7 @@ impl PythonDebugAdapter {
|
||||||
) -> Result<Arc<Path>, String> {
|
) -> Result<Arc<Path>, String> {
|
||||||
self.debugpy_whl_base_path
|
self.debugpy_whl_base_path
|
||||||
.get_or_init(|| async move {
|
.get_or_init(|| async move {
|
||||||
Self::maybe_fetch_new_wheel(delegate).await;
|
self.maybe_fetch_new_wheel(delegate).await;
|
||||||
Ok(Arc::from(
|
Ok(Arc::from(
|
||||||
debug_adapters_dir()
|
debug_adapters_dir()
|
||||||
.join(Self::ADAPTER_NAME)
|
.join(Self::ADAPTER_NAME)
|
||||||
|
@ -217,6 +216,45 @@ impl PythonDebugAdapter {
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn base_venv_path(&self, delegate: &Arc<dyn DapDelegate>) -> Result<Arc<Path>, String> {
|
||||||
|
self.base_venv_path
|
||||||
|
.get_or_init(|| async {
|
||||||
|
let base_python = Self::system_python_name(delegate)
|
||||||
|
.await
|
||||||
|
.ok_or_else(|| String::from("Could not find a Python installation"))?;
|
||||||
|
|
||||||
|
let did_succeed = util::command::new_smol_command(base_python)
|
||||||
|
.args(["-m", "venv", "zed_base_venv"])
|
||||||
|
.current_dir(
|
||||||
|
paths::debug_adapters_dir().join(Self::DEBUG_ADAPTER_NAME.as_ref()),
|
||||||
|
)
|
||||||
|
.spawn()
|
||||||
|
.map_err(|e| format!("{e:#?}"))?
|
||||||
|
.status()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("{e:#?}"))?
|
||||||
|
.success();
|
||||||
|
if !did_succeed {
|
||||||
|
return Err("Failed to create base virtual environment".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
const DIR: &'static str = if cfg!(target_os = "windows") {
|
||||||
|
"Scripts"
|
||||||
|
} else {
|
||||||
|
"bin"
|
||||||
|
};
|
||||||
|
Ok(Arc::from(
|
||||||
|
paths::debug_adapters_dir()
|
||||||
|
.join(Self::DEBUG_ADAPTER_NAME.as_ref())
|
||||||
|
.join("zed_base_venv")
|
||||||
|
.join(DIR)
|
||||||
|
.join("python3")
|
||||||
|
.as_ref(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
async fn system_python_name(delegate: &Arc<dyn DapDelegate>) -> Option<String> {
|
async fn system_python_name(delegate: &Arc<dyn DapDelegate>) -> Option<String> {
|
||||||
const BINARY_NAMES: [&str; 3] = ["python3", "python", "py"];
|
const BINARY_NAMES: [&str; 3] = ["python3", "python", "py"];
|
||||||
let mut name = None;
|
let mut name = None;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue