Skip to content

Commit 72123ab

Browse files
authored
fix: filter out WSL Windows drive mount paths in conda locator (Fixes #369) (#370)
On WSL2, `~/.conda/environments.txt` is shared with the Windows host and contains paths like `/mnt/d/Tools/Anaconda/envs/...` that point to Windows PE executables unusable from Linux. PET would try to find a conda manager for each, fail, and log ERROR for every environment — causing log spam and ~6s overhead. **Changes:** - Add `is_windows_drive_mount()` helper (Unix-only) to detect `/mnt/<drive>/...` paths - Add `is_wsl()` helper using `/proc/version` WSL signature detection with result caching - Filter out Windows drive mount paths early in `get_conda_environment_paths()` before expensive scanning - Unit tests for the path matching logic (Unix-gated) Fixes #369
1 parent 5ff1eb6 commit 72123ab

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

crates/pet-conda/src/environment_locations.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,48 @@ use std::{
2020

2121
const 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+
2365
pub 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

Comments
 (0)