|
35 | 35 | import java.lang.management.ManagementFactory;
|
36 | 36 | import java.nio.file.Files;
|
37 | 37 | import java.nio.file.NoSuchFileException;
|
| 38 | +import java.nio.file.Path; |
38 | 39 | import java.nio.file.Paths;
|
39 | 40 | import java.util.ArrayList;
|
40 | 41 | import java.util.HashMap;
|
@@ -356,16 +357,78 @@ private static String getLauncherExecName() {
|
356 | 357 | if (ImageInfo.inImageCode()) {
|
357 | 358 | String binPathName = null;
|
358 | 359 | if (ProcessProperties.getArgumentVectorBlockSize() > 0) {
|
359 |
| - binPathName = ProcessProperties.getArgumentVectorProgramName(); |
| 360 | + binPathName = calculateProgramFullPath(ProcessProperties.getArgumentVectorProgramName()); |
360 | 361 | }
|
361 | 362 | if (binPathName != null) {
|
362 |
| - return Paths.get(binPathName).toAbsolutePath().toString(); |
| 363 | + return binPathName; |
363 | 364 | }
|
364 | 365 | return ProcessProperties.getExecutableName();
|
365 | 366 | }
|
366 | 367 | return GraalPythonMain.BASH_LAUNCHER_EXEC_NAME;
|
367 | 368 | }
|
368 | 369 |
|
| 370 | + /** |
| 371 | + * Follows the same semantics as CPython's {@code getpath.c:calculate_program_full_path} to |
| 372 | + * determine the full program path if we just got a non-absolute program name. This method |
| 373 | + * handles the following cases: |
| 374 | + * <dl> |
| 375 | + * <dt><b>Program name is an absolute path</b></dt> |
| 376 | + * <dd>Just return {@code program}.</dd> |
| 377 | + * <dt><b>Program name is a relative path</b></dt> |
| 378 | + * <dd>it will resolve it to an absolute path. E.g. {@code "./python3"} will become {@code |
| 379 | + * "<current_working_dir>/python3"}/dd> |
| 380 | + * <dt><b>Program name is neither an absolute nor a relative path</b></dt> |
| 381 | + * <dd>It will resolve the program name wrt. to the {@code PATH} env variable. Since it may be |
| 382 | + * that the {@code PATH} variable is not available, this method will return {@code null}</dd> |
| 383 | + * </dl> |
| 384 | + * |
| 385 | + * @param program The program name as passed in the process' argument vector (position 0). |
| 386 | + * @return The absolute path to the program or {@code null}. |
| 387 | + */ |
| 388 | + private static String calculateProgramFullPath(String program) { |
| 389 | + Path programPath = Paths.get(program); |
| 390 | + |
| 391 | + // If this is an absolute path, we are already fine. |
| 392 | + if (programPath.isAbsolute()) { |
| 393 | + return program; |
| 394 | + } |
| 395 | + |
| 396 | + /* |
| 397 | + * If there is no slash in the arg[0] path, then we have to assume python is on the user's |
| 398 | + * $PATH, since there's no other way to find a directory to start the search from. If $PATH |
| 399 | + * isn't exported, you lose. |
| 400 | + */ |
| 401 | + if (programPath.getNameCount() < 2) { |
| 402 | + // Resolve the program name with respect to the PATH variable. |
| 403 | + String path = System.getenv("PATH"); |
| 404 | + if (path != null) { |
| 405 | + int last = 0; |
| 406 | + for (int i = path.indexOf(File.pathSeparatorChar); i != -1; i = path.indexOf(File.pathSeparatorChar, last)) { |
| 407 | + Path resolvedProgramName = Paths.get(path.substring(last, i)).resolve(programPath); |
| 408 | + if (Files.isExecutable(resolvedProgramName)) { |
| 409 | + return resolvedProgramName.toString(); |
| 410 | + } |
| 411 | + |
| 412 | + // next start is the char after the separator because we have "path0:path1" and |
| 413 | + // 'i' points to ':' |
| 414 | + last = i + 1; |
| 415 | + } |
| 416 | + } |
| 417 | + return null; |
| 418 | + } |
| 419 | + // It's seemingly a relative path, so we can just resolve it to an absolute one. |
| 420 | + assert !programPath.isAbsolute(); |
| 421 | + /* |
| 422 | + * Another special case (see: CPython function "getpath.c:copy_absolute"): If the program |
| 423 | + * name starts with "./" (on Unix; or similar on other systems) then the path is |
| 424 | + * canonicalized. |
| 425 | + */ |
| 426 | + if (".".equals(programPath.getName(0).toString())) { |
| 427 | + return programPath.toAbsolutePath().normalize().toString(); |
| 428 | + } |
| 429 | + return programPath.toAbsolutePath().toString(); |
| 430 | + } |
| 431 | + |
369 | 432 | private String[] getExecutableList() {
|
370 | 433 | String launcherExecName = getLauncherExecName();
|
371 | 434 | if (launcherExecName != null) {
|
|
0 commit comments