Skip to content

Commit 7f4061e

Browse files
authored
Search for envs using user provided conda exe (#112)
1 parent e8f7fd2 commit 7f4061e

File tree

2 files changed

+72
-6
lines changed

2 files changed

+72
-6
lines changed

crates/pet-conda/src/environment_locations.rs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@ use std::{
1717

1818
const APP_NAME: &str = "conda";
1919

20-
pub fn get_conda_environment_paths(env_vars: &EnvVariables) -> Vec<PathBuf> {
20+
pub fn get_conda_environment_paths(
21+
env_vars: &EnvVariables,
22+
conda_executable: &Option<PathBuf>,
23+
) -> Vec<PathBuf> {
2124
let mut env_paths = thread::scope(|s| {
2225
let mut envs = vec![];
2326
for thread in [
2427
s.spawn(|| get_conda_envs_from_environment_txt(env_vars)),
2528
s.spawn(|| get_conda_environment_paths_from_conda_rc(env_vars)),
2629
s.spawn(|| get_conda_environment_paths_from_known_paths(env_vars)),
27-
s.spawn(|| get_known_conda_install_locations(env_vars)),
30+
s.spawn(|| get_known_conda_install_locations(env_vars, conda_executable)),
2831
] {
2932
if let Ok(mut env_paths) = thread.join() {
3033
envs.append(&mut env_paths);
@@ -188,7 +191,10 @@ pub fn get_conda_envs_from_environment_txt(env_vars: &EnvVariables) -> Vec<PathB
188191
}
189192

190193
#[cfg(windows)]
191-
pub fn get_known_conda_install_locations(env_vars: &EnvVariables) -> Vec<PathBuf> {
194+
pub fn get_known_conda_install_locations(
195+
env_vars: &EnvVariables,
196+
conda_executable: &Option<PathBuf>,
197+
) -> Vec<PathBuf> {
192198
use pet_fs::path::norm_case;
193199

194200
let user_profile = env_vars.userprofile.clone().unwrap_or_default();
@@ -246,14 +252,20 @@ pub fn get_known_conda_install_locations(env_vars: &EnvVariables) -> Vec<PathBuf
246252
// We do not want to have duplicates in different cases.
247253
// & we'd like to preserve the case of the original path as on disc.
248254
known_paths = known_paths.iter().map(norm_case).collect();
255+
if let Some(conda_dir) = get_conda_dir_from_exe(conda_executable) {
256+
known_paths.push(conda_dir);
257+
}
249258
known_paths.sort();
250259
known_paths.dedup();
251260

252261
known_paths
253262
}
254263

255264
#[cfg(unix)]
256-
pub fn get_known_conda_install_locations(env_vars: &EnvVariables) -> Vec<PathBuf> {
265+
pub fn get_known_conda_install_locations(
266+
env_vars: &EnvVariables,
267+
conda_executable: &Option<PathBuf>,
268+
) -> Vec<PathBuf> {
257269
let mut known_paths = vec![];
258270
let home_value = env_vars.clone().home.unwrap_or_default();
259271
let directories_to_look_in = [
@@ -294,8 +306,41 @@ pub fn get_known_conda_install_locations(env_vars: &EnvVariables) -> Vec<PathBuf
294306
known_paths.push(home.clone().join("micromamba"));
295307
known_paths.push(home.join(".conda"));
296308
}
309+
if let Some(conda_dir) = get_conda_dir_from_exe(conda_executable) {
310+
known_paths.push(conda_dir);
311+
}
297312
known_paths.sort();
298313
known_paths.dedup();
299314

300315
known_paths
301316
}
317+
318+
pub fn get_conda_dir_from_exe(conda_executable: &Option<PathBuf>) -> Option<PathBuf> {
319+
if let Some(conda_executable) = conda_executable {
320+
if conda_executable.is_file() {
321+
if let Some(conda_dir) = conda_executable.parent() {
322+
// Possible exe is in the install (root prefix) directory.
323+
if is_conda_env(conda_dir) {
324+
return Some(conda_dir.to_path_buf());
325+
} else if let Some(conda_dir) = conda_dir.parent() {
326+
// Possible the exe is in the `bin` or `Scripts` directory.
327+
if is_conda_env(conda_dir) {
328+
return Some(conda_dir.to_path_buf());
329+
}
330+
}
331+
}
332+
} else {
333+
let conda_dir = conda_executable.clone();
334+
// Possible exe is in the install (root prefix) directory.
335+
if is_conda_env(&conda_dir) {
336+
return Some(conda_dir.to_path_buf());
337+
} else if let Some(conda_dir) = conda_dir.parent() {
338+
// Possible the exe is in the `bin` or `Scripts` directory.
339+
if is_conda_env(conda_dir) {
340+
return Some(conda_dir.to_path_buf());
341+
}
342+
}
343+
}
344+
}
345+
None
346+
}

crates/pet-conda/src/lib.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
use conda_info::CondaInfo;
55
use env_variables::EnvVariables;
66
use environment_locations::{
7-
get_conda_environment_paths, get_conda_envs_from_environment_txt, get_environments,
7+
get_conda_dir_from_exe, get_conda_environment_paths, get_conda_envs_from_environment_txt,
8+
get_environments,
89
};
910
use environments::{get_conda_environment_info, CondaEnvironment};
1011
use log::error;
@@ -15,6 +16,7 @@ use pet_core::{
1516
reporter::Reporter,
1617
Locator,
1718
};
19+
use pet_fs::path::norm_case;
1820
use pet_python_utils::env::PythonEnv;
1921
use serde::{Deserialize, Serialize};
2022
use std::{
@@ -54,13 +56,15 @@ pub struct CondaTelemetryInfo {
5456
pub env_dirs: Vec<PathBuf>,
5557
pub environments_txt: Option<PathBuf>,
5658
pub environments_txt_exists: Option<bool>,
59+
pub user_provided_env_found: Option<bool>,
5760
pub environments_from_txt: Vec<PathBuf>,
5861
}
5962

6063
pub struct Conda {
6164
pub environments: Arc<Mutex<HashMap<PathBuf, PythonEnvironment>>>,
6265
pub managers: Arc<Mutex<HashMap<PathBuf, CondaManager>>>,
6366
pub env_vars: EnvVariables,
67+
conda_executable: Arc<Mutex<Option<PathBuf>>>,
6468
}
6569

6670
impl Conda {
@@ -69,6 +73,7 @@ impl Conda {
6973
environments: Arc::new(Mutex::new(HashMap::new())),
7074
managers: Arc::new(Mutex::new(HashMap::new())),
7175
env_vars: EnvVariables::from(env),
76+
conda_executable: Arc::new(Mutex::new(None)),
7277
}
7378
}
7479
fn clear(&self) {
@@ -127,10 +132,19 @@ impl CondaLocator for Conda {
127132
environments_txt = Some(file);
128133
}
129134

135+
let conda_exe = &self.conda_executable.lock().unwrap().clone();
136+
let envs_found = get_conda_environment_paths(&self.env_vars, conda_exe);
137+
let mut user_provided_env_found = None;
138+
if let Some(conda_dir) = get_conda_dir_from_exe(conda_exe) {
139+
let conda_dir = norm_case(conda_dir);
140+
user_provided_env_found = Some(envs_found.contains(&conda_dir));
141+
}
142+
130143
CondaTelemetryInfo {
131144
can_spawn_conda,
132145
conda_rcs,
133146
env_dirs,
147+
user_provided_env_found,
134148
environments_txt,
135149
environments_txt_exists,
136150
environments_from_txt: get_conda_envs_from_environment_txt(&self.env_vars),
@@ -192,6 +206,12 @@ impl Locator for Conda {
192206
fn get_name(&self) -> &'static str {
193207
"Conda" // Do not change this name, as this is used in telemetry.
194208
}
209+
fn configure(&self, config: &pet_core::Configuration) {
210+
if let Some(ref conda_exe) = config.conda_executable {
211+
let mut conda_executable = self.conda_executable.lock().unwrap();
212+
conda_executable.replace(conda_exe.clone());
213+
}
214+
}
195215
fn supported_categories(&self) -> Vec<PythonEnvironmentKind> {
196216
vec![PythonEnvironmentKind::Conda]
197217
}
@@ -262,9 +282,10 @@ impl Locator for Conda {
262282
self.clear();
263283

264284
let env_vars = self.env_vars.clone();
285+
let executable = self.conda_executable.lock().unwrap().clone();
265286
thread::scope(|s| {
266287
// 1. Get a list of all know conda environments file paths
267-
let possible_conda_envs = get_conda_environment_paths(&env_vars);
288+
let possible_conda_envs = get_conda_environment_paths(&env_vars, &executable);
268289
for path in possible_conda_envs {
269290
s.spawn(move || {
270291
// 2. Get the details of the conda environment

0 commit comments

Comments
 (0)