Skip to content

Support virtualenvwrapper in nativelocator #23388

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 1 commit into from
May 8, 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
8 changes: 5 additions & 3 deletions native_locator/src/conda.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use crate::known;
use crate::messaging;
use crate::messaging::EnvManagerType;
use crate::utils::find_python_binary_path;
use regex::Regex;
use std::env;
Expand Down Expand Up @@ -218,15 +219,15 @@ pub fn find_conda_binary(environment: &impl known::Environment) -> Option<PathBu

pub fn get_conda_version(conda_binary: &PathBuf) -> Option<String> {
let mut parent = conda_binary.parent()?;
if parent.ends_with("bin"){
if parent.ends_with("bin") {
parent = parent.parent()?;
}
if parent.ends_with("Library"){
if parent.ends_with("Library") {
parent = parent.parent()?;
}
let conda_python_json_path = match get_conda_package_json_path(&parent, "conda") {
Some(exe) => Some(exe),
None => get_conda_package_json_path(&parent.parent()?, "conda")
None => get_conda_package_json_path(&parent.parent()?, "conda"),
}?;
get_version_from_meta_json(&conda_python_json_path)
}
Expand Down Expand Up @@ -387,6 +388,7 @@ pub fn find_and_report(
let params = messaging::EnvManager::new(
conda_binary.to_string_lossy().to_string(),
get_conda_version(&conda_binary),
EnvManagerType::Conda,
);
dispatcher.report_environment_manager(params);

Expand Down
27 changes: 20 additions & 7 deletions native_locator/src/global_virtualenvs.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::pipenv;
use crate::virtualenvwrapper;
use crate::{
known,
utils::{find_python_binary_path, get_version},
messaging::MessageDispatcher,
utils::{find_python_binary_path, get_version, PythonEnv},
};
use std::{fs, path::PathBuf};

Expand Down Expand Up @@ -43,12 +46,6 @@ fn get_global_virtualenv_dirs(environment: &impl known::Environment) -> Vec<Path
venv_dirs
}

pub struct PythonEnv {
pub path: PathBuf,
pub executable: PathBuf,
pub version: Option<String>,
}

pub fn list_global_virtualenvs(environment: &impl known::Environment) -> Vec<PythonEnv> {
let mut python_envs: Vec<PythonEnv> = vec![];
for root_dir in get_global_virtualenv_dirs(environment).iter() {
Expand All @@ -73,3 +70,19 @@ pub fn list_global_virtualenvs(environment: &impl known::Environment) -> Vec<Pyt

python_envs
}

pub fn find_and_report(
dispatcher: &mut impl MessageDispatcher,
environment: &impl known::Environment,
) -> Option<()> {
for env in list_global_virtualenvs(environment).iter() {
if pipenv::find_and_report(&env, dispatcher).is_some() {
continue;
}
if virtualenvwrapper::find_and_report(&env, dispatcher, environment).is_some() {
continue;
}
}

None
}
3 changes: 3 additions & 0 deletions native_locator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ pub mod conda;
pub mod known;
pub mod pyenv;
pub mod global_virtualenvs;
pub mod virtualenvwrapper;
pub mod pipenv;
pub mod virtualenv;
6 changes: 4 additions & 2 deletions native_locator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ mod messaging;
mod pipenv;
mod pyenv;
mod utils;
mod virtualenv;
mod virtualenvwrapper;
mod windows_python;

fn main() {
Expand All @@ -25,6 +27,8 @@ fn main() {
dispatcher.log_info("Starting Native Locator");
let now = SystemTime::now();

global_virtualenvs::find_and_report(&mut dispatcher, &environment);

// Finds python on PATH
common_python::find_and_report(&mut dispatcher, &environment);

Expand All @@ -37,8 +41,6 @@ fn main() {

pyenv::find_and_report(&mut dispatcher, &environment);

pipenv::find_and_report(&mut dispatcher, &environment);

#[cfg(unix)]
homebrew::find_and_report(&mut dispatcher, &environment);

Expand Down
13 changes: 12 additions & 1 deletion native_locator/src/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,27 @@ pub trait MessageDispatcher {
fn log_error(&mut self, message: &str) -> ();
}

#[derive(Serialize, Deserialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
pub enum EnvManagerType {
Conda,
Pyenv,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EnvManager {
pub executable_path: String,
pub version: Option<String>,
pub tool: EnvManagerType,
}

impl EnvManager {
pub fn new(executable_path: String, version: Option<String>) -> Self {
pub fn new(executable_path: String, version: Option<String>, tool: EnvManagerType) -> Self {
Self {
executable_path,
version,
tool,
}
}
}
Expand All @@ -35,6 +44,7 @@ impl Clone for EnvManager {
Self {
executable_path: self.executable_path.clone(),
version: self.version.clone(),
tool: self.tool,
}
}
}
Expand Down Expand Up @@ -67,6 +77,7 @@ pub enum PythonEnvironmentCategory {
PyenvVirtualEnv,
WindowsStore,
Pipenv,
VirtualEnvWrapper,
}

#[derive(Serialize, Deserialize)]
Expand Down
57 changes: 26 additions & 31 deletions native_locator/src/pipenv.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::global_virtualenvs::{list_global_virtualenvs, PythonEnv};
use crate::known;
use crate::messaging::{MessageDispatcher, PythonEnvironment};
use crate::utils::PythonEnv;
use std::fs;
use std::path::PathBuf;

fn get_project_folder(env: &PythonEnv) -> Option<String> {
fn get_pipenv_project(env: &PythonEnv) -> Option<String> {
let project_file = env.path.join(".project");
if project_file.exists() {
if let Ok(contents) = fs::read_to_string(project_file) {
Expand All @@ -21,35 +20,31 @@ fn get_project_folder(env: &PythonEnv) -> Option<String> {
None
}

pub fn find_and_report(
dispatcher: &mut impl MessageDispatcher,
environment: &impl known::Environment,
) -> Option<()> {
for env in list_global_virtualenvs(environment).iter() {
if let Some(project_path) = get_project_folder(&env) {
let env_path = env
.path
.clone()
.into_os_string()
.to_string_lossy()
.to_string();
let executable = env
.executable
.clone()
.into_os_string()
.to_string_lossy()
.to_string();
let env = PythonEnvironment::new_pipenv(
Some(executable),
env.version.clone(),
Some(env_path.clone()),
Some(env_path),
None,
project_path,
);
pub fn find_and_report(env: &PythonEnv, dispatcher: &mut impl MessageDispatcher) -> Option<()> {
if let Some(project_path) = get_pipenv_project(env) {
let env_path = env
.path
.clone()
.into_os_string()
.to_string_lossy()
.to_string();
let executable = env
.executable
.clone()
.into_os_string()
.to_string_lossy()
.to_string();
let env = PythonEnvironment::new_pipenv(
Some(executable),
env.version.clone(),
Some(env_path.clone()),
Some(env_path),
None,
project_path,
);

dispatcher.report_environment(env);
}
dispatcher.report_environment(env);
return Some(());
}

None
Expand Down
3 changes: 2 additions & 1 deletion native_locator/src/pyenv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::path::PathBuf;
use crate::known;
use crate::messaging;
use crate::messaging::EnvManager;
use crate::messaging::EnvManagerType;
use crate::utils::find_python_binary_path;
use crate::utils::parse_pyenv_cfg;

Expand Down Expand Up @@ -156,7 +157,7 @@ pub fn find_and_report(

let manager = match get_pyenv_binary(environment) {
Some(pyenv_binary) => {
let manager = messaging::EnvManager::new(pyenv_binary, None);
let manager = messaging::EnvManager::new(pyenv_binary, None, EnvManagerType::Pyenv);
dispatcher.report_environment_manager(manager.clone());
Some(manager)
}
Expand Down
7 changes: 7 additions & 0 deletions native_locator/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ use std::{
process::Command,
};

#[derive(Debug)]
pub struct PythonEnv {
pub path: PathBuf,
pub executable: PathBuf,
pub version: Option<String>,
}

#[derive(Debug)]
pub struct PyEnvCfg {
pub version: String,
Expand Down
43 changes: 43 additions & 0 deletions native_locator/src/virtualenv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use std::path::PathBuf;

use crate::utils::PythonEnv;

pub fn is_virtualenv(env: &PythonEnv) -> bool {
if let Some(file_path) = PathBuf::from(env.executable.clone()).parent() {
// Check if there are any activate.* files in the same directory as the interpreter.
//
// env
// |__ activate, activate.* <--- check if any of these files exist
// |__ python <--- interpreterPath

// if let Some(parent_path) = PathBuf::from(env.)
// const directory = path.dirname(interpreterPath);
// const files = await fsapi.readdir(directory);
// const regex = /^activate(\.([A-z]|\d)+)?$/i;
if file_path.join("activate").exists() || file_path.join("activate.bat").exists() {
return true;
}

// Support for activate.ps, etc.
match std::fs::read_dir(file_path) {
Ok(files) => {
for file in files {
if let Ok(file) = file {
if let Some(file_name) = file.file_name().to_str() {
if file_name.starts_with("activate") {
return true;
}
}
}
}
return false;
}
Err(_) => return false,
};
}

false
}
Loading
Loading