@@ -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,9 +104,9 @@ 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
+ if cfg ! ( target_os = "windows" ) {
150
108
"jvm.dll"
151
- } else if is_macos ( ) {
109
+ } else if cfg ! ( target_os = "macos" ) {
152
110
"libjvm.dylib"
153
111
} else {
154
112
"libjvm.so"
@@ -160,60 +118,102 @@ pub fn get_jvm_dyn_lib_file_name() -> &'static str {
160
118
/// 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
119
///
162
120
/// 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 > {
121
+ pub fn locate_java_home ( ) -> Result < String > {
164
122
match & env:: var ( "JAVA_HOME" ) {
165
123
Ok ( s) if s. is_empty ( ) => do_locate_java_home ( ) ,
166
124
Ok ( java_home_env_var) => Ok ( java_home_env_var. clone ( ) ) ,
167
125
Err ( _) => do_locate_java_home ( ) ,
168
126
}
169
127
}
170
128
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
- } ;
129
+ #[ cfg( target_os = "windows" ) ]
130
+ fn do_locate_java_home ( ) -> Result < String > {
131
+ let output = Command :: new ( "where" )
132
+ . arg ( "java" )
133
+ . output ( )
134
+ . map_err ( |e| JavaLocatorError :: new ( format ! ( "Failed to run command `where` ({e})" ) ) ) ?;
180
135
181
- let mut command = Command :: new ( command_str) ;
136
+ let java_exec_path_raw = std:: str:: from_utf8 ( & output. stdout ) ?;
137
+ java_exec_path_validation ( java_exec_path_raw) ?;
182
138
183
- if !is_macos ( ) {
184
- command. arg ( "java" ) ;
139
+ // Windows will return multiple lines if there are multiple `java` in the PATH.
140
+ let paths_found = java_exec_path_raw. lines ( ) . count ( ) ;
141
+ if paths_found > 1 {
142
+ eprintln ! ( "WARNING: java_locator found {paths_found} possible java locations. Using the first one. To silence this warning set JAVA_HOME env var." )
185
143
}
186
144
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
- } ) ?;
145
+ let java_exec_path = java_exec_path_raw
146
+ . lines ( )
147
+ // The first line is the one that would be run, so take just that line.
148
+ . next ( )
149
+ . expect ( "gauranteed to have at least one line by java_exec_path_validation" )
150
+ . trim ( ) ;
151
+
152
+ let mut home_path = follow_symlinks ( java_exec_path) ;
153
+
154
+ home_path. pop ( ) ;
155
+ home_path. pop ( ) ;
156
+
157
+ home_path
158
+ . into_os_string ( )
159
+ . into_string ( )
160
+ . map_err ( |path| JavaLocatorError :: new ( format ! ( "Java path {path:?} is invalid utf8" ) ) )
161
+ }
207
162
208
- // Return early in case that the java executable is not found
209
- if java_exec_path. is_empty ( ) {
210
- Err ( errors:: JavaLocatorError :: new (
211
- "Java is not installed or not added in the system PATH" ,
212
- ) ) ?
163
+ #[ cfg( target_os = "macos" ) ]
164
+ fn do_locate_java_home ( ) -> Result < String > {
165
+ let output = Command :: new ( "/usr/libexec/java_home" )
166
+ . output ( )
167
+ . map_err ( |e| {
168
+ JavaLocatorError :: new ( format ! (
169
+ "Failed to run command `/usr/libexec/java_home` ({e})"
170
+ ) )
171
+ } ) ?;
172
+
173
+ let java_exec_path = std:: str:: from_utf8 ( & output. stdout ) ?. trim ( ) ;
174
+
175
+ java_exec_path_validation ( java_exec_path) ?;
176
+ let home_path = follow_symlinks ( java_exec_path) ;
177
+
178
+ home_path
179
+ . into_os_string ( )
180
+ . into_string ( )
181
+ . map_err ( |path| JavaLocatorError :: new ( format ! ( "Java path {path:?} is invalid utf8" ) ) )
182
+ }
183
+
184
+ #[ cfg( not( any( target_os = "windows" , target_os = "macos" ) ) ) ] // Unix
185
+ fn do_locate_java_home ( ) -> Result < String > {
186
+ let output = Command :: new ( "which" )
187
+ . arg ( "java" )
188
+ . output ( )
189
+ . map_err ( |e| JavaLocatorError :: new ( format ! ( "Failed to run command `which` ({e})" ) ) ) ?;
190
+ let java_exec_path = std:: str:: from_utf8 ( & output. stdout ) ?. trim ( ) ;
191
+
192
+ java_exec_path_validation ( java_exec_path) ?;
193
+ let mut home_path = follow_symlinks ( java_exec_path) ;
194
+
195
+ // Here we should have found ourselves in a directory like /usr/lib/jvm/java-8-oracle/jre/bin/java
196
+ home_path. pop ( ) ;
197
+ home_path. pop ( ) ;
198
+
199
+ home_path
200
+ . into_os_string ( )
201
+ . into_string ( )
202
+ . map_err ( |path| JavaLocatorError :: new ( format ! ( "Java path {path:?} is invalid utf8" ) ) )
203
+ }
204
+
205
+ fn java_exec_path_validation ( path : & str ) -> Result < ( ) > {
206
+ if path. is_empty ( ) {
207
+ return Err ( JavaLocatorError :: new (
208
+ "Java is not installed or not in the system PATH" . into ( ) ,
209
+ ) ) ;
213
210
}
214
211
215
- let mut test_path = PathBuf :: from ( java_exec_path. trim ( ) ) ;
212
+ Ok ( ( ) )
213
+ }
216
214
215
+ fn follow_symlinks ( path : & str ) -> PathBuf {
216
+ let mut test_path = PathBuf :: from ( path) ;
217
217
while let Ok ( path) = test_path. read_link ( ) {
218
218
test_path = if path. is_absolute ( ) {
219
219
path
@@ -223,55 +223,39 @@ fn do_locate_java_home() -> errors::Result<String> {
223
223
test_path
224
224
} ;
225
225
}
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
- }
226
+ test_path
240
227
}
241
228
242
229
/// 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.*" } ;
245
-
246
- locate_file ( jvm_dyn_lib_file_name)
230
+ pub fn locate_jvm_dyn_library ( ) -> Result < String > {
231
+ if cfg ! ( target_os = "windows" ) {
232
+ locate_file ( "jvm.dll" )
233
+ } else {
234
+ locate_file ( "libjvm.*" )
235
+ }
247
236
}
248
237
249
238
/// Returns the path that contains the file with the provided name.
250
239
///
251
240
/// This function argument can be a wildcard.
252
- pub fn locate_file ( file_name : & str ) -> errors :: Result < String > {
241
+ pub fn locate_file ( file_name : & str ) -> Result < String > {
253
242
// Find the JAVA_HOME
254
243
let java_home = locate_java_home ( ) ?;
255
244
256
245
let query = format ! ( "{}/**/{}" , Pattern :: escape( & java_home) , file_name) ;
257
246
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 ( ) )
247
+ let path = glob ( & query) ?. filter_map ( |x| x. ok ( ) ) . next ( ) . ok_or_else ( || {
248
+ JavaLocatorError :: new ( format ! (
249
+ "Could not find the {file_name} library in any subdirectory of {java_home}" ,
250
+ ) )
251
+ } ) ?;
252
+
253
+ let parent_path = path. parent ( ) . unwrap ( ) ;
254
+ match parent_path. to_str ( ) {
255
+ Some ( parent_path) => Ok ( parent_path. to_owned ( ) ) ,
256
+ None => Err ( JavaLocatorError :: new ( format ! (
257
+ "Java path {parent_path:?} is invalid utf8"
258
+ ) ) ) ,
275
259
}
276
260
}
277
261
0 commit comments