Skip to content

Commit 8b621e0

Browse files
committed
Resolve non-abs/rel exec paths wrt. to PATH
1 parent 7282f3e commit 8b621e0

File tree

1 file changed

+65
-2
lines changed

1 file changed

+65
-2
lines changed

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

Lines changed: 65 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;
@@ -356,16 +357,78 @@ private static String getLauncherExecName() {
356357
if (ImageInfo.inImageCode()) {
357358
String binPathName = null;
358359
if (ProcessProperties.getArgumentVectorBlockSize() > 0) {
359-
binPathName = ProcessProperties.getArgumentVectorProgramName();
360+
binPathName = calculateProgramFullPath(ProcessProperties.getArgumentVectorProgramName());
360361
}
361362
if (binPathName != null) {
362-
return Paths.get(binPathName).toAbsolutePath().toString();
363+
return binPathName;
363364
}
364365
return ProcessProperties.getExecutableName();
365366
}
366367
return GraalPythonMain.BASH_LAUNCHER_EXEC_NAME;
367368
}
368369

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+
369432
private String[] getExecutableList() {
370433
String launcherExecName = getLauncherExecName();
371434
if (launcherExecName != null) {

0 commit comments

Comments
 (0)