Skip to content

Commit bd93933

Browse files
committed
fix: address review feedback - race condition, test portability (PR #350)
1 parent ce0f808 commit bd93933

File tree

2 files changed

+29
-19
lines changed

2 files changed

+29
-19
lines changed

crates/pet-conda/src/lib.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,15 @@ impl CondaLocator for Conda {
168168
self.managers.insert(conda_dir.clone(), manager.clone());
169169

170170
// Also check for a mamba/micromamba manager in the same directory and report it.
171-
if !self.mamba_managers.contains_key(&conda_dir) {
172-
if let Some(mamba_mgr) = get_mamba_manager(&conda_dir) {
173-
self.mamba_managers
174-
.insert(conda_dir.clone(), mamba_mgr.clone());
175-
reporter.report_manager(&mamba_mgr.to_manager());
176-
}
177-
}
171+
let _ = self
172+
.mamba_managers
173+
.get_or_insert_with(conda_dir.clone(), || {
174+
let mgr = get_mamba_manager(&conda_dir);
175+
if let Some(ref m) = mgr {
176+
reporter.report_manager(&m.to_manager());
177+
}
178+
mgr
179+
});
178180

179181
// Find all the environments in the conda install folder. (under `envs` folder)
180182
for conda_env in
@@ -349,14 +351,16 @@ impl Locator for Conda {
349351
reporter.report_environment(&env);
350352

351353
// Also check for a mamba/micromamba manager in the same directory and report it.
352-
let is_new_mamba = !self.mamba_managers.contains_key(conda_dir);
353-
if let Some(mamba_mgr) = self.mamba_managers.get_or_insert_with(conda_dir.clone(), || {
354-
get_mamba_manager(conda_dir)
355-
}) {
356-
if is_new_mamba {
357-
reporter.report_manager(&mamba_mgr.to_manager());
354+
// Reporting inside the closure minimizes the TOCTOU window compared to a
355+
// separate contains_key check, though concurrent threads may still
356+
// briefly both invoke the closure before the write-lock double-check.
357+
let _ = self.mamba_managers.get_or_insert_with(conda_dir.clone(), || {
358+
let mgr = get_mamba_manager(conda_dir);
359+
if let Some(ref m) = mgr {
360+
reporter.report_manager(&m.to_manager());
358361
}
359-
}
362+
mgr
363+
});
360364
} else {
361365
// We will still return the conda env even though we do not have the manager.
362366
// This might seem incorrect, however the tool is about discovering environments.

crates/pet-conda/tests/manager_test.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,18 +140,24 @@ fn is_mamba_executable_identifies_mamba_binaries() {
140140
use pet_conda::manager::is_mamba_executable;
141141
use std::path::Path;
142142

143+
// Cross-platform: forward-slash paths work on all platforms
143144
assert!(is_mamba_executable(Path::new("/usr/bin/mamba")));
144145
assert!(is_mamba_executable(Path::new("/usr/bin/micromamba")));
145-
assert!(is_mamba_executable(Path::new("C:\\Scripts\\mamba.exe")));
146-
assert!(is_mamba_executable(Path::new(
147-
"C:\\Scripts\\micromamba.exe"
148-
)));
149146
assert!(is_mamba_executable(Path::new("/opt/miniforge3/bin/mamba")));
150147

151148
// Should NOT match conda or python
152149
assert!(!is_mamba_executable(Path::new("/usr/bin/conda")));
153150
assert!(!is_mamba_executable(Path::new("/usr/bin/python")));
154-
assert!(!is_mamba_executable(Path::new("C:\\Scripts\\conda.exe")));
151+
152+
// Windows-specific paths with backslashes (only valid on Windows)
153+
#[cfg(windows)]
154+
{
155+
assert!(is_mamba_executable(Path::new("C:\\Scripts\\mamba.exe")));
156+
assert!(is_mamba_executable(Path::new(
157+
"C:\\Scripts\\micromamba.exe"
158+
)));
159+
assert!(!is_mamba_executable(Path::new("C:\\Scripts\\conda.exe")));
160+
}
155161
}
156162

157163
/// Test that get_mamba_manager finds a mamba manager from a conda install with mamba.

0 commit comments

Comments
 (0)