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