Skip to content

Commit b402f12

Browse files
authored
Fx win reg locator (#23486)
1 parent da9caf0 commit b402f12

File tree

1 file changed

+158
-102
lines changed

1 file changed

+158
-102
lines changed

native_locator/src/windows_registry.rs

Lines changed: 158 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -16,114 +16,134 @@ use std::path::PathBuf;
1616
#[cfg(windows)]
1717
use winreg::RegKey;
1818

19-
#[cfg(windows)]
20-
fn get_registry_pythons_from_key(
21-
hk: &RegKey,
22-
conda_locator: &mut dyn CondaLocator,
23-
) -> Option<LocatorResult> {
24-
let mut environments = vec![];
25-
let mut managers: Vec<EnvManager> = vec![];
26-
let python_key = hk.open_subkey("Software\\Python").ok()?;
27-
for company in python_key.enum_keys().filter_map(Result::ok) {
28-
if let Some(result) =
29-
get_registry_pythons_from_key_for_company(&hk, &company, conda_locator)
30-
{
31-
managers.extend(result.managers);
32-
environments.extend(result.environments);
33-
}
34-
}
35-
36-
Some(LocatorResult {
37-
environments,
38-
managers,
39-
})
40-
}
41-
4219
#[cfg(windows)]
4320
fn get_registry_pythons_from_key_for_company(
44-
hk: &RegKey,
21+
key_container: &str,
22+
company_key: &RegKey,
4523
company: &str,
4624
conda_locator: &mut dyn CondaLocator,
4725
) -> Option<LocatorResult> {
48-
use crate::messaging::Architecture;
26+
use log::{trace, warn};
4927

50-
let mut environments = vec![];
28+
use crate::messaging::Architecture;
5129
let mut managers: Vec<EnvManager> = vec![];
52-
let python_key = hk.open_subkey("Software\\Python").ok()?;
53-
let company_key = python_key.open_subkey(company).ok()?;
30+
let mut environments = vec![];
5431
let company_display_name: Option<String> = company_key.get_value("DisplayName").ok();
55-
for key in company_key.enum_keys().filter_map(Result::ok) {
56-
if let Some(key) = company_key.open_subkey(key).ok() {
57-
if let Some(install_path_key) = key.open_subkey("InstallPath").ok() {
58-
let env_path: String = install_path_key.get_value("").ok().unwrap_or_default();
59-
let env_path = PathBuf::from(env_path);
32+
for installed_python in company_key.enum_keys().filter_map(Result::ok) {
33+
match company_key.open_subkey(installed_python.clone()) {
34+
Ok(installed_python_key) => {
35+
match installed_python_key.open_subkey("InstallPath") {
36+
Ok(install_path_key) => {
37+
let env_path: String =
38+
install_path_key.get_value("").ok().unwrap_or_default();
39+
let env_path = PathBuf::from(env_path);
40+
trace!(
41+
"Found Python ({}) in {}\\Software\\Python\\{}\\{}",
42+
env_path.to_str().unwrap_or_default(),
43+
key_container,
44+
company,
45+
installed_python,
46+
);
47+
48+
// Possible this is a conda install folder.
49+
if let Some(conda_result) = conda_locator.find_in(&env_path) {
50+
for manager in conda_result.managers {
51+
let mut mgr = manager.clone();
52+
mgr.company = Some(company.to_string());
53+
mgr.company_display_name = company_display_name.clone();
54+
managers.push(mgr)
55+
}
56+
for env in conda_result.environments {
57+
let mut env = env.clone();
58+
env.company = Some(company.to_string());
59+
env.company_display_name = company_display_name.clone();
60+
if let Some(mgr) = env.env_manager {
61+
let mut mgr = mgr.clone();
62+
mgr.company = Some(company.to_string());
63+
mgr.company_display_name = company_display_name.clone();
64+
env.env_manager = Some(mgr);
65+
}
66+
environments.push(env);
67+
}
68+
continue;
69+
}
6070

61-
// Possible this is a conda install folder.
62-
if let Some(conda_result) = conda_locator.find_in(&env_path) {
63-
for manager in conda_result.managers {
64-
let mut mgr = manager.clone();
65-
mgr.company = Some(company.to_string());
66-
mgr.company_display_name = company_display_name.clone();
67-
managers.push(mgr)
68-
}
69-
for env in conda_result.environments {
70-
let mut env = env.clone();
71+
let env_path = if env_path.exists() {
72+
Some(env_path)
73+
} else {
74+
None
75+
};
76+
let executable: String = install_path_key
77+
.get_value("ExecutablePath")
78+
.ok()
79+
.unwrap_or_default();
80+
if executable.len() == 0 {
81+
warn!(
82+
"Executable is empty {}\\Software\\Python\\{}\\{}\\ExecutablePath",
83+
key_container, company, installed_python
84+
);
85+
continue;
86+
}
87+
let executable = PathBuf::from(executable);
88+
if !executable.exists() {
89+
warn!(
90+
"Python executable ({}) file not found for {}\\Software\\Python\\{}\\{}",
91+
executable.to_str().unwrap_or_default(),
92+
key_container,
93+
company,
94+
installed_python
95+
);
96+
continue;
97+
}
98+
let version: String = installed_python_key
99+
.get_value("Version")
100+
.ok()
101+
.unwrap_or_default();
102+
let architecture: String = installed_python_key
103+
.get_value("SysArchitecture")
104+
.ok()
105+
.unwrap_or_default();
106+
let display_name: String = installed_python_key
107+
.get_value("DisplayName")
108+
.ok()
109+
.unwrap_or_default();
110+
111+
let mut env = PythonEnvironment::new(
112+
Some(display_name),
113+
None,
114+
Some(executable.clone()),
115+
PythonEnvironmentCategory::WindowsRegistry,
116+
if version.len() > 0 {
117+
Some(version)
118+
} else {
119+
None
120+
},
121+
env_path,
122+
None,
123+
Some(vec![executable.to_string_lossy().to_string()]),
124+
);
125+
if architecture.contains("32") {
126+
env.arch = Some(Architecture::X86);
127+
} else if architecture.contains("64") {
128+
env.arch = Some(Architecture::X64);
129+
}
71130
env.company = Some(company.to_string());
72131
env.company_display_name = company_display_name.clone();
73-
if let Some(mgr) = env.env_manager {
74-
let mut mgr = mgr.clone();
75-
mgr.company = Some(company.to_string());
76-
mgr.company_display_name = company_display_name.clone();
77-
env.env_manager = Some(mgr);
78-
}
79132
environments.push(env);
80133
}
81-
continue;
82-
}
83-
84-
let env_path = if env_path.exists() {
85-
Some(env_path)
86-
} else {
87-
None
88-
};
89-
let executable: String = install_path_key
90-
.get_value("ExecutablePath")
91-
.ok()
92-
.unwrap_or_default();
93-
if executable.len() == 0 {
94-
continue;
95-
}
96-
let executable = PathBuf::from(executable);
97-
if !executable.exists() {
98-
continue;
134+
Err(err) => {
135+
warn!(
136+
"Failed to open {}\\Software\\Python\\{}\\{}\\InstallPath, {:?}",
137+
key_container, company, installed_python, err
138+
);
139+
}
99140
}
100-
let version: String = key.get_value("Version").ok().unwrap_or_default();
101-
let architecture: String =
102-
key.get_value("SysArchitecture").ok().unwrap_or_default();
103-
let display_name: String = key.get_value("DisplayName").ok().unwrap_or_default();
104-
105-
let mut env = PythonEnvironment::new(
106-
Some(display_name),
107-
None,
108-
Some(executable.clone()),
109-
PythonEnvironmentCategory::WindowsRegistry,
110-
if version.len() > 0 {
111-
Some(version)
112-
} else {
113-
None
114-
},
115-
env_path,
116-
None,
117-
Some(vec![executable.to_string_lossy().to_string()]),
141+
}
142+
Err(err) => {
143+
warn!(
144+
"Failed to open {}\\Software\\Python\\{}\\{}, {:?}",
145+
key_container, company, installed_python, err
118146
);
119-
if architecture.contains("32") {
120-
env.arch = Some(Architecture::X86);
121-
} else if architecture.contains("64") {
122-
env.arch = Some(Architecture::X64);
123-
}
124-
env.company = Some(company.to_string());
125-
env.company_display_name = company_display_name.clone();
126-
environments.push(env);
127147
}
128148
}
129149
}
@@ -136,19 +156,55 @@ fn get_registry_pythons_from_key_for_company(
136156

137157
#[cfg(windows)]
138158
fn get_registry_pythons(conda_locator: &mut dyn CondaLocator) -> Option<LocatorResult> {
139-
let hklm = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE);
140-
let hkcu = winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER);
159+
use log::{trace, warn};
141160

142161
let mut environments = vec![];
143162
let mut managers: Vec<EnvManager> = vec![];
144163

145-
if let Some(result) = get_registry_pythons_from_key(&hklm, conda_locator) {
146-
managers.extend(result.managers);
147-
environments.extend(result.environments);
164+
struct RegistryKey {
165+
pub name: &'static str,
166+
pub key: winreg::RegKey,
148167
}
149-
if let Some(result) = get_registry_pythons_from_key(&hkcu, conda_locator) {
150-
managers.extend(result.managers);
151-
environments.extend(result.environments);
168+
let search_keys = [
169+
RegistryKey {
170+
name: "HKLM",
171+
key: winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE),
172+
},
173+
RegistryKey {
174+
name: "HKCU",
175+
key: winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER),
176+
},
177+
];
178+
for (name, key) in search_keys.iter().map(|f| (f.name, &f.key)) {
179+
match key.open_subkey("Software\\Python") {
180+
Ok(python_key) => {
181+
for company in python_key.enum_keys().filter_map(Result::ok) {
182+
trace!("Searching {}\\Software\\Python\\{}", name, company);
183+
match python_key.open_subkey(&company) {
184+
Ok(company_key) => {
185+
if let Some(result) = get_registry_pythons_from_key_for_company(
186+
name,
187+
&company_key,
188+
&company,
189+
conda_locator,
190+
) {
191+
managers.extend(result.managers);
192+
environments.extend(result.environments);
193+
}
194+
}
195+
Err(err) => {
196+
warn!(
197+
"Failed to open {}\\Software\\Python\\{}, {:?}",
198+
name, company, err
199+
);
200+
}
201+
}
202+
}
203+
}
204+
Err(err) => {
205+
warn!("Failed to open {}\\Software\\Python, {:?}", name, err)
206+
}
207+
}
152208
}
153209
Some(LocatorResult {
154210
environments,
@@ -177,7 +233,7 @@ impl Locator for WindowsRegistry<'_> {
177233

178234
fn find(&mut self) -> Option<LocatorResult> {
179235
if let Some(result) = get_registry_pythons(self.conda_locator) {
180-
if !result.environments.is_empty() && !result.managers.is_empty() {
236+
if !result.environments.is_empty() || !result.managers.is_empty() {
181237
return Some(result);
182238
}
183239
}

0 commit comments

Comments
 (0)