@@ -20,6 +20,48 @@ use std::{
2020
2121const APP_NAME : & str = "conda" ;
2222
23+ /// Checks whether the current environment is Windows Subsystem for Linux.
24+ /// Result is cached after the first call.
25+ #[ cfg( unix) ]
26+ fn is_wsl ( ) -> bool {
27+ use std:: sync:: OnceLock ;
28+ static IS_WSL : OnceLock < bool > = OnceLock :: new ( ) ;
29+ * IS_WSL . get_or_init ( || {
30+ std:: fs:: read_to_string ( "/proc/version" )
31+ . map ( |v| v. to_lowercase ( ) . contains ( "microsoft" ) )
32+ . unwrap_or ( false )
33+ } )
34+ }
35+
36+ /// Returns true if the path is a Windows drive mounted via WSL (e.g. `/mnt/c/...`).
37+ /// These paths contain Windows PE executables that cannot be run from Linux.
38+ #[ cfg( unix) ]
39+ fn is_wsl_windows_drive_path ( path : & Path ) -> bool {
40+ if !is_wsl ( ) {
41+ return false ;
42+ }
43+ is_windows_drive_mount ( path)
44+ }
45+
46+ /// Checks if a path matches the WSL Windows drive mount pattern `/mnt/<drive_letter>/`.
47+ #[ cfg( unix) ]
48+ fn is_windows_drive_mount ( path : & Path ) -> bool {
49+ if let Some ( path_str) = path. to_str ( ) {
50+ if let Some ( rest) = path_str. strip_prefix ( "/mnt/" ) {
51+ let mut chars = rest. chars ( ) ;
52+ if let Some ( drive_letter) = chars. next ( ) {
53+ if drive_letter. is_ascii_alphabetic ( ) {
54+ match chars. next ( ) {
55+ None | Some ( '/' ) => return true ,
56+ _ => { }
57+ }
58+ }
59+ }
60+ }
61+ }
62+ false
63+ }
64+
2365pub fn get_conda_environment_paths (
2466 env_vars : & EnvVariables ,
2567 conda_executable : & Option < PathBuf > ,
@@ -43,6 +85,24 @@ pub fn get_conda_environment_paths(
4385 env_paths = env_paths. iter ( ) . map ( norm_case) . collect ( ) ;
4486 env_paths. sort ( ) ;
4587 env_paths. dedup ( ) ;
88+
89+ // On WSL, filter out paths on Windows drive mounts (/mnt/<drive>/) since they
90+ // contain Windows PE executables that cannot be run from Linux.
91+ #[ cfg( unix) ]
92+ {
93+ env_paths. retain ( |p| {
94+ if is_wsl_windows_drive_path ( p) {
95+ trace ! (
96+ "Skipping conda path on Windows drive (not usable from WSL): {:?}" ,
97+ p
98+ ) ;
99+ false
100+ } else {
101+ true
102+ }
103+ } ) ;
104+ }
105+
46106 // For each env, check if we have a conda install directory in them and
47107 // & then iterate through the list of envs in the envs directory.
48108 let mut result: Vec < PathBuf > = env_paths
@@ -498,3 +558,32 @@ pub fn get_conda_dir_from_exe(conda_executable: &Option<PathBuf>) -> Option<Path
498558 }
499559 None
500560}
561+
562+ #[ cfg( all( test, unix) ) ]
563+ mod tests {
564+ use super :: * ;
565+
566+ #[ test]
567+ fn test_windows_drive_mount_detection ( ) {
568+ // Typical WSL Windows drive mount paths
569+ assert ! ( is_windows_drive_mount( Path :: new( "/mnt/c/" ) ) ) ;
570+ assert ! ( is_windows_drive_mount( Path :: new( "/mnt/c/Users" ) ) ) ;
571+ assert ! ( is_windows_drive_mount( Path :: new(
572+ "/mnt/d/Tools/Anaconda/envs/myenv"
573+ ) ) ) ;
574+ assert ! ( is_windows_drive_mount( Path :: new( "/mnt/C/Users" ) ) ) ;
575+ assert ! ( is_windows_drive_mount( Path :: new( "/mnt/D/Tools" ) ) ) ;
576+
577+ // Just the drive letter with no trailing content
578+ assert ! ( is_windows_drive_mount( Path :: new( "/mnt/c" ) ) ) ;
579+
580+ // Not a Windows drive mount
581+ assert ! ( !is_windows_drive_mount( Path :: new( "/home/user/miniconda3" ) ) ) ;
582+ assert ! ( !is_windows_drive_mount( Path :: new( "/opt/conda" ) ) ) ;
583+ assert ! ( !is_windows_drive_mount( Path :: new( "/mnt/data/conda" ) ) ) ;
584+ assert ! ( !is_windows_drive_mount( Path :: new( "/mnt/cdrom/something" ) ) ) ;
585+ assert ! ( !is_windows_drive_mount( Path :: new( "/mnt/" ) ) ) ;
586+ assert ! ( !is_windows_drive_mount( Path :: new( "/mnt" ) ) ) ;
587+ assert ! ( !is_windows_drive_mount( Path :: new( "/mnt/12/path" ) ) ) ;
588+ }
589+ }
0 commit comments