Skip to content

Commit 8965999

Browse files
authored
Incremental reporting of Conda envs (#28)
1 parent e90258a commit 8965999

File tree

19 files changed

+397
-408
lines changed

19 files changed

+397
-408
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pet-conda/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,9 @@ pet-utils = { path = "../pet-utils" }
1212
log = "0.4.21"
1313
regex = "1.10.4"
1414

15+
[dev-dependencies]
16+
pet-reporter = { path = "../pet-reporter" }
17+
18+
1519
[features]
1620
ci = []

crates/pet-conda/src/lib.rs

+77-63
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use environments::{get_conda_environment_info, CondaEnvironment};
77
use log::error;
88
use manager::CondaManager;
99
use pet_core::{
10-
os_environment::Environment, python_environment::PythonEnvironment, Locator, LocatorResult,
10+
os_environment::Environment, python_environment::PythonEnvironment, reporter::Reporter,
11+
Locator, LocatorResult,
1112
};
1213
use pet_utils::env::PythonEnv;
1314
use std::{
@@ -147,73 +148,86 @@ impl Locator for Conda {
147148
None
148149
}
149150

150-
fn find(&self) -> Option<LocatorResult> {
151-
// 1. Get a list of all know conda environments
152-
let known_conda_envs =
153-
get_conda_environments(&get_conda_environment_paths(&self.env_vars), &None);
154-
let mut new_managers = vec![];
155-
{
156-
let mut managers = self.managers.lock().unwrap();
157-
// 2. Go through all conda dirs and build the conda managers.
158-
for env in &known_conda_envs {
159-
if let Some(conda_dir) = &env.conda_dir {
160-
if managers.contains_key(conda_dir) {
161-
continue;
151+
fn find(&self, reporter: &dyn Reporter) {
152+
let env_vars = self.env_vars.clone();
153+
thread::scope(|s| {
154+
// 1. Get a list of all know conda environments file paths
155+
let possible_conda_envs = get_conda_environment_paths(&env_vars);
156+
for path in possible_conda_envs {
157+
s.spawn(move || {
158+
// 2. Get the details of the conda environment
159+
// This we do not get any details, then its not a conda environment
160+
let env = get_conda_environment_info(&path, &None)?;
161+
162+
// 3. If we have a conda environment without a conda_dir
163+
// Then we will not be able to get the manager.
164+
// Either way report this environment
165+
if env.conda_dir.is_none(){
166+
// We will still return the conda env even though we do not have the manager.
167+
// This might seem incorrect, however the tool is about discovering environments.
168+
// The client can activate this env either using another conda manager or using the activation scripts
169+
error!("Unable to find Conda Manager for the Conda env: {:?}", env);
170+
let prefix = env.prefix.clone();
171+
let env = env.to_python_environment(None, None);
172+
let mut environments = self.environments.lock().unwrap();
173+
environments.insert(prefix, env.clone());
174+
reporter.report_environment(&env);
175+
return None;
162176
}
163-
if let Some(manager) = CondaManager::from(conda_dir) {
164-
new_managers.push(manager.to_manager());
165-
managers.insert(conda_dir.clone(), manager);
177+
178+
// 3. We have a conda environment with a conda_dir (above we handled the case when its not found)
179+
// We will try to get the manager for this conda_dir
180+
let prefix = env.clone().prefix.clone();
181+
182+
{
183+
// 3.1 Check if we have already reported this environment.
184+
// Closure to quickly release lock
185+
let environments = self.environments.lock().unwrap();
186+
if environments.contains_key(&env.prefix) {
187+
return None;
188+
}
166189
}
167-
}
168-
}
169-
}
170190

171-
let mut environments = self.environments.lock().unwrap();
172-
let mut new_environments: Vec<PythonEnvironment> = vec![];
173-
// 3. Go through each environment we know of and build the python environments.
174-
for known_env in &known_conda_envs {
175-
if environments.contains_key(&known_env.prefix) {
176-
continue;
177-
}
178-
if let Some(conda_dir) = &known_env.conda_dir {
179-
if let Some(manager) = self.get_manager(conda_dir) {
180-
let env = known_env.to_python_environment(
181-
Some(manager.conda_dir.clone()),
182-
Some(manager.to_manager()),
183-
);
184-
environments.insert(known_env.prefix.clone(), env.clone());
185-
new_environments.push(env);
186-
} else {
187-
// We will still return the conda env even though we do not have the manager.
188-
// This might seem incorrect, however the tool is about discovering environments.
189-
// The client can activate this env either using another conda manager or using the activation scripts
190-
error!("Unable to find Conda Manager for Conda env (even though we have a conda_dir {:?}): Env Details = {:?}", conda_dir, known_env);
191-
let env = known_env.to_python_environment(Some(conda_dir.clone()), None);
192-
environments.insert(known_env.prefix.clone(), env.clone());
193-
new_environments.push(env);
194-
}
195-
} else {
196-
// We will still return the conda env even though we do not have the manager.
197-
// This might seem incorrect, however the tool is about discovering environments.
198-
// The client can activate this env either using another conda manager or using the activation scripts
199-
error!(
200-
"Unable to find Conda Manager for the Conda env: {:?}",
201-
known_env
202-
);
203-
let env = known_env.to_python_environment(None, None);
204-
environments.insert(known_env.prefix.clone(), env.clone());
205-
new_environments.push(env);
206-
}
207-
}
208191

209-
if new_managers.is_empty() && new_environments.is_empty() {
210-
return None;
211-
}
192+
// 4 Get the manager for this env.
193+
let conda_dir = &env.conda_dir.clone()?;
194+
let managers = self.managers.lock().unwrap();
195+
let mut manager = managers.get(conda_dir).cloned();
196+
drop(managers);
212197

213-
Some(LocatorResult {
214-
managers: new_managers,
215-
environments: new_environments,
216-
})
198+
if manager.is_none() {
199+
// 4.1 Build the manager from the conda dir if we do not have it.
200+
if let Some(conda_manager) = CondaManager::from(conda_dir) {
201+
reporter.report_manager(&conda_manager.to_manager());
202+
let mut managers = self.managers.lock().unwrap();
203+
managers.insert(conda_dir.to_path_buf().clone(), conda_manager.clone());
204+
manager = Some(conda_manager);
205+
}
206+
}
207+
208+
// 5. Report this env.
209+
if let Some(manager) = manager {
210+
let env = env.to_python_environment(
211+
Some(manager.conda_dir.clone()),
212+
Some(manager.to_manager()),
213+
);
214+
let mut environments = self.environments.lock().unwrap();
215+
environments.insert(prefix.clone(), env.clone());
216+
reporter.report_environment(&env);
217+
} else {
218+
// We will still return the conda env even though we do not have the manager.
219+
// This might seem incorrect, however the tool is about discovering environments.
220+
// The client can activate this env either using another conda manager or using the activation scripts
221+
error!("Unable to find Conda Manager for Conda env (even though we have a conda_dir {:?}): Env Details = {:?}", conda_dir, env);
222+
let env = env.to_python_environment(Some(conda_dir.clone()), None);
223+
let mut environments = self.environments.lock().unwrap();
224+
environments.insert(prefix.clone(), env.clone());
225+
reporter.report_environment(&env);
226+
}
227+
Option::<()>::Some(())
228+
});
229+
}
230+
});
217231
}
218232
}
219233

crates/pet-conda/tests/ci_test.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ fn detect_conda_root() {
1717
manager::EnvManagerType, os_environment::EnvironmentApi,
1818
python_environment::PythonEnvironmentCategory, Locator,
1919
};
20-
use std::path::PathBuf;
20+
use pet_reporter::test::create_reporter;
2121

2222
let env = EnvironmentApi::new();
2323

24+
let reporter = create_reporter();
2425
let conda = Conda::from(&env);
25-
let result = conda.find().unwrap();
26+
conda.find(&reporter);
27+
let result = reporter.get_result();
2628

2729
assert_eq!(result.managers.len(), 1);
2830

@@ -92,6 +94,7 @@ fn detect_new_conda_env() {
9294
use pet_core::{
9395
os_environment::EnvironmentApi, python_environment::PythonEnvironmentCategory, Locator,
9496
};
97+
use pet_reporter::test::create_reporter;
9598
use std::path::PathBuf;
9699

97100
let env_name = "env_with_python";
@@ -102,7 +105,9 @@ fn detect_new_conda_env() {
102105
let env = EnvironmentApi::new();
103106

104107
let conda = Conda::from(&env);
105-
let result = conda.find().unwrap();
108+
let reporter = create_reporter();
109+
conda.find(&reporter);
110+
let result = reporter.get_result();
106111

107112
assert_eq!(result.managers.len(), 1);
108113

@@ -191,14 +196,17 @@ fn detect_new_conda_env_without_python() {
191196
use pet_core::{
192197
os_environment::EnvironmentApi, python_environment::PythonEnvironmentCategory, Locator,
193198
};
199+
use pet_reporter::test::create_reporter;
194200
use std::path::PathBuf;
195201

196202
let env_name = "env_without_python";
197203
create_conda_env(&CondaCreateEnvNameOrPath::Name(env_name.into()), None);
198204
let env = EnvironmentApi::new();
199205

200206
let conda = Conda::from(&env);
201-
let result = conda.find().unwrap();
207+
let reporter = create_reporter();
208+
conda.find(&reporter);
209+
let result = reporter.get_result();
202210

203211
assert_eq!(result.managers.len(), 1);
204212

@@ -238,6 +246,7 @@ fn detect_new_conda_env_created_with_p_flag_without_python() {
238246
use pet_core::{
239247
os_environment::EnvironmentApi, python_environment::PythonEnvironmentCategory, Locator,
240248
};
249+
use pet_reporter::test::create_reporter;
241250
use std::path::PathBuf;
242251

243252
let env_name = "env_without_python3";
@@ -246,7 +255,9 @@ fn detect_new_conda_env_created_with_p_flag_without_python() {
246255
let env = EnvironmentApi::new();
247256

248257
let conda = Conda::from(&env);
249-
let result = conda.find().unwrap();
258+
let reporter = create_reporter();
259+
conda.find(&reporter);
260+
let result = reporter.get_result();
250261

251262
assert_eq!(result.managers.len(), 1);
252263

@@ -286,6 +297,7 @@ fn detect_new_conda_env_created_with_p_flag_with_python() {
286297
use pet_core::{
287298
os_environment::EnvironmentApi, python_environment::PythonEnvironmentCategory, Locator,
288299
};
300+
use pet_reporter::test::create_reporter;
289301
use std::path::PathBuf;
290302

291303
let env_name = "env_with_python3";
@@ -298,7 +310,9 @@ fn detect_new_conda_env_created_with_p_flag_with_python() {
298310
let env = EnvironmentApi::new();
299311

300312
let conda = Conda::from(&env);
301-
let result = conda.find().unwrap();
313+
let reporter = create_reporter();
314+
conda.find(&reporter);
315+
let result = reporter.get_result();
302316

303317
assert_eq!(result.managers.len(), 1);
304318

crates/pet-core/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use manager::EnvManager;
55
use pet_utils::env::PythonEnv;
66
use python_environment::PythonEnvironment;
7+
use reporter::Reporter;
78

89
pub mod arch;
910
pub mod manager;
@@ -39,5 +40,5 @@ pub trait Locator: Send + Sync {
3940
/**
4041
* Finds all environments specific to this locator.
4142
*/
42-
fn find(&self) -> Option<LocatorResult>;
43+
fn find(&self, reporter: &dyn Reporter);
4344
}

0 commit comments

Comments
 (0)