Skip to content

Commit 4ad900b

Browse files
Copilotkarthiknadig
andcommitted
Add LocatorCache and CachedValue abstractions in pet-core and refactor locators to use them
Co-authored-by: karthiknadig <[email protected]>
1 parent 8c771e5 commit 4ad900b

File tree

6 files changed

+359
-111
lines changed

6 files changed

+359
-111
lines changed

crates/pet-conda/src/lib.rs

Lines changed: 31 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use environments::{get_conda_environment_info, CondaEnvironment};
1111
use log::error;
1212
use manager::CondaManager;
1313
use pet_core::{
14+
cache::{EnvironmentCache, LocatorCache},
1415
env::PythonEnv,
1516
os_environment::Environment,
1617
python_environment::{PythonEnvironment, PythonEnvironmentKind},
@@ -20,7 +21,6 @@ use pet_core::{
2021
use pet_fs::path::norm_case;
2122
use serde::{Deserialize, Serialize};
2223
use std::{
23-
collections::HashMap,
2424
path::{Path, PathBuf},
2525
sync::{Arc, Mutex},
2626
thread,
@@ -38,6 +38,9 @@ pub mod package;
3838
mod telemetry;
3939
pub mod utils;
4040

41+
/// Type alias for caching Conda managers by path.
42+
pub type CondaManagerCache = LocatorCache<PathBuf, CondaManager>;
43+
4144
pub trait CondaLocator: Send + Sync {
4245
fn find_and_report(&self, reporter: &dyn Reporter, path: &Path);
4346
fn find_and_report_missing_envs(
@@ -61,24 +64,24 @@ pub struct CondaTelemetryInfo {
6164
}
6265

6366
pub struct Conda {
64-
pub environments: Arc<Mutex<HashMap<PathBuf, PythonEnvironment>>>,
65-
pub managers: Arc<Mutex<HashMap<PathBuf, CondaManager>>>,
67+
pub environments: EnvironmentCache,
68+
pub managers: CondaManagerCache,
6669
pub env_vars: EnvVariables,
6770
conda_executable: Arc<Mutex<Option<PathBuf>>>,
6871
}
6972

7073
impl Conda {
7174
pub fn from(env: &dyn Environment) -> Conda {
7275
Conda {
73-
environments: Arc::new(Mutex::new(HashMap::new())),
74-
managers: Arc::new(Mutex::new(HashMap::new())),
76+
environments: EnvironmentCache::new(),
77+
managers: CondaManagerCache::new(),
7578
env_vars: EnvVariables::from(env),
7679
conda_executable: Arc::new(Mutex::new(None)),
7780
}
7881
}
7982
fn clear(&self) {
80-
self.environments.lock().unwrap().clear();
81-
self.managers.lock().unwrap().clear();
83+
self.environments.clear();
84+
self.managers.clear();
8285
}
8386
}
8487

@@ -91,7 +94,7 @@ impl CondaLocator for Conda {
9194
// Look for environments that we couldn't find without spawning conda.
9295
let user_provided_conda_exe = conda_executable.is_some();
9396
let conda_info = CondaInfo::from(conda_executable)?;
94-
let environments = self.environments.lock().unwrap().clone();
97+
let environments = self.environments.clone_map();
9598
let new_envs = conda_info
9699
.envs
97100
.clone()
@@ -119,10 +122,7 @@ impl CondaLocator for Conda {
119122

120123
fn get_info_for_telemetry(&self, conda_executable: Option<PathBuf>) -> CondaTelemetryInfo {
121124
let can_spawn_conda = CondaInfo::from(conda_executable).is_some();
122-
let environments = self.environments.lock().unwrap().clone();
123-
let environments = environments
124-
.into_values()
125-
.collect::<Vec<PythonEnvironment>>();
125+
let environments = self.environments.values();
126126
let (conda_rcs, env_dirs) = get_conda_rcs_and_env_dirs(&self.env_vars, &environments);
127127
let mut environments_txt = None;
128128
let mut environments_txt_exists = None;
@@ -159,19 +159,14 @@ impl CondaLocator for Conda {
159159
if let Some(conda_dir) = manager.conda_dir.clone() {
160160
// Keep track to search again later.
161161
// Possible we'll find environments in other directories created using this manager
162-
let mut managers = self.managers.lock().unwrap();
163-
// Keep track to search again later.
164-
// Possible we'll find environments in other directories created using this manager
165-
managers.insert(conda_dir.clone(), manager.clone());
166-
drop(managers);
162+
self.managers.insert(conda_dir.clone(), manager.clone());
167163

168164
// Find all the environments in the conda install folder. (under `envs` folder)
169165
for conda_env in
170166
get_conda_environments(&get_environments(&conda_dir), &manager.clone().into())
171167
{
172168
// If reported earlier, no point processing this again.
173-
let mut environments = self.environments.lock().unwrap();
174-
if environments.contains_key(&conda_env.prefix) {
169+
if self.environments.contains_key(&conda_env.prefix) {
175170
continue;
176171
}
177172

@@ -183,7 +178,7 @@ impl CondaLocator for Conda {
183178
.and_then(|p| CondaManager::from(&p))
184179
.unwrap_or(manager.clone());
185180
let env = conda_env.to_python_environment(Some(manager.to_manager()));
186-
environments.insert(conda_env.prefix.clone(), env.clone());
181+
self.environments.insert(conda_env.prefix.clone(), env.clone());
187182
reporter.report_manager(&manager.to_manager());
188183
reporter.report_environment(&env);
189184
}
@@ -194,14 +189,13 @@ impl CondaLocator for Conda {
194189

195190
impl Conda {
196191
fn get_manager(&self, conda_dir: &Path) -> Option<CondaManager> {
197-
let mut managers = self.managers.lock().unwrap();
198192
// If we have a conda install folder, then use that to get the manager.
199-
if let Some(mgr) = managers.get(conda_dir) {
200-
return Some(mgr.clone());
193+
if let Some(mgr) = self.managers.get(&conda_dir.to_path_buf()) {
194+
return Some(mgr);
201195
}
202196

203197
if let Some(manager) = CondaManager::from(conda_dir) {
204-
managers.insert(conda_dir.into(), manager.clone());
198+
self.managers.insert(conda_dir.into(), manager.clone());
205199
Some(manager)
206200
} else {
207201
None
@@ -246,25 +240,23 @@ impl Locator for Conda {
246240
return None;
247241
}
248242

249-
let mut environments = self.environments.lock().unwrap();
250-
251243
// Do we already have an env for this.
252-
if let Some(env) = environments.get(path) {
253-
return Some(env.clone());
244+
if let Some(env) = self.environments.get(path) {
245+
return Some(env);
254246
}
255247
if let Some(env) = get_conda_environment_info(path, &None) {
256248
if let Some(conda_dir) = &env.conda_dir {
257249
if let Some(manager) = self.get_manager(conda_dir) {
258250
let env = env.to_python_environment(Some(manager.to_manager()));
259-
environments.insert(path.clone(), env.clone());
251+
self.environments.insert(path.clone(), env.clone());
260252
return Some(env);
261253
} else {
262254
// We will still return the conda env even though we do not have the manager.
263255
// This might seem incorrect, however the tool is about discovering environments.
264256
// The client can activate this env either using another conda manager or using the activation scripts
265257
error!("Unable to find Conda Manager for env (even though we have a conda_dir): {:?}", env);
266258
let env = env.to_python_environment(None);
267-
environments.insert(path.clone(), env.clone());
259+
self.environments.insert(path.clone(), env.clone());
268260
return Some(env);
269261
}
270262
} else {
@@ -273,7 +265,7 @@ impl Locator for Conda {
273265
// The client can activate this env either using another conda manager or using the activation scripts
274266
error!("Unable to find Conda Manager for env: {:?}", env);
275267
let env = env.to_python_environment(None);
276-
environments.insert(path.clone(), env.clone());
268+
self.environments.insert(path.clone(), env.clone());
277269
return Some(env);
278270
}
279271
}
@@ -306,8 +298,7 @@ impl Locator for Conda {
306298
error!("Unable to find Conda Manager for the Conda env: {:?}", env);
307299
let prefix = env.prefix.clone();
308300
let env = env.to_python_environment(None);
309-
let mut environments = self.environments.lock().unwrap();
310-
environments.insert(prefix, env.clone());
301+
self.environments.insert(prefix, env.clone());
311302
reporter.report_environment(&env);
312303
return None;
313304
}
@@ -316,27 +307,19 @@ impl Locator for Conda {
316307
// We will try to get the manager for this conda_dir
317308
let prefix = env.clone().prefix.clone();
318309

319-
{
320-
// 3.1 Check if we have already reported this environment.
321-
// Closure to quickly release lock
322-
let environments = self.environments.lock().unwrap();
323-
if environments.contains_key(&env.prefix) {
324-
return None;
325-
}
310+
// 3.1 Check if we have already reported this environment.
311+
if self.environments.contains_key(&env.prefix) {
312+
return None;
326313
}
327314

328-
329315
// 4 Get the manager for this env.
330316
let conda_dir = &env.conda_dir.clone()?;
331-
let managers = self.managers.lock().unwrap();
332-
let mut manager = managers.get(conda_dir).cloned();
333-
drop(managers);
317+
let mut manager = self.managers.get(conda_dir);
334318

335319
if manager.is_none() {
336320
// 4.1 Build the manager from the conda dir if we do not have it.
337321
if let Some(conda_manager) = CondaManager::from(conda_dir) {
338-
let mut managers = self.managers.lock().unwrap();
339-
managers.insert(conda_dir.to_path_buf().clone(), conda_manager.clone());
322+
self.managers.insert(conda_dir.to_path_buf().clone(), conda_manager.clone());
340323
manager = Some(conda_manager);
341324
}
342325
}
@@ -346,8 +329,7 @@ impl Locator for Conda {
346329
let env = env.to_python_environment(
347330
Some(manager.to_manager()),
348331
);
349-
let mut environments = self.environments.lock().unwrap();
350-
environments.insert(prefix.clone(), env.clone());
332+
self.environments.insert(prefix.clone(), env.clone());
351333
reporter.report_manager(&manager.to_manager());
352334
reporter.report_environment(&env);
353335
} else {
@@ -356,8 +338,7 @@ impl Locator for Conda {
356338
// The client can activate this env either using another conda manager or using the activation scripts
357339
error!("Unable to find Conda Manager for Conda env (even though we have a conda_dir {:?}): Env Details = {:?}", conda_dir, env);
358340
let env = env.to_python_environment(None);
359-
let mut environments = self.environments.lock().unwrap();
360-
environments.insert(prefix.clone(), env.clone());
341+
self.environments.insert(prefix.clone(), env.clone());
361342
reporter.report_environment(&env);
362343
}
363344
Option::<()>::Some(())

0 commit comments

Comments
 (0)