Skip to content

Commit 398e32a

Browse files
authored
Ensure we parse env variables once (#94)
1 parent f4f78b0 commit 398e32a

File tree

26 files changed

+175
-147
lines changed

26 files changed

+175
-147
lines changed

crates/pet-conda/src/environment_locations.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,8 @@ fn get_conda_environment_paths_from_known_paths(env_vars: &EnvVariables) -> Vec<
9090
if let Ok(entries) = fs::read_dir(full_path) {
9191
for entry in entries.filter_map(Result::ok) {
9292
let path = entry.path();
93-
if let Ok(meta) = fs::metadata(&path) {
94-
if meta.is_dir() {
95-
env_paths.push(path);
96-
}
93+
if path.is_dir() {
94+
env_paths.push(path);
9795
}
9896
}
9997
}
@@ -112,10 +110,8 @@ fn get_conda_environment_paths_from_additional_paths(
112110
if let Ok(entries) = fs::read_dir(path) {
113111
for entry in entries.filter_map(Result::ok) {
114112
let path = entry.path();
115-
if let Ok(meta) = fs::metadata(&path) {
116-
if meta.is_dir() {
117-
env_paths.push(path);
118-
}
113+
if path.is_dir() {
114+
env_paths.push(path);
119115
}
120116
}
121117
}
@@ -146,7 +142,7 @@ pub fn get_environments(conda_dir: &Path) -> Vec<PathBuf> {
146142
}
147143
} else if is_conda_env(conda_dir) {
148144
envs.push(conda_dir.to_path_buf());
149-
} else if fs::metadata(conda_dir.join("envs")).is_ok() {
145+
} else if conda_dir.join("envs").exists() {
150146
// This could be a directory where conda environments are stored.
151147
// I.e. its not necessarily the root conda install directory.
152148
// E.g. C:\Users\donjayamanne\.conda

crates/pet-conda/src/environments.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ use pet_core::{
1414
};
1515
use pet_fs::path::{norm_case, resolve_symlink};
1616
use pet_python_utils::executable::{find_executable, find_executables};
17-
use std::{
18-
fs,
19-
path::{Path, PathBuf},
20-
};
17+
use std::path::{Path, PathBuf};
2118

2219
#[derive(Debug, Clone)]
2320
pub struct CondaEnvironment {
@@ -84,7 +81,7 @@ pub fn get_conda_environment_info(
8481
None => get_conda_installation_used_to_create_conda_env(env_path),
8582
};
8683
if let Some(conda_dir) = &conda_install_folder {
87-
if fs::metadata(conda_dir).is_err() {
84+
if !conda_dir.exists() {
8885
warn!(
8986
"Conda install folder {}, does not exist, hence will not be used for the Conda Env: {}",
9087
env_path.display(),

crates/pet-conda/src/manager.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn get_conda_executable(path: &Path) -> Option<PathBuf> {
2323

2424
for relative_path in relative_path_to_conda_exe {
2525
let exe = path.join(&relative_path);
26-
if exe.metadata().is_ok() {
26+
if exe.exists() {
2727
return Some(exe);
2828
}
2929
}
@@ -49,10 +49,8 @@ pub fn find_conda_binary(env_vars: &EnvVariables) -> Option<PathBuf> {
4949
for path in env::split_paths(&paths) {
5050
for bin in get_conda_bin_names() {
5151
let conda_path = path.join(bin);
52-
if let Ok(metadata) = std::fs::metadata(&conda_path) {
53-
if metadata.is_file() || metadata.is_symlink() {
54-
return Some(conda_path);
55-
}
52+
if conda_path.is_file() || conda_path.is_symlink() {
53+
return Some(conda_path);
5654
}
5755
}
5856
}

crates/pet-conda/src/utils.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
use std::{
5-
fs,
6-
path::{Path, PathBuf},
7-
};
4+
use std::path::{Path, PathBuf};
85

96
/// conda-meta must exist as this contains a mandatory `history` file.
107
pub fn is_conda_install(path: &Path) -> bool {
11-
(path.join("condabin").metadata().is_ok() || path.join("envs").metadata().is_ok())
12-
&& path.join("conda-meta").metadata().is_ok()
8+
(path.join("condabin").exists() || path.join("envs").exists())
9+
&& path.join("conda-meta").exists()
1310
}
1411

1512
/// conda-meta must exist as this contains a mandatory `history` file.
1613
/// The root conda installation folder is also a conda environment (its the base environment).
1714
pub fn is_conda_env(path: &Path) -> bool {
18-
if let Ok(metadata) = fs::metadata(path.join("conda-meta")) {
19-
metadata.is_dir()
20-
} else {
21-
false
22-
}
15+
path.join("conda-meta").is_dir()
2316
}
2417

2518
/// Only used in tests, noop in production.

crates/pet-core/src/os_environment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::{
1010
use log::trace;
1111
use pet_fs::path::norm_case;
1212

13-
pub trait Environment {
13+
pub trait Environment: Send + Sync {
1414
fn get_user_home(&self) -> Option<PathBuf>;
1515
/// Only used in tests, None in production.
1616
#[allow(dead_code)]

crates/pet-core/src/python_environment.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,14 @@ impl PythonEnvironment {
114114

115115
impl std::fmt::Display for PythonEnvironment {
116116
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
117-
writeln!(f, "Environment ({:?})", self.kind).unwrap_or_default();
117+
writeln!(
118+
f,
119+
"Environment ({})",
120+
self.kind
121+
.map(|v| format!("{v:?}"))
122+
.unwrap_or("Unknown".to_string())
123+
)
124+
.unwrap_or_default();
118125
if let Some(name) = &self.display_name {
119126
writeln!(f, " Display-Name: {name}").unwrap_or_default();
120127
}

crates/pet-global-virtualenvs/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ fn get_global_virtualenv_dirs(
1414

1515
if let Some(work_on_home) = work_on_home_env_var {
1616
let work_on_home = norm_case(PathBuf::from(work_on_home));
17-
if fs::metadata(&work_on_home).is_ok() {
17+
if work_on_home.exists() {
1818
venv_dirs.push(work_on_home);
1919
} else if let Some(home) = &user_home {
2020
if let Ok(work_on_home) = work_on_home.strip_prefix("~") {
2121
let work_on_home = home.join(work_on_home);
22-
if fs::metadata(&work_on_home).is_ok() {
22+
if work_on_home.exists() {
2323
venv_dirs.push(work_on_home);
2424
}
2525
}
@@ -28,7 +28,7 @@ fn get_global_virtualenv_dirs(
2828

2929
// Used by pipenv (https://github.com/pypa/pipenv/blob/main/pipenv/utils/shell.py#L184)
3030
if let Some(xdg_data_home) = xdg_data_home.map(|d| PathBuf::from(d).join("virtualenvs")) {
31-
if fs::metadata(&xdg_data_home).is_ok() {
31+
if xdg_data_home.exists() {
3232
venv_dirs.push(xdg_data_home);
3333
}
3434
}
@@ -41,19 +41,19 @@ fn get_global_virtualenv_dirs(
4141
PathBuf::from(".local").join("share").join("virtualenvs"), // Used by pipenv (https://github.com/pypa/pipenv/blob/main/pipenv/utils/shell.py#L184)
4242
] {
4343
let venv_dir = home.join(dir);
44-
if fs::metadata(&venv_dir).is_ok() {
44+
if venv_dir.exists() {
4545
venv_dirs.push(venv_dir);
4646
}
4747
}
4848
if cfg!(target_os = "linux") {
4949
// https://virtualenvwrapper.readthedocs.io/en/latest/index.html
5050
// Default recommended location for virtualenvwrapper
5151
let envs = PathBuf::from("Envs");
52-
if fs::metadata(&envs).is_ok() {
52+
if envs.exists() {
5353
venv_dirs.push(envs);
5454
}
5555
let envs = PathBuf::from("envs");
56-
if fs::metadata(&envs).is_ok() {
56+
if envs.exists() {
5757
venv_dirs.push(envs);
5858
}
5959
}

crates/pet-homebrew/src/environment_locations.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use crate::env_variables::EnvVariables;
55
use lazy_static::lazy_static;
66
use regex::Regex;
7-
use std::{fs, path::PathBuf};
7+
use std::path::PathBuf;
88

99
lazy_static! {
1010
static ref PYTHON_VERSION: Regex =
@@ -41,9 +41,7 @@ pub fn get_homebrew_prefix_bin(env_vars: &EnvVariables) -> Vec<PathBuf> {
4141
// Check the environment variables
4242
if let Some(homebrew_prefix) = &env_vars.homebrew_prefix {
4343
let homebrew_prefix_bin = PathBuf::from(homebrew_prefix).join("bin");
44-
if fs::metadata(&homebrew_prefix_bin).is_ok()
45-
&& !homebrew_prefixes.contains(&homebrew_prefix_bin)
46-
{
44+
if homebrew_prefix_bin.exists() && !homebrew_prefixes.contains(&homebrew_prefix_bin) {
4745
homebrew_prefixes.push(homebrew_prefix_bin);
4846
}
4947
}

crates/pet-pipenv/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn get_pipenv_project_from_prefix(prefix: &Path) -> Option<PathBuf> {
3737
let project_file = prefix.join(".project");
3838
let contents = fs::read_to_string(project_file).ok()?;
3939
let project_folder = norm_case(PathBuf::from(contents.trim().to_string()));
40-
if fs::metadata(&project_folder).is_ok() {
40+
if project_folder.exists() {
4141
Some(project_folder)
4242
} else {
4343
None
@@ -46,14 +46,14 @@ fn get_pipenv_project_from_prefix(prefix: &Path) -> Option<PathBuf> {
4646

4747
fn is_pipenv(env: &PythonEnv, env_vars: &EnvVariables) -> bool {
4848
if let Some(project_path) = get_pipenv_project(env) {
49-
if fs::metadata(project_path.join(env_vars.pipenv_pipfile.clone())).is_ok() {
49+
if project_path.join(env_vars.pipenv_pipfile.clone()).exists() {
5050
return true;
5151
}
5252
}
5353
// If we have a Pipfile, then this is a pipenv environment.
5454
// Else likely a virtualenvwrapper or the like.
5555
if let Some(project_path) = get_pipenv_project(env) {
56-
fs::metadata(project_path.join(env_vars.pipenv_pipfile.clone())).is_ok()
56+
project_path.join(env_vars.pipenv_pipfile.clone()).exists()
5757
} else {
5858
false
5959
}

crates/pet-pyenv/src/environment_locations.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use crate::env_variables::EnvVariables;
55
use pet_fs::path::norm_case;
6-
use std::{fs, path::PathBuf};
6+
use std::path::PathBuf;
77

88
#[cfg(windows)]
99
pub fn get_home_pyenv_dir(env_vars: &EnvVariables) -> Option<PathBuf> {
@@ -24,10 +24,8 @@ pub fn get_binary_from_known_paths(env_vars: &EnvVariables) -> Option<PathBuf> {
2424
} else {
2525
known_path.join("pyenv")
2626
};
27-
if let Ok(metadata) = fs::metadata(&exe) {
28-
if metadata.is_file() {
29-
return Some(norm_case(exe));
30-
}
27+
if exe.is_file() {
28+
return Some(norm_case(exe));
3129
}
3230
}
3331
None

crates/pet-pyenv/src/manager.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ fn get_pyenv_info(environment: &EnvVariables) -> PyEnvInfo {
4141
};
4242
if let Some(dir) = get_pyenv_dir(environment) {
4343
let versions = dir.join("versions");
44-
if fs::metadata(&versions).is_ok() {
44+
if versions.exists() {
4545
pyenv.versions = Some(versions);
4646
}
4747
let exe = dir.join("bin").join("pyenv");
48-
if fs::metadata(&exe).is_ok() {
48+
if exe.exists() {
4949
pyenv.exe = Some(exe);
5050
}
5151
}
@@ -57,13 +57,13 @@ fn get_pyenv_info(environment: &EnvVariables) -> PyEnvInfo {
5757
if let Some(path) = get_home_pyenv_dir(environment) {
5858
if pyenv.exe.is_none() {
5959
let exe = path.join("bin").join("pyenv");
60-
if fs::metadata(&exe).is_ok() {
60+
if exe.exists() {
6161
pyenv.exe = Some(exe);
6262
}
6363
}
6464
if pyenv.versions.is_none() {
6565
let versions = path.join("versions");
66-
if fs::metadata(&versions).is_ok() {
66+
if versions.exists() {
6767
pyenv.versions = Some(versions);
6868
}
6969
}

crates/pet-python-utils/src/executable.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn find_executable(env_path: &Path) -> Option<PathBuf> {
2525
env_path.join("python3.exe"),
2626
]
2727
.into_iter()
28-
.find(|path| fs::metadata(path).is_ok())
28+
.find(|path| path.exists())
2929
}
3030

3131
#[cfg(unix)]
@@ -37,7 +37,7 @@ pub fn find_executable(env_path: &Path) -> Option<PathBuf> {
3737
env_path.join("python3"),
3838
]
3939
.into_iter()
40-
.find(|path| fs::metadata(path).is_ok())
40+
.find(|path| path.exists())
4141
}
4242

4343
pub fn find_executables<T: AsRef<Path>>(env_path: T) -> Vec<PathBuf> {
@@ -48,7 +48,7 @@ pub fn find_executables<T: AsRef<Path>>(env_path: T) -> Vec<PathBuf> {
4848
let mut python_executables = vec![];
4949
let bin = if cfg!(windows) { "Scripts" } else { "bin" };
5050
let mut env_path = env_path.as_ref().to_path_buf();
51-
if env_path.join(bin).metadata().is_ok() {
51+
if env_path.join(bin).exists() {
5252
env_path = env_path.join(bin);
5353
}
5454

@@ -72,18 +72,16 @@ pub fn find_executables<T: AsRef<Path>>(env_path: T) -> Vec<PathBuf> {
7272
// If you install [email protected], then only a python3.10 exe is created in that bin directory.
7373
// As a compromise, we only enumerate if this is a bin directory and there are no python exes
7474
// Else enumerating entire directories is very expensive.
75-
if env_path.join(python_exe).metadata().is_ok()
76-
|| env_path.join(python3_exe).metadata().is_ok()
75+
if env_path.join(python_exe).exists()
76+
|| env_path.join(python3_exe).exists()
7777
|| env_path.ends_with(bin)
7878
{
7979
// Enumerate this directory and get all `python` & `pythonX.X` files.
8080
if let Ok(entries) = fs::read_dir(env_path) {
8181
for entry in entries.filter_map(Result::ok) {
8282
let file = entry.path();
83-
if let Ok(metadata) = fs::metadata(&file) {
84-
if is_python_executable_name(&entry.path()) && metadata.is_file() {
85-
python_executables.push(file);
86-
}
83+
if file.is_file() && is_python_executable_name(&file) {
84+
python_executables.push(file);
8785
}
8886
}
8987
}

crates/pet-python-utils/src/headers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn get_version(path: &Path) -> Option<String> {
4141
let mut contents = "".to_string();
4242
if let Ok(result) = fs::read_to_string(patchlevel_h) {
4343
contents = result;
44-
} else if fs::metadata(&headers_path).is_err() {
44+
} else if !headers_path.exists() {
4545
// TODO: Remove this check, unnecessary, as we try to read the dir below.
4646
// Such a path does not exist, get out.
4747
continue;

crates/pet-python-utils/src/pyvenv_cfg.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ fn find(path: &Path) -> Option<PathBuf> {
4444
// Check if the pyvenv.cfg file is in the current directory.
4545
// Possible the passed value is the `env`` directory.
4646
let cfg = path.join(PYVENV_CONFIG_FILE);
47-
if fs::metadata(&cfg).is_ok() {
47+
if cfg.exists() {
4848
return Some(cfg);
4949
}
5050

5151
let bin = if cfg!(windows) { "Scripts" } else { "bin" };
5252
if path.ends_with(bin) {
5353
let cfg = path.parent()?.join(PYVENV_CONFIG_FILE);
54-
if fs::metadata(&cfg).is_ok() {
54+
if cfg.exists() {
5555
return Some(cfg);
5656
}
5757
}

crates/pet-venv/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4+
use std::path::Path;
5+
46
use pet_core::{
57
python_environment::{PythonEnvironment, PythonEnvironmentBuilder, PythonEnvironmentKind},
68
reporter::Reporter,
@@ -20,6 +22,9 @@ fn is_venv_internal(env: &PythonEnv) -> Option<bool> {
2022
pub fn is_venv(env: &PythonEnv) -> bool {
2123
is_venv_internal(env).unwrap_or_default()
2224
}
25+
pub fn is_venv_dir(path: &Path) -> bool {
26+
PyVenvCfg::find(path).is_some()
27+
}
2328
pub struct Venv {}
2429

2530
impl Venv {

crates/pet-virtualenv/src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use pet_core::{
88
};
99
use pet_python_utils::version;
1010
use pet_python_utils::{env::PythonEnv, executable::find_executables};
11-
use std::fs;
1211

1312
pub fn is_virtualenv(env: &PythonEnv) -> bool {
1413
if env.prefix.is_none() {
@@ -31,9 +30,7 @@ pub fn is_virtualenv(env: &PythonEnv) -> bool {
3130
// const directory = path.dirname(interpreterPath);
3231
// const files = await fsapi.readdir(directory);
3332
// const regex = /^activate(\.([A-z]|\d)+)?$/i;
34-
if fs::metadata(bin.join("activate")).is_ok()
35-
|| fs::metadata(bin.join("activate.bat")).is_ok()
36-
{
33+
if bin.join("activate").exists() || bin.join("activate.bat").exists() {
3734
return true;
3835
}
3936

0 commit comments

Comments
 (0)