Fix toolchain detection for worktree-local paths (#20229)

Reimplements `pet::EnvironmentApi`, trying to access the `project_env`
first
Closes #20177 

Release Notes:

- Fixed python toolchain detection when worktree local path is set
This commit is contained in:
Stanislav Alekseev 2024-11-05 15:25:18 +02:00 committed by GitHub
parent f8bd6c66f4
commit a26c0a8537
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 132 additions and 13 deletions

View file

@ -47,6 +47,7 @@ lsp.workspace = true
node_runtime.workspace = true
paths.workspace = true
pet.workspace = true
pet-fs.workspace = true
pet-core.workspace = true
pet-conda.workspace = true
pet-poetry.workspace = true

View file

@ -11,11 +11,13 @@ use language::ToolchainLister;
use language::{ContextProvider, LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary;
use node_runtime::NodeRuntime;
use pet_core::os_environment::Environment;
use pet_core::python_environment::PythonEnvironmentKind;
use pet_core::Configuration;
use project::lsp_store::language_server_settings;
use serde_json::Value;
use std::sync::Mutex;
use std::{
any::Any,
borrow::Cow,
@ -380,8 +382,13 @@ fn env_priority(kind: Option<PythonEnvironmentKind>) -> usize {
#[async_trait(?Send)]
impl ToolchainLister for PythonToolchainProvider {
async fn list(&self, worktree_root: PathBuf) -> ToolchainList {
let environment = pet_core::os_environment::EnvironmentApi::new();
async fn list(
&self,
worktree_root: PathBuf,
project_env: Option<HashMap<String, String>>,
) -> ToolchainList {
let env = project_env.unwrap_or_default();
let environment = EnvironmentApi::from_env(&env);
let locators = pet::locators::create_locators(
Arc::new(pet_conda::Conda::from(&environment)),
Arc::new(pet_poetry::Poetry::from(&environment)),
@ -427,6 +434,78 @@ impl ToolchainLister for PythonToolchainProvider {
}
}
pub struct EnvironmentApi<'a> {
global_search_locations: Arc<Mutex<Vec<PathBuf>>>,
project_env: &'a HashMap<String, String>,
pet_env: pet_core::os_environment::EnvironmentApi,
}
impl<'a> EnvironmentApi<'a> {
pub fn from_env(project_env: &'a HashMap<String, String>) -> Self {
let paths = project_env
.get("PATH")
.map(|p| std::env::split_paths(p).collect())
.unwrap_or_default();
EnvironmentApi {
global_search_locations: Arc::new(Mutex::new(paths)),
project_env,
pet_env: pet_core::os_environment::EnvironmentApi::new(),
}
}
fn user_home(&self) -> Option<PathBuf> {
self.project_env
.get("HOME")
.or_else(|| self.project_env.get("USERPROFILE"))
.map(|home| pet_fs::path::norm_case(PathBuf::from(home)))
.or_else(|| self.pet_env.get_user_home())
}
}
impl<'a> pet_core::os_environment::Environment for EnvironmentApi<'a> {
fn get_user_home(&self) -> Option<PathBuf> {
self.user_home()
}
fn get_root(&self) -> Option<PathBuf> {
None
}
fn get_env_var(&self, key: String) -> Option<String> {
self.project_env
.get(&key)
.cloned()
.or_else(|| self.pet_env.get_env_var(key))
}
fn get_know_global_search_locations(&self) -> Vec<PathBuf> {
if self.global_search_locations.lock().unwrap().is_empty() {
let mut paths =
std::env::split_paths(&self.get_env_var("PATH".to_string()).unwrap_or_default())
.collect::<Vec<PathBuf>>();
log::trace!("Env PATH: {:?}", paths);
for p in self.pet_env.get_know_global_search_locations() {
if !paths.contains(&p) {
paths.push(p);
}
}
let mut paths = paths
.into_iter()
.filter(|p| p.exists())
.collect::<Vec<PathBuf>>();
self.global_search_locations
.lock()
.unwrap()
.append(&mut paths);
}
self.global_search_locations.lock().unwrap().clone()
}
}
#[cfg(test)]
mod tests {
use gpui::{BorrowAppContext, Context, ModelContext, TestAppContext};