@@ -11,6 +11,7 @@ use environments::{get_conda_environment_info, CondaEnvironment};
1111use log:: error;
1212use manager:: CondaManager ;
1313use 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::{
2021use pet_fs:: path:: norm_case;
2122use serde:: { Deserialize , Serialize } ;
2223use std:: {
23- collections:: HashMap ,
2424 path:: { Path , PathBuf } ,
2525 sync:: { Arc , Mutex } ,
2626 thread,
@@ -38,6 +38,9 @@ pub mod package;
3838mod telemetry;
3939pub mod utils;
4040
41+ /// Type alias for caching Conda managers by path.
42+ pub type CondaManagerCache = LocatorCache < PathBuf , CondaManager > ;
43+
4144pub 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
6366pub 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
7073impl 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
195190impl 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