Skip to content

Commit b25271b

Browse files
committed
Use truffle resource api when getLanguageHome cannot find valid home
1 parent 17147e2 commit b25271b

File tree

5 files changed

+300
-72
lines changed

5 files changed

+300
-72
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
interactive = true, internal = false, //
147147
contextPolicy = TruffleLanguage.ContextPolicy.SHARED, //
148148
fileTypeDetectors = PythonFileDetector.class, //
149+
internalResources = PythonResource.class, //
149150
website = "https://www.graalvm.org/python/")
150151
@ProvidedTags({
151152
StandardTags.CallTag.class,
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python;
42+
43+
import java.io.IOException;
44+
import java.nio.file.InvalidPathException;
45+
import java.nio.file.Path;
46+
import java.util.List;
47+
48+
import com.oracle.truffle.api.CompilerDirectives;
49+
import com.oracle.truffle.api.InternalResource;
50+
import com.oracle.truffle.api.InternalResource.Id;
51+
52+
/**
53+
* This code needs to be kept in sync somehow with the suite.py code. In particular, the layouts
54+
* produced by the unpacking logic in {@link #unpackFiles} should produce the same layout as the
55+
* GRAALPYTHON_GRAALVM_SUPPORT distribution in the suite.py.
56+
*/
57+
@Id("python-home")
58+
public final class PythonResource implements InternalResource {
59+
private static final Path BASE_PATH = Path.of("META-INF", "resources");
60+
private static final String LIBGRAALPY = "libgraalpy";
61+
private static final String LIBPYTHON = "libpython";
62+
private static final String LIBGRAALPY_FILES = LIBGRAALPY + ".files";
63+
private static final String LIBPYTHON_FILES = LIBPYTHON + ".files";
64+
private static final String INCLUDE_FILES = "include.files";
65+
private static final String NATIVE_FILES = "native.files";
66+
private static final Path LIBGRAALPY_SHA256 = Path.of(LIBGRAALPY + ".sha256");
67+
private static final Path LIBPYTHON_SHA256 = Path.of(LIBPYTHON + ".sha256");
68+
private static final Path INCLUDE_SHA256 = Path.of("include.sha256");
69+
private static final Path NATIVE_SHA256 = Path.of("native.sha256");
70+
71+
@Override
72+
public void unpackFiles(Env env, Path targetDirectory) throws IOException {
73+
OS os = env.getOS();
74+
Path osArch = Path.of(os.toString()).resolve(env.getCPUArchitecture().toString());
75+
if (os.equals(OS.WINDOWS)) {
76+
env.unpackResourceFiles(BASE_PATH.resolve(LIBPYTHON_FILES), targetDirectory.resolve("Lib"), BASE_PATH.resolve(LIBPYTHON));
77+
env.unpackResourceFiles(BASE_PATH.resolve(LIBGRAALPY_FILES), targetDirectory.resolve("lib-graalpython"), BASE_PATH.resolve(LIBGRAALPY));
78+
} else {
79+
env.unpackResourceFiles(BASE_PATH.resolve(LIBPYTHON_FILES), targetDirectory.resolve("lib").resolve("python" + PythonLanguage.MAJOR + "." + PythonLanguage.MINOR), BASE_PATH.resolve(LIBPYTHON));
80+
env.unpackResourceFiles(BASE_PATH.resolve(LIBGRAALPY_FILES), targetDirectory.resolve("lib").resolve("graalpy" + PythonLanguage.GRAALVM_MAJOR + "." + PythonLanguage.GRAALVM_MINOR), BASE_PATH.resolve(LIBGRAALPY));
81+
}
82+
// include files are in the same place on all platforms
83+
env.unpackResourceFiles(BASE_PATH.resolve(INCLUDE_FILES), targetDirectory, BASE_PATH);
84+
// native files already have the correct structure
85+
env.unpackResourceFiles(BASE_PATH.resolve(osArch).resolve(NATIVE_FILES), targetDirectory, BASE_PATH.resolve(osArch));
86+
}
87+
88+
@Override
89+
public String versionHash(Env env) {
90+
StringBuilder sb = new StringBuilder();
91+
for (var s : List.of(LIBGRAALPY_SHA256, LIBPYTHON_SHA256, INCLUDE_SHA256, Path.of(env.getOS().toString()).resolve(env.getCPUArchitecture().toString()).resolve(NATIVE_SHA256))) {
92+
try {
93+
sb.append(env.readResourceLines(BASE_PATH.resolve(s)).get(0).substring(0, 8));
94+
} catch (IOException | IndexOutOfBoundsException | InvalidPathException e) {
95+
throw CompilerDirectives.shouldNotReachHere(e);
96+
}
97+
}
98+
return sb.toString();
99+
}
100+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public void postInitialize(Python3Core core) {
226226
PythonModule mod = core.lookupBuiltinModule(T___GRAALPYTHON__);
227227
PythonLanguage language = context.getLanguage();
228228
if (!ImageInfo.inImageBuildtimeCode()) {
229-
mod.setAttribute(tsLiteral("home"), toTruffleStringUncached(language.getHome()));
229+
mod.setAttribute(tsLiteral("home"), context.getLanguageHome());
230230
}
231231
mod.setAttribute(tsLiteral("in_image_buildtime"), ImageInfo.inImageBuildtimeCode());
232232
mod.setAttribute(tsLiteral("in_image"), ImageInfo.inImageCode());

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
import org.graalvm.options.OptionKey;
9999

100100
import com.oracle.graal.python.PythonLanguage;
101+
import com.oracle.graal.python.PythonResource;
101102
import com.oracle.graal.python.builtins.Python3Core;
102103
import com.oracle.graal.python.builtins.PythonOS;
103104
import com.oracle.graal.python.builtins.modules.ImpModuleBuiltins;
@@ -1678,7 +1679,7 @@ private void initializePosixSupport() {
16781679
}
16791680
}
16801681

1681-
private TruffleString sysPrefix, basePrefix, coreHome, capiHome, jniHome, stdLibHome;
1682+
private TruffleString langHome, sysPrefix, basePrefix, coreHome, capiHome, jniHome, stdLibHome;
16821683

16831684
public void initializeHomeAndPrefixPaths(Env newEnv, String languageHome) {
16841685
sysPrefix = newEnv.getOptions().get(PythonOptions.SysPrefix);
@@ -1721,25 +1722,44 @@ public void initializeHomeAndPrefixPaths(Env newEnv, String languageHome) {
17211722
home = null;
17221723
}
17231724

1724-
if (home != null) {
1725+
Supplier<?>[] homeCandidates = new Supplier<?>[] {
1726+
() -> { return home; },
1727+
() -> {
1728+
try {
1729+
return newEnv.getInternalResource(PythonResource.class).getAbsoluteFile();
1730+
} catch (IOException e) {
1731+
return null;
1732+
}
1733+
}
1734+
};
1735+
for (Supplier<?> homeCandidateSupplier : homeCandidates) {
1736+
final TruffleFile homeCandidate = (TruffleFile) homeCandidateSupplier.get();
1737+
if (homeCandidate == null) {
1738+
continue;
1739+
}
1740+
boolean homeSeemsValid = !coreHome.isEmpty() && !stdLibHome.isEmpty();
1741+
1742+
langHome = toTruffleStringUncached(homeCandidate.toString());
17251743
if (sysPrefix.isEmpty()) {
1726-
sysPrefix = toTruffleStringUncached(home.getAbsoluteFile().getPath());
1744+
sysPrefix = toTruffleStringUncached(homeCandidate.getAbsoluteFile().getPath());
17271745
}
17281746

17291747
if (basePrefix.isEmpty()) {
1730-
basePrefix = toTruffleStringUncached(home.getAbsoluteFile().getPath());
1748+
basePrefix = toTruffleStringUncached(homeCandidate.getAbsoluteFile().getPath());
17311749
}
17321750

17331751
if (coreHome.isEmpty()) {
17341752
try {
1735-
outer: for (TruffleFile f : home.list()) {
1753+
outer: for (TruffleFile f : homeCandidate.list()) {
17361754
if (f.getName().equals("lib-graalpython") && f.isDirectory()) {
17371755
coreHome = toTruffleStringUncached(f.getPath());
1756+
homeSeemsValid = true;
17381757
break;
17391758
} else if (f.getName().equals("lib") && f.isDirectory()) {
17401759
for (TruffleFile f2 : f.list()) {
17411760
if (f2.getName().equals("graalpy" + PythonLanguage.GRAALVM_MAJOR + "." + PythonLanguage.GRAALVM_MINOR) && f.isDirectory()) {
17421761
coreHome = toTruffleStringUncached(f2.getPath());
1762+
homeSeemsValid = true;
17431763
break outer;
17441764
}
17451765
}
@@ -1752,7 +1772,7 @@ public void initializeHomeAndPrefixPaths(Env newEnv, String languageHome) {
17521772
if (stdLibHome.isEmpty()) {
17531773
// try stdlib layouts per sysconfig or our sources
17541774
try {
1755-
outer: for (TruffleFile f : home.list()) {
1775+
outer: for (TruffleFile f : homeCandidate.list()) {
17561776
if (getPythonOS() == PLATFORM_WIN32 && (f.getName().equals("Lib") || f.getName().equals("lib")) && f.isDirectory()) {
17571777
// nt stdlib layout
17581778
stdLibHome = toTruffleStringUncached(f.getPath());
@@ -1761,6 +1781,7 @@ public void initializeHomeAndPrefixPaths(Env newEnv, String languageHome) {
17611781
for (TruffleFile f2 : f.list()) {
17621782
if (f2.getName().equals("python" + PythonLanguage.MAJOR + "." + PythonLanguage.MINOR) && f.isDirectory()) {
17631783
stdLibHome = toTruffleStringUncached(f2.getPath());
1784+
homeSeemsValid = true;
17641785
break outer;
17651786
}
17661787
}
@@ -1769,6 +1790,7 @@ public void initializeHomeAndPrefixPaths(Env newEnv, String languageHome) {
17691790
for (TruffleFile f2 : f.list()) {
17701791
if (f2.getName().equals("3") && f.isDirectory()) {
17711792
stdLibHome = toTruffleStringUncached(f2.getPath());
1793+
homeSeemsValid = true;
17721794
break outer;
17731795
}
17741796
}
@@ -1785,6 +1807,18 @@ public void initializeHomeAndPrefixPaths(Env newEnv, String languageHome) {
17851807
if (jniHome.isEmpty()) {
17861808
jniHome = coreHome;
17871809
}
1810+
1811+
if (homeSeemsValid) {
1812+
break;
1813+
} else {
1814+
// reset values
1815+
sysPrefix = newEnv.getOptions().get(PythonOptions.SysPrefix);
1816+
basePrefix = newEnv.getOptions().get(PythonOptions.SysBasePrefix);
1817+
coreHome = newEnv.getOptions().get(PythonOptions.CoreHome);
1818+
stdLibHome = newEnv.getOptions().get(PythonOptions.StdLibHome);
1819+
capiHome = newEnv.getOptions().get(PythonOptions.CAPI);
1820+
jniHome = newEnv.getOptions().get(PythonOptions.JNIHome);
1821+
}
17881822
}
17891823

17901824
if (ImageInfo.inImageBuildtimeCode()) {
@@ -1810,10 +1844,18 @@ public void initializeHomeAndPrefixPaths(Env newEnv, String languageHome) {
18101844
"\n\tStdLibHome: {4}" +
18111845
"\n\tExecutable: {5}" +
18121846
"\n\tCAPI: {6}" +
1813-
"\n\tJNI library: {7}", home != null ? home.getPath() : "", sysPrefix, basePrefix, coreHome, stdLibHome, newEnv.getOptions().get(PythonOptions.Executable), capiHome,
1847+
"\n\tJNI library: {7}", langHome, sysPrefix, basePrefix, coreHome, stdLibHome, newEnv.getOptions().get(PythonOptions.Executable), capiHome,
18141848
jniHome));
18151849
}
18161850

1851+
@TruffleBoundary
1852+
public TruffleString getLanguageHome() {
1853+
if (langHome == null || langHome.isEmpty()) {
1854+
langHome = T_PREFIX;
1855+
}
1856+
return langHome;
1857+
}
1858+
18171859
@TruffleBoundary
18181860
public TruffleString getSysPrefix() {
18191861
if (sysPrefix.isEmpty()) {
@@ -1826,13 +1868,7 @@ public TruffleString getSysPrefix() {
18261868
@TruffleBoundary
18271869
public TruffleString getSysBasePrefix() {
18281870
if (basePrefix.isEmpty()) {
1829-
String homePrefix = getLanguage().getHome();
1830-
if (homePrefix == null || homePrefix.isEmpty()) {
1831-
basePrefix = T_PREFIX;
1832-
} else {
1833-
basePrefix = toTruffleStringUncached(homePrefix);
1834-
}
1835-
1871+
basePrefix = getLanguageHome();
18361872
}
18371873
return basePrefix;
18381874
}
@@ -2294,15 +2330,13 @@ private static boolean hasAllowedSuffix(TruffleString path, TruffleString[] allo
22942330
@TruffleBoundary
22952331
public boolean isPyFileInLanguageHome(TruffleFile path) {
22962332
assert !ImageInfo.inImageBuildtimeCode() : "language home won't be available during image build time";
2297-
String languageHome = getLanguage().getHome();
2298-
22992333
// The language home may be 'null' if an embedder uses Python. In this case, IO must just be
23002334
// allowed.
2301-
if (languageHome != null) {
2335+
if (langHome != null) {
23022336
// This deliberately uses 'getAbsoluteFile' and not 'getCanonicalFile' because if, e.g.,
23032337
// 'path' is a symlink outside of the language home, the user should not be able to read
23042338
// the symlink if 'allowIO' is false.
2305-
TruffleFile coreHomePath = env.getInternalTruffleFile(languageHome).getAbsoluteFile();
2339+
TruffleFile coreHomePath = getEnv().getInternalTruffleFile(langHome.toJavaStringUncached()).getAbsoluteFile();
23062340
TruffleFile absolutePath = path.getAbsoluteFile();
23072341
return absolutePath.startsWith(coreHomePath);
23082342
}

0 commit comments

Comments
 (0)