-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathlib.rs
More file actions
97 lines (86 loc) · 3.58 KB
/
lib.rs
File metadata and controls
97 lines (86 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use std::ops::Deref;
use lazy_static::lazy_static;
use log::warn;
use pet_core::{
python_environment::PythonEnvironment, reporter::Reporter,
telemetry::inaccurate_python_info::InaccuratePythonEnvironmentInfo,
};
use pet_fs::path::norm_case;
use regex::Regex;
lazy_static! {
static ref PYTHON_VERSION: Regex = Regex::new(r"(\d+\.\d+\.\d+).*")
.expect("Error creating Python Version Regex for comparison");
}
pub fn report_inaccuracies_identified_after_resolving(
_reporter: &dyn Reporter,
env: &PythonEnvironment,
resolved: &PythonEnvironment,
) -> Option<()> {
let known_symlinks = env.symlinks.clone().unwrap_or_default();
let resolved_executable = &resolved.executable.clone()?;
let norm_cased_executable = norm_case(resolved_executable);
let mut invalid_executable = env.executable.clone().unwrap_or_default()
!= resolved_executable.deref()
&& env.executable.clone().unwrap_or_default() != norm_cased_executable;
if env.executable.clone().is_none() {
invalid_executable = false;
}
let mut executable_not_in_symlinks = !known_symlinks.contains(resolved_executable)
&& !known_symlinks.contains(&norm_cased_executable);
if env.executable.is_none() {
executable_not_in_symlinks = false;
}
let invalid_prefix = if let Some(ref env_prefix) = env.prefix {
let resolved_prefix = resolved.prefix.clone()?;
// Canonicalize both paths to handle symlinks — a venv prefix like
// /usr/local/venvs/myvenv may be a symlink to /usr/local/venvs/versioned/myvenv-1.0.51,
// and sys.prefix returns the resolved target. Without this, the comparison
// produces a false positive "Prefix is incorrect" warning. (See #358)
// Wrap in norm_case to handle Windows UNC prefix (`\\?\`) from canonicalize.
let env_canonical =
norm_case(std::fs::canonicalize(env_prefix).unwrap_or(env_prefix.clone()));
let resolved_canonical =
norm_case(std::fs::canonicalize(&resolved_prefix).unwrap_or(resolved_prefix));
env_canonical != resolved_canonical
} else {
false
};
let mut invalid_arch = env.arch.clone() != resolved.arch.clone();
if env.arch.clone().is_none() {
invalid_arch = false;
}
let invalid_version = are_versions_different(
&resolved.version.clone()?,
&env.version.clone().unwrap_or_default(),
);
if invalid_executable
|| executable_not_in_symlinks
|| invalid_prefix
|| invalid_arch
|| invalid_version.unwrap_or_default()
{
let event = InaccuratePythonEnvironmentInfo {
kind: env.kind,
invalid_executable: Some(invalid_executable),
executable_not_in_symlinks: Some(executable_not_in_symlinks),
invalid_prefix: Some(invalid_prefix),
invalid_version,
invalid_arch: Some(invalid_arch),
};
warn!(
"Inaccurate Python Environment Info for => \n{}.\nResolved as => \n{}\nIncorrect information => \n{}",
env, resolved, event
);
// reporter.report_telemetry(TelemetryEvent::InaccuratePythonEnvironmentInfo(event));
}
Option::Some(())
}
fn are_versions_different(actual: &str, expected: &str) -> Option<bool> {
let actual = PYTHON_VERSION.captures(actual)?;
let actual = actual.get(1)?.as_str().to_string();
let expected = PYTHON_VERSION.captures(expected)?;
let expected = expected.get(1)?.as_str().to_string();
Some(actual != expected)
}