@@ -15,25 +15,28 @@ use pet_core::LocatorKind;
1515use pet_core:: {
1616 os_environment:: Environment , Locator , RefreshStatePersistence , RefreshStateSyncScope ,
1717} ;
18+ #[ cfg( any( windows, test) ) ]
1819use pet_fs:: path:: norm_case;
1920use std:: path:: { Path , PathBuf } ;
2021use std:: sync:: { Arc , RwLock } ;
2122
2223#[ derive( Clone , Debug ) ]
2324struct CachedStoreEnvironment {
25+ #[ allow( dead_code) ]
2426 environment : PythonEnvironment ,
2527 #[ allow( dead_code) ]
2628 normalized_symlinks : Vec < PathBuf > ,
2729}
2830
2931impl CachedStoreEnvironment {
32+ #[ cfg( any( windows, test) ) ]
3033 fn from_environment ( environment : PythonEnvironment ) -> Self {
3134 let normalized_symlinks = environment
3235 . symlinks
3336 . as_deref ( )
3437 . unwrap_or_default ( )
3538 . iter ( )
36- . map ( normalize_for_comparison)
39+ . map ( |path| normalize_for_comparison ( path ) )
3740 . collect ( ) ;
3841
3942 Self {
@@ -43,7 +46,8 @@ impl CachedStoreEnvironment {
4346 }
4447}
4548
46- fn normalize_for_comparison ( path : & PathBuf ) -> PathBuf {
49+ #[ cfg( any( windows, test) ) ]
50+ fn normalize_for_comparison ( path : & Path ) -> PathBuf {
4751 let normalized = norm_case ( path) ;
4852 let path_str = normalized. to_string_lossy ( ) ;
4953 if path_str. starts_with ( r"\\?\" ) {
@@ -62,7 +66,7 @@ pub fn is_windows_app_folder_in_program_files(path: &Path) -> bool {
6266pub struct WindowsStore {
6367 pub env_vars : EnvVariables ,
6468 #[ allow( dead_code) ]
65- environments : Arc < RwLock < Option < Vec < CachedStoreEnvironment > > > > ,
69+ environments : Arc < RwLock < Option < Arc < Vec < CachedStoreEnvironment > > > > > ,
6670}
6771
6872impl WindowsStore {
@@ -73,7 +77,7 @@ impl WindowsStore {
7377 }
7478 }
7579 #[ cfg( windows) ]
76- fn find_with_cache ( & self ) -> Option < Vec < CachedStoreEnvironment > > {
80+ fn find_with_cache ( & self ) -> Option < Arc < Vec < CachedStoreEnvironment > > > {
7781 // First check if we have cached results
7882 {
7983 let environments = self . environments . read ( ) . unwrap ( ) ;
@@ -82,11 +86,13 @@ impl WindowsStore {
8286 }
8387 }
8488
85- let envs = list_store_pythons ( & self . env_vars )
86- . unwrap_or_default ( )
87- . into_iter ( )
88- . map ( CachedStoreEnvironment :: from_environment)
89- . collect :: < Vec < _ > > ( ) ;
89+ let envs = Arc :: new (
90+ list_store_pythons ( & self . env_vars )
91+ . unwrap_or_default ( )
92+ . into_iter ( )
93+ . map ( CachedStoreEnvironment :: from_environment)
94+ . collect :: < Vec < _ > > ( ) ,
95+ ) ;
9096 self . environments . write ( ) . unwrap ( ) . replace ( envs. clone ( ) ) ;
9197 Some ( envs)
9298 }
@@ -138,9 +144,10 @@ impl Locator for WindowsStore {
138144 use pet_core:: python_environment:: PythonEnvironmentBuilder ;
139145 use pet_virtualenv:: is_virtualenv;
140146
141- // Assume we create a virtual env from a python install,
142- // Then the exe in the virtual env bin will be a symlink to the homebrew python install.
143- // Hence the first part of the condition will be true, but the second part will be false.
147+ // A virtual environment created from a Windows Store Python may still have an
148+ // executable path or symlink chain that resolves back to the base Store install.
149+ // Even in that case, the environment itself is a virtualenv and should not be
150+ // classified as a Windows Store environment here.
144151 if is_virtualenv ( env) {
145152 return None ;
146153 }
@@ -151,7 +158,7 @@ impl Locator for WindowsStore {
151158 . map ( |p| normalize_for_comparison ( & p) )
152159 . collect ( ) ;
153160 if let Some ( environments) = self . find_with_cache ( ) {
154- for found_env in environments {
161+ for found_env in environments. iter ( ) {
155162 if !found_env. normalized_symlinks . is_empty ( ) {
156163 // Check if we have found this exe.
157164 if list_of_possible_exes
@@ -262,9 +269,9 @@ mod tests {
262269 symlinks : Some ( vec ! [ PathBuf :: from( format!( r"\\?\{}" , symlink. display( ) ) ) ] ) ,
263270 ..Default :: default ( )
264271 } ;
265- locator. environments . write ( ) . unwrap ( ) . replace ( vec ! [
272+ locator. environments . write ( ) . unwrap ( ) . replace ( Arc :: new ( vec ! [
266273 CachedStoreEnvironment :: from_environment( store_environment) ,
267- ] ) ;
274+ ] ) ) ;
268275
269276 let mut env = PythonEnv :: new ( symlink. clone ( ) , None , None ) ;
270277 env. symlinks = Some ( vec ! [ symlink] ) ;
@@ -284,9 +291,9 @@ mod tests {
284291 symlinks : Some ( vec ! [ symlink. clone( ) ] ) ,
285292 ..Default :: default ( )
286293 } ;
287- locator. environments . write ( ) . unwrap ( ) . replace ( vec ! [
294+ locator. environments . write ( ) . unwrap ( ) . replace ( Arc :: new ( vec ! [
288295 CachedStoreEnvironment :: from_environment( store_environment) ,
289- ] ) ;
296+ ] ) ) ;
290297
291298 let mut env = PythonEnv :: new ( symlink. clone ( ) , None , None ) ;
292299 env. symlinks = Some ( vec ! [ PathBuf :: from( format!( r"\\?\{}" , symlink. display( ) ) ) ] ) ;
@@ -304,12 +311,12 @@ mod tests {
304311 . environments
305312 . write ( )
306313 . unwrap ( )
307- . replace ( vec ! [ cached_environment( "stale" ) ] ) ;
314+ . replace ( Arc :: new ( vec ! [ cached_environment( "stale" ) ] ) ) ;
308315 refreshed
309316 . environments
310317 . write ( )
311318 . unwrap ( )
312- . replace ( vec ! [ cached_environment( "fresh" ) ] ) ;
319+ . replace ( Arc :: new ( vec ! [ cached_environment( "fresh" ) ] ) ) ;
313320
314321 shared. sync_refresh_state_from ( & refreshed, & RefreshStateSyncScope :: Full ) ;
315322
@@ -327,12 +334,12 @@ mod tests {
327334 . environments
328335 . write ( )
329336 . unwrap ( )
330- . replace ( vec ! [ cached_environment( "stale" ) ] ) ;
337+ . replace ( Arc :: new ( vec ! [ cached_environment( "stale" ) ] ) ) ;
331338 refreshed
332339 . environments
333340 . write ( )
334341 . unwrap ( )
335- . replace ( vec ! [ cached_environment( "fresh" ) ] ) ;
342+ . replace ( Arc :: new ( vec ! [ cached_environment( "fresh" ) ] ) ) ;
336343
337344 shared. sync_refresh_state_from ( & refreshed, & RefreshStateSyncScope :: Workspace ) ;
338345
@@ -350,12 +357,12 @@ mod tests {
350357 . environments
351358 . write ( )
352359 . unwrap ( )
353- . replace ( vec ! [ cached_environment( "stale" ) ] ) ;
360+ . replace ( Arc :: new ( vec ! [ cached_environment( "stale" ) ] ) ) ;
354361 refreshed
355362 . environments
356363 . write ( )
357364 . unwrap ( )
358- . replace ( vec ! [ cached_environment( "fresh" ) ] ) ;
365+ . replace ( Arc :: new ( vec ! [ cached_environment( "fresh" ) ] ) ) ;
359366
360367 shared. sync_refresh_state_from (
361368 & refreshed,
@@ -368,7 +375,7 @@ mod tests {
368375 . environments
369376 . write ( )
370377 . unwrap ( )
371- . replace ( vec ! [ cached_environment( "stale" ) ] ) ;
378+ . replace ( Arc :: new ( vec ! [ cached_environment( "stale" ) ] ) ) ;
372379 shared. sync_refresh_state_from (
373380 & refreshed,
374381 & RefreshStateSyncScope :: GlobalFiltered ( PythonEnvironmentKind :: Conda ) ,
0 commit comments