@@ -16,114 +16,134 @@ use std::path::PathBuf;
1616#[ cfg( windows) ]
1717use 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) ]
4320fn 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) ]
138158fn 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