Skip to content

Search for envs using user provided conda exe #112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions crates/pet-conda/src/environment_locations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ use std::{

const APP_NAME: &str = "conda";

pub fn get_conda_environment_paths(env_vars: &EnvVariables) -> Vec<PathBuf> {
pub fn get_conda_environment_paths(
env_vars: &EnvVariables,
conda_executable: &Option<PathBuf>,
) -> Vec<PathBuf> {
let mut env_paths = thread::scope(|s| {
let mut envs = vec![];
for thread in [
s.spawn(|| get_conda_envs_from_environment_txt(env_vars)),
s.spawn(|| get_conda_environment_paths_from_conda_rc(env_vars)),
s.spawn(|| get_conda_environment_paths_from_known_paths(env_vars)),
s.spawn(|| get_known_conda_install_locations(env_vars)),
s.spawn(|| get_known_conda_install_locations(env_vars, conda_executable)),
] {
if let Ok(mut env_paths) = thread.join() {
envs.append(&mut env_paths);
Expand Down Expand Up @@ -188,7 +191,10 @@ pub fn get_conda_envs_from_environment_txt(env_vars: &EnvVariables) -> Vec<PathB
}

#[cfg(windows)]
pub fn get_known_conda_install_locations(env_vars: &EnvVariables) -> Vec<PathBuf> {
pub fn get_known_conda_install_locations(
env_vars: &EnvVariables,
conda_executable: &Option<PathBuf>,
) -> Vec<PathBuf> {
use pet_fs::path::norm_case;

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

known_paths
}

#[cfg(unix)]
pub fn get_known_conda_install_locations(env_vars: &EnvVariables) -> Vec<PathBuf> {
pub fn get_known_conda_install_locations(
env_vars: &EnvVariables,
conda_executable: &Option<PathBuf>,
) -> Vec<PathBuf> {
let mut known_paths = vec![];
let home_value = env_vars.clone().home.unwrap_or_default();
let directories_to_look_in = [
Expand Down Expand Up @@ -294,8 +306,41 @@ pub fn get_known_conda_install_locations(env_vars: &EnvVariables) -> Vec<PathBuf
known_paths.push(home.clone().join("micromamba"));
known_paths.push(home.join(".conda"));
}
if let Some(conda_dir) = get_conda_dir_from_exe(conda_executable) {
known_paths.push(conda_dir);
}
known_paths.sort();
known_paths.dedup();

known_paths
}

pub fn get_conda_dir_from_exe(conda_executable: &Option<PathBuf>) -> Option<PathBuf> {
if let Some(conda_executable) = conda_executable {
if conda_executable.is_file() {
if let Some(conda_dir) = conda_executable.parent() {
// Possible exe is in the install (root prefix) directory.
if is_conda_env(conda_dir) {
return Some(conda_dir.to_path_buf());
} else if let Some(conda_dir) = conda_dir.parent() {
// Possible the exe is in the `bin` or `Scripts` directory.
if is_conda_env(conda_dir) {
return Some(conda_dir.to_path_buf());
}
}
}
} else {
let conda_dir = conda_executable.clone();
// Possible exe is in the install (root prefix) directory.
if is_conda_env(&conda_dir) {
return Some(conda_dir.to_path_buf());
} else if let Some(conda_dir) = conda_dir.parent() {
// Possible the exe is in the `bin` or `Scripts` directory.
if is_conda_env(conda_dir) {
return Some(conda_dir.to_path_buf());
}
}
}
}
None
}
25 changes: 23 additions & 2 deletions crates/pet-conda/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
use conda_info::CondaInfo;
use env_variables::EnvVariables;
use environment_locations::{
get_conda_environment_paths, get_conda_envs_from_environment_txt, get_environments,
get_conda_dir_from_exe, get_conda_environment_paths, get_conda_envs_from_environment_txt,
get_environments,
};
use environments::{get_conda_environment_info, CondaEnvironment};
use log::error;
Expand All @@ -15,6 +16,7 @@ use pet_core::{
reporter::Reporter,
Locator,
};
use pet_fs::path::norm_case;
use pet_python_utils::env::PythonEnv;
use serde::{Deserialize, Serialize};
use std::{
Expand Down Expand Up @@ -54,13 +56,15 @@ pub struct CondaTelemetryInfo {
pub env_dirs: Vec<PathBuf>,
pub environments_txt: Option<PathBuf>,
pub environments_txt_exists: Option<bool>,
pub user_provided_env_found: Option<bool>,
pub environments_from_txt: Vec<PathBuf>,
}

pub struct Conda {
pub environments: Arc<Mutex<HashMap<PathBuf, PythonEnvironment>>>,
pub managers: Arc<Mutex<HashMap<PathBuf, CondaManager>>>,
pub env_vars: EnvVariables,
conda_executable: Arc<Mutex<Option<PathBuf>>>,
}

impl Conda {
Expand All @@ -69,6 +73,7 @@ impl Conda {
environments: Arc::new(Mutex::new(HashMap::new())),
managers: Arc::new(Mutex::new(HashMap::new())),
env_vars: EnvVariables::from(env),
conda_executable: Arc::new(Mutex::new(None)),
}
}
fn clear(&self) {
Expand Down Expand Up @@ -127,10 +132,19 @@ impl CondaLocator for Conda {
environments_txt = Some(file);
}

let conda_exe = &self.conda_executable.lock().unwrap().clone();
let envs_found = get_conda_environment_paths(&self.env_vars, conda_exe);
let mut user_provided_env_found = None;
if let Some(conda_dir) = get_conda_dir_from_exe(conda_exe) {
let conda_dir = norm_case(conda_dir);
user_provided_env_found = Some(envs_found.contains(&conda_dir));
}

CondaTelemetryInfo {
can_spawn_conda,
conda_rcs,
env_dirs,
user_provided_env_found,
environments_txt,
environments_txt_exists,
environments_from_txt: get_conda_envs_from_environment_txt(&self.env_vars),
Expand Down Expand Up @@ -192,6 +206,12 @@ impl Locator for Conda {
fn get_name(&self) -> &'static str {
"Conda" // Do not change this name, as this is used in telemetry.
}
fn configure(&self, config: &pet_core::Configuration) {
if let Some(ref conda_exe) = config.conda_executable {
let mut conda_executable = self.conda_executable.lock().unwrap();
conda_executable.replace(conda_exe.clone());
}
}
fn supported_categories(&self) -> Vec<PythonEnvironmentKind> {
vec![PythonEnvironmentKind::Conda]
}
Expand Down Expand Up @@ -262,9 +282,10 @@ impl Locator for Conda {
self.clear();

let env_vars = self.env_vars.clone();
let executable = self.conda_executable.lock().unwrap().clone();
thread::scope(|s| {
// 1. Get a list of all know conda environments file paths
let possible_conda_envs = get_conda_environment_paths(&env_vars);
let possible_conda_envs = get_conda_environment_paths(&env_vars, &executable);
for path in possible_conda_envs {
s.spawn(move || {
// 2. Get the details of the conda environment
Expand Down
Loading