@@ -91,53 +91,11 @@ use std::env;
91
91
use std:: path:: PathBuf ;
92
92
use std:: process:: Command ;
93
93
94
+ use errors:: { JavaLocatorError , Result } ;
94
95
use glob:: { glob, Pattern } ;
95
- use lazy_static:: lazy_static;
96
96
97
97
pub mod errors;
98
98
99
- const WINDOWS : & ' static str = "windows" ;
100
- const MACOS : & ' static str = "macos" ;
101
- const ANDROID : & ' static str = "android" ;
102
- const UNIX : & ' static str = "unix" ;
103
-
104
- lazy_static ! {
105
- static ref TARGET_OS : String = {
106
- let target_os_res = env:: var( "CARGO_CFG_TARGET_OS" ) ;
107
- let tos = target_os_res. as_ref( ) . map( |x| & * * x) . unwrap_or_else( |_| {
108
- if cfg!( windows) {
109
- WINDOWS
110
- } else if cfg!( target_os = "macos" ) {
111
- MACOS
112
- } else if cfg!( target_os = "android" ) {
113
- ANDROID
114
- } else {
115
- UNIX
116
- }
117
- } ) ;
118
-
119
- tos. to_string( )
120
- } ;
121
- }
122
-
123
- fn is_windows ( ) -> bool {
124
- & * TARGET_OS == WINDOWS
125
- }
126
-
127
- fn is_macos ( ) -> bool {
128
- & * TARGET_OS == MACOS
129
- }
130
-
131
- #[ allow( dead_code) ]
132
- fn is_android ( ) -> bool {
133
- & * TARGET_OS == ANDROID
134
- }
135
-
136
- #[ allow( dead_code) ]
137
- fn is_unix ( ) -> bool {
138
- & * TARGET_OS == UNIX
139
- }
140
-
141
99
/// Returns the name of the jvm dynamic library:
142
100
///
143
101
/// * libjvm.so for Linux
@@ -146,11 +104,16 @@ fn is_unix() -> bool {
146
104
///
147
105
/// * jvm.dll for Windows
148
106
pub fn get_jvm_dyn_lib_file_name ( ) -> & ' static str {
149
- if is_windows ( ) {
107
+ #[ cfg( target_os = "windows" ) ]
108
+ {
150
109
"jvm.dll"
151
- } else if is_macos ( ) {
110
+ }
111
+ #[ cfg( target_os = "macos" ) ]
112
+ {
152
113
"libjvm.dylib"
153
- } else {
114
+ }
115
+ #[ cfg( not( any( target_os = "windows" , target_os = "macos" ) ) ) ]
116
+ {
154
117
"libjvm.so"
155
118
}
156
119
}
@@ -160,60 +123,103 @@ pub fn get_jvm_dyn_lib_file_name() -> &'static str {
160
123
/// If `JAVA_HOME` env var is defined, the function returns it without any checks whether the var points to a valid directory or not.
161
124
///
162
125
/// If `JAVA_HOME` is not defined, the function tries to locate it using the `java` executable.
163
- pub fn locate_java_home ( ) -> errors :: Result < String > {
126
+ pub fn locate_java_home ( ) -> Result < String > {
164
127
match & env:: var ( "JAVA_HOME" ) {
165
128
Ok ( s) if s. is_empty ( ) => do_locate_java_home ( ) ,
166
129
Ok ( java_home_env_var) => Ok ( java_home_env_var. clone ( ) ) ,
167
130
Err ( _) => do_locate_java_home ( ) ,
168
131
}
169
132
}
170
133
171
- fn do_locate_java_home ( ) -> errors:: Result < String > {
172
- // Prepare the command depending on the host
173
- let command_str = if is_windows ( ) {
174
- "where"
175
- } else if is_macos ( ) {
176
- "/usr/libexec/java_home"
177
- } else {
178
- "which"
179
- } ;
134
+ #[ cfg( target_os = "windows" ) ]
135
+ fn do_locate_java_home ( ) -> Result < String > {
136
+ let output = Command :: new ( "where" )
137
+ . arg ( "java" )
138
+ . output ( )
139
+ . map_err ( |e| JavaLocatorError :: new ( format ! ( "Failed to run command `where` ({e})" ) ) ) ?;
140
+
141
+ let java_exec_path = std:: str:: from_utf8 ( & output. stdout ) ?
142
+ // Windows will return multiple lines if there are multiple `java` in the PATH.
143
+ . lines ( )
144
+ // The first line is the one that would be run, so take just that line.
145
+ . next ( )
146
+ . unwrap ( )
147
+ . trim ( ) ;
148
+
149
+ if java_exec_path. is_empty ( ) {
150
+ return Err ( JavaLocatorError :: new (
151
+ "Java is not installed or not in the system PATH" . into ( ) ,
152
+ ) ) ;
153
+ }
154
+
155
+ let mut home_path = follow_symlinks ( java_exec_path) ;
156
+
157
+ // Here we should have found ourselves in a directory like /usr/lib/jvm/java-8-oracle/jre/bin/java
158
+ home_path. pop ( ) ;
159
+ home_path. pop ( ) ;
160
+
161
+ home_path
162
+ . into_os_string ( )
163
+ . into_string ( )
164
+ . map_err ( |path| JavaLocatorError :: new ( format ! ( "Java path {path:?} is invalid utf8" ) ) )
165
+ }
166
+
167
+ #[ cfg( target_os = "macos" ) ]
168
+ fn do_locate_java_home ( ) -> Result < String > {
169
+ let output = Command :: new ( "/usr/libexec/java_home" )
170
+ . output ( )
171
+ . map_err ( |e| {
172
+ JavaLocatorError :: new ( format ! (
173
+ "Failed to run command `/usr/libexec/java_home` ({e})"
174
+ ) )
175
+ } ) ?;
180
176
181
- let mut command = Command :: new ( command_str ) ;
177
+ let java_exec_path = std :: str :: from_utf8 ( & output . stdout ) ? . trim ( ) ;
182
178
183
- if !is_macos ( ) {
184
- command. arg ( "java" ) ;
179
+ if java_exec_path. is_empty ( ) {
180
+ return Err ( JavaLocatorError :: new (
181
+ "Java is not installed or not in the system PATH" . into ( ) ,
182
+ ) ) ;
185
183
}
186
184
187
- let output = command. output ( ) . map_err ( |error| {
188
- let message = format ! (
189
- "Command '{}' is not found in the system PATH ({})" ,
190
- command_str, error
191
- ) ;
192
- errors:: JavaLocatorError :: new ( & message)
193
- } ) ?;
194
- let java_exec_path = String :: from_utf8 ( output. stdout ) . map ( |jp| {
195
- let mut lines: Vec < & str > = jp. lines ( ) . collect ( ) ;
196
- if lines. len ( ) > 1 {
197
- println ! (
198
- "WARNING: java_locator found {} possible java locations: {}. Using the last one." ,
199
- lines. len( ) ,
200
- lines. join( ", " )
201
- ) ;
202
- lines. remove ( lines. len ( ) - 1 ) . to_string ( )
203
- } else {
204
- jp
205
- }
206
- } ) ?;
185
+ let home_path = follow_symlinks ( java_exec_path) ;
186
+
187
+ home_path
188
+ . into_os_string ( )
189
+ . into_string ( )
190
+ . map_err ( |path| JavaLocatorError :: new ( format ! ( "Java path {path:?} is invalid utf8" ) ) )
191
+ }
192
+
193
+ // TODO: double check this
194
+ #[ cfg( not( any( target_os = "windows" , target_os = "macos" ) ) ) ] // Unix
195
+ fn do_locate_java_home ( ) -> Result < String > {
196
+ let output = Command :: new ( "which" )
197
+ . arg ( "java" )
198
+ . output ( )
199
+ . map_err ( |e| JavaLocatorError :: new ( format ! ( "Failed to run command `which` ({e})" ) ) ) ?;
200
+ let java_exec_path = std:: str:: from_utf8 ( & output. stdout ) ?. trim ( ) ;
207
201
208
- // Return early in case that the java executable is not found
209
202
if java_exec_path. is_empty ( ) {
210
- Err ( errors :: JavaLocatorError :: new (
211
- "Java is not installed or not added in the system PATH" ,
212
- ) ) ?
203
+ return Err ( JavaLocatorError :: new (
204
+ "Java is not installed or not in the system PATH" . into ( ) ,
205
+ ) ) ;
213
206
}
214
207
215
- let mut test_path = PathBuf :: from ( java_exec_path. trim ( ) ) ;
208
+ let mut home_path = follow_symlinks ( java_exec_path) ;
209
+
210
+ // Here we should have found ourselves in a directory like /usr/lib/jvm/java-8-oracle/jre/bin/java
211
+ home_path. pop ( ) ;
212
+ home_path. pop ( ) ;
213
+
214
+ home_path
215
+ . into_os_string ( )
216
+ . into_string ( )
217
+ . map_err ( |path| JavaLocatorError :: new ( format ! ( "Java path {path:?} is invalid utf8" ) ) )
218
+ }
216
219
220
+ // Its not clear to me which systems need this so for now its run on all systems.
221
+ fn follow_symlinks ( path : & str ) -> PathBuf {
222
+ let mut test_path = PathBuf :: from ( path) ;
217
223
while let Ok ( path) = test_path. read_link ( ) {
218
224
test_path = if path. is_absolute ( ) {
219
225
path
@@ -223,55 +229,40 @@ fn do_locate_java_home() -> errors::Result<String> {
223
229
test_path
224
230
} ;
225
231
}
226
-
227
- if !is_macos ( ) {
228
- // Here we should have found ourselves in a directory like /usr/lib/jvm/java-8-oracle/jre/bin/java
229
- test_path. pop ( ) ;
230
- test_path. pop ( ) ;
231
- }
232
-
233
- match test_path. to_str ( ) {
234
- Some ( s) => Ok ( String :: from ( s) ) ,
235
- None => Err ( errors:: JavaLocatorError :: new ( & format ! (
236
- "Could not convert path {:?} to String" ,
237
- test_path
238
- ) ) ) ,
239
- }
232
+ test_path
240
233
}
241
234
242
235
/// Returns the path that contains the `libjvm.so` (or `jvm.dll` in windows).
243
- pub fn locate_jvm_dyn_library ( ) -> errors:: Result < String > {
244
- let jvm_dyn_lib_file_name = if is_windows ( ) { "jvm.dll" } else { "libjvm.*" } ;
236
+ pub fn locate_jvm_dyn_library ( ) -> Result < String > {
237
+ #[ cfg( target_os = "windows" ) ]
238
+ let jvm_dyn_lib_file_name = "jvm.dll" ;
239
+ #[ cfg( not( target_os = "windows" ) ) ]
240
+ let jvm_dyn_lib_file_name = "libjvm.*" ;
245
241
246
242
locate_file ( jvm_dyn_lib_file_name)
247
243
}
248
244
249
245
/// Returns the path that contains the file with the provided name.
250
246
///
251
247
/// This function argument can be a wildcard.
252
- pub fn locate_file ( file_name : & str ) -> errors :: Result < String > {
248
+ pub fn locate_file ( file_name : & str ) -> Result < String > {
253
249
// Find the JAVA_HOME
254
250
let java_home = locate_java_home ( ) ?;
255
251
256
252
let query = format ! ( "{}/**/{}" , Pattern :: escape( & java_home) , file_name) ;
257
253
258
- let paths_vec: Vec < String > = glob ( & query) ?
259
- . filter_map ( Result :: ok)
260
- . map ( |path_buf| {
261
- let mut pb = path_buf. clone ( ) ;
262
- pb. pop ( ) ;
263
- pb. to_str ( ) . unwrap_or ( "" ) . to_string ( )
264
- } )
265
- . filter ( |s : & String | !s. is_empty ( ) )
266
- . collect ( ) ;
267
-
268
- if paths_vec. is_empty ( ) {
269
- Err ( errors:: JavaLocatorError :: new ( & format ! (
270
- "Could not find the {} library in any subdirectory of {}" ,
271
- file_name, java_home
272
- ) ) )
273
- } else {
274
- Ok ( paths_vec[ 0 ] . clone ( ) )
254
+ let path = glob ( & query) ?. filter_map ( |x| x. ok ( ) ) . next ( ) . ok_or_else ( || {
255
+ JavaLocatorError :: new ( format ! (
256
+ "Could not find the {file_name} library in any subdirectory of {java_home}" ,
257
+ ) )
258
+ } ) ?;
259
+
260
+ let parent_path = path. parent ( ) . unwrap ( ) ;
261
+ match parent_path. to_str ( ) {
262
+ Some ( parent_path) => Ok ( parent_path. to_owned ( ) ) ,
263
+ None => Err ( JavaLocatorError :: new ( format ! (
264
+ "Java path {parent_path:?} is invalid utf8"
265
+ ) ) ) ,
275
266
}
276
267
}
277
268
0 commit comments