Skip to content

Commit ed2e1aa

Browse files
authored
Look for Python (PythonCore) in windows registry (#23414)
1 parent b15a3c4 commit ed2e1aa

File tree

5 files changed

+110
-79
lines changed

5 files changed

+110
-79
lines changed

native_locator/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ pub mod pipenv;
1414
pub mod virtualenv;
1515
pub mod venv;
1616
pub mod locator;
17+
pub mod windows_registry;
18+
pub mod windows_store;

native_locator/src/main.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ mod utils;
2424
mod venv;
2525
mod virtualenv;
2626
mod virtualenvwrapper;
27-
mod windows_python;
27+
mod windows_store;
28+
mod windows_registry;
2829

2930
fn main() {
3031
let environment = EnvironmentApi {};
@@ -44,7 +45,9 @@ fn main() {
4445
#[cfg(unix)]
4546
let homebrew_locator = homebrew::Homebrew::with(&environment);
4647
#[cfg(windows)]
47-
let windows_locator = windows_python::WindowsPython::with(&environment);
48+
let windows_store = windows_store::WindowsStore::with(&environment);
49+
#[cfg(windows)]
50+
let windows_registry = windows_registry::WindowsRegistry::new();
4851
let conda_locator = conda::Conda::with(&environment);
4952

5053
// Step 1: These environments take precedence over all others.
@@ -54,7 +57,9 @@ fn main() {
5457
find_environments(&homebrew_locator, &mut dispatcher);
5558
find_environments(&conda_locator, &mut dispatcher);
5659
#[cfg(windows)]
57-
find_environments(&windows_locator, &mut dispatcher);
60+
find_environments(&windows_registry, &mut dispatcher);
61+
#[cfg(windows)]
62+
find_environments(&windows_store, &mut dispatcher);
5863

5964
// Step 2: Search in some global locations.
6065
for env in list_global_virtual_envs(&environment).iter() {

native_locator/src/messaging.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub enum PythonEnvironmentCategory {
8383
Pyenv,
8484
PyenvVirtualEnv,
8585
WindowsStore,
86+
WindowsRegistry,
8687
Pipenv,
8788
VirtualEnvWrapper,
8889
Venv,
Lines changed: 91 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,91 @@
1-
// // Copyright (c) Microsoft Corporation. All rights reserved.
2-
// // Licensed under the MIT License.
3-
// use crate::messaging;
4-
// use std::path::PathBuf;
5-
// use winreg::RegKey;
6-
7-
// fn get_registry_pythons_from_key(
8-
// dispatcher: &mut impl messaging::MessageDispatcher,
9-
// hk: &RegKey,
10-
// company: &str,
11-
// ) -> Option<Vec<PathBuf>> {
12-
// let python_key = hk.open_subkey("Software\\Python").ok()?;
13-
// let company_key = python_key.open_subkey(company).ok()?;
14-
15-
// let mut pythons = vec![];
16-
// for key in company_key.enum_keys().filter_map(Result::ok) {
17-
// let version_key = company_key.open_subkey(key).ok()?;
18-
// let install_path_key = version_key.open_subkey("InstallPath").ok()?;
19-
// let executable: String = install_path_key.get_value("ExecutablePath").ok()?;
20-
// let version = version_key.get_value("Version").ok()?;
21-
22-
// dispatcher.report_environment(messaging::PythonEnvironment::new(
23-
// None,
24-
// Some(PathBuf::from(executable.clone())),
25-
// messaging::PythonEnvironmentCategory::WindowsRegistry,
26-
// Some(version),
27-
// None,
28-
// None,
29-
// None,
30-
// None,
31-
// ));
32-
33-
// pythons.push(PathBuf::from(executable));
34-
// }
35-
36-
// Some(pythons)
37-
// }
38-
39-
// #[cfg(windows)]
40-
// pub fn report_and_get_registry_pythons(
41-
// dispatcher: &mut impl messaging::MessageDispatcher,
42-
// company: &str,
43-
// ) -> Option<Vec<PathBuf>> {
44-
// let hklm = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE);
45-
// let hkcu = winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER);
46-
47-
// let mut pythons = vec![];
48-
// if let Some(hklm_pythons) = get_registry_pythons_from_key(dispatcher, &hklm, company) {
49-
// pythons.extend(hklm_pythons);
50-
// }
51-
// if let Some(hkcu_pythons) = get_registry_pythons_from_key(dispatcher, &hkcu, company) {
52-
// pythons.extend(hkcu_pythons);
53-
// }
54-
55-
// Some(pythons)
56-
// }
57-
58-
// // PythonCore
59-
// // ContinuumAnalytics
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#[cfg(windows)]
5+
use crate::locator::{Locator, LocatorResult};
6+
#[cfg(windows)]
7+
use crate::messaging::{PythonEnvironment, PythonEnvironmentCategory};
8+
#[cfg(windows)]
9+
use crate::utils::PythonEnv;
10+
#[cfg(windows)]
11+
use winreg::RegKey;
12+
#[cfg(windows)]
13+
use std::path::PathBuf;
14+
15+
#[cfg(windows)]
16+
fn get_registry_pythons_from_key(hk: &RegKey, company: &str) -> Option<Vec<PythonEnvironment>> {
17+
let python_key = hk.open_subkey("Software\\Python").ok()?;
18+
let company_key = python_key.open_subkey(company).ok()?;
19+
20+
let mut pythons = vec![];
21+
for key in company_key.enum_keys().filter_map(Result::ok) {
22+
let version_key = company_key.open_subkey(key).ok()?;
23+
let install_path_key = version_key.open_subkey("InstallPath").ok()?;
24+
let executable: String = install_path_key.get_value("ExecutablePath").ok()?;
25+
let version = version_key.get_value("Version").ok()?;
26+
27+
let env = PythonEnvironment::new(
28+
None,
29+
Some(PathBuf::from(executable.clone())),
30+
PythonEnvironmentCategory::WindowsRegistry,
31+
Some(version),
32+
None,
33+
None,
34+
None,
35+
Some(vec![executable.clone()]),
36+
);
37+
38+
pythons.push(env);
39+
}
40+
41+
Some(pythons)
42+
}
43+
44+
#[cfg(windows)]
45+
pub fn get_registry_pythons(company: &str) -> Option<Vec<PythonEnvironment>> {
46+
let hklm = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE);
47+
let hkcu = winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER);
48+
49+
let mut pythons = vec![];
50+
if let Some(hklm_pythons) = get_registry_pythons_from_key(&hklm, company) {
51+
pythons.extend(hklm_pythons);
52+
}
53+
if let Some(hkcu_pythons) = get_registry_pythons_from_key(&hkcu, company) {
54+
pythons.extend(hkcu_pythons);
55+
}
56+
57+
Some(pythons)
58+
}
59+
60+
#[cfg(windows)]
61+
pub struct WindowsRegistry {}
62+
63+
#[cfg(windows)]
64+
impl WindowsRegistry {
65+
#[allow(dead_code)]
66+
pub fn new() -> WindowsRegistry {
67+
WindowsRegistry {}
68+
}
69+
}
70+
71+
#[cfg(windows)]
72+
impl Locator for WindowsRegistry {
73+
fn resolve(&self, env: &PythonEnv) -> Option<PythonEnvironment> {
74+
None
75+
}
76+
77+
fn find(&self) -> Option<LocatorResult> {
78+
let environments = get_registry_pythons("PythonCore")?;
79+
if environments.is_empty() {
80+
None
81+
} else {
82+
Some(LocatorResult {
83+
managers: vec![],
84+
environments,
85+
})
86+
}
87+
}
88+
}
89+
90+
// PythonCore
91+
// ContinuumAnalytics

native_locator/src/windows_python.rs renamed to native_locator/src/windows_store.rs

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ use crate::utils::PythonEnv;
99
use std::path::Path;
1010
use std::path::PathBuf;
1111

12-
fn is_windows_python_executable(path: &PathBuf) -> bool {
12+
pub fn is_windows_python_executable(path: &PathBuf) -> bool {
1313
let name = path.file_name().unwrap().to_string_lossy().to_lowercase();
14+
// TODO: Is it safe to assume the number 3?
1415
name.starts_with("python3.") && name.ends_with(".exe")
1516
}
17+
1618
fn list_windows_store_python_executables(
1719
environment: &dyn known::Environment,
1820
) -> Option<Vec<PathBuf>> {
@@ -38,22 +40,18 @@ fn list_windows_store_python_executables(
3840
Some(python_envs)
3941
}
4042

41-
fn list_registry_pythons() -> Option<Vec<PathBuf>> {
42-
None
43-
}
44-
45-
pub struct WindowsPython<'a> {
43+
pub struct WindowsStore<'a> {
4644
pub environment: &'a dyn Environment,
4745
}
4846

49-
impl WindowsPython<'_> {
47+
impl WindowsStore<'_> {
5048
#[allow(dead_code)]
51-
pub fn with<'a>(environment: &'a impl Environment) -> WindowsPython {
52-
WindowsPython { environment }
49+
pub fn with<'a>(environment: &'a impl Environment) -> WindowsStore {
50+
WindowsStore { environment }
5351
}
5452
}
5553

56-
impl Locator for WindowsPython<'_> {
54+
impl Locator for WindowsStore<'_> {
5755
fn resolve(&self, env: &PythonEnv) -> Option<PythonEnvironment> {
5856
if is_windows_python_executable(&env.executable) {
5957
return Some(PythonEnvironment {
@@ -80,13 +78,6 @@ impl Locator for WindowsPython<'_> {
8078
}
8179
});
8280
}
83-
if let Some(envs) = list_registry_pythons() {
84-
envs.iter().for_each(|env| {
85-
if let Some(env) = self.resolve(&&PythonEnv::from(env.clone())) {
86-
environments.push(env);
87-
}
88-
});
89-
}
9081

9182
if environments.is_empty() {
9283
None

0 commit comments

Comments
 (0)