Skip to content

Commit ea37e87

Browse files
committed
[GR-29087] Resolve launcher exec name to absolute path.
PullRequest: graalpython/1583
2 parents e09efe1 + 8b621e0 commit ea37e87

File tree

1 file changed

+68
-2
lines changed

1 file changed

+68
-2
lines changed

graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.lang.management.ManagementFactory;
3636
import java.nio.file.Files;
3737
import java.nio.file.NoSuchFileException;
38+
import java.nio.file.Path;
3839
import java.nio.file.Paths;
3940
import java.util.ArrayList;
4041
import java.util.HashMap;
@@ -357,13 +358,78 @@ private static String getLauncherExecName() {
357358
if (ImageInfo.inImageCode()) {
358359
String binPathName = null;
359360
if (ProcessProperties.getArgumentVectorBlockSize() > 0) {
360-
binPathName = ProcessProperties.getArgumentVectorProgramName();
361+
binPathName = calculateProgramFullPath(ProcessProperties.getArgumentVectorProgramName());
361362
}
362-
return binPathName != null ? binPathName : ProcessProperties.getExecutableName();
363+
if (binPathName != null) {
364+
return binPathName;
365+
}
366+
return ProcessProperties.getExecutableName();
363367
}
364368
return GraalPythonMain.BASH_LAUNCHER_EXEC_NAME;
365369
}
366370

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

0 commit comments

Comments
 (0)