33
44use pet_core:: os_environment:: Environment ;
55use std:: collections:: HashSet ;
6- use std:: fs;
76use std:: path:: PathBuf ;
87
98pub fn get_search_paths_from_env_variables ( environment : & dyn Environment ) -> Vec < PathBuf > {
@@ -19,7 +18,7 @@ pub fn get_search_paths_from_env_variables(environment: &dyn Environment) -> Vec
1918 environment
2019 . get_know_global_search_locations ( )
2120 . into_iter ( )
22- . map ( |p| fs :: canonicalize ( & p ) . unwrap_or ( p ) )
21+ . map ( normalize_search_path )
2322 . collect :: < HashSet < PathBuf > > ( )
2423 . into_iter ( )
2524 . filter ( |p| !p. starts_with ( apps_path. clone ( ) ) )
@@ -28,3 +27,28 @@ pub fn get_search_paths_from_env_variables(environment: &dyn Environment) -> Vec
2827 Vec :: new ( )
2928 }
3029}
30+
31+ /// Normalizes a search path for deduplication purposes.
32+ ///
33+ /// On Unix: Uses fs::canonicalize to resolve symlinks. This is important for merged-usr
34+ /// systems where /bin, /sbin, /usr/sbin are symlinks to /usr/bin - we don't want to
35+ /// report the same Python installation multiple times.
36+ /// See: https://github.com/microsoft/python-environment-tools/pull/200
37+ ///
38+ /// On Windows: Uses norm_case (GetLongPathNameW) to normalize case WITHOUT resolving
39+ /// directory junctions. This is important for tools like Scoop that use junctions
40+ /// (e.g., python\current -> python\3.13.3). Using fs::canonicalize would resolve
41+ /// the junction, causing symlink tracking to fail when the shim points to the
42+ /// junction path but executables are discovered from the resolved path.
43+ /// See: https://github.com/microsoft/python-environment-tools/issues/187
44+ fn normalize_search_path ( path : PathBuf ) -> PathBuf {
45+ #[ cfg( unix) ]
46+ {
47+ std:: fs:: canonicalize ( & path) . unwrap_or ( path)
48+ }
49+
50+ #[ cfg( windows) ]
51+ {
52+ pet_fs:: path:: norm_case ( & path)
53+ }
54+ }
0 commit comments