Skip to content

Commit ce7922c

Browse files
committed
[GR-44824] Support for Windows in the 'standalone' module
PullRequest: graalpython/2895
2 parents a52b465 + bc38ee2 commit ce7922c

File tree

7 files changed

+189
-95
lines changed

7 files changed

+189
-95
lines changed

ci.jsonnet

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{ "overlay": "2f40099575fdfd627c05c67783b13efad0e15980" }
1+
{ "overlay": "722a2918fe02527be69d3a59e042ef76d6f8333c" }

graalpython/com.oracle.graal.python.test/src/tests/test_standalone.py

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,11 @@
4141
import subprocess
4242
import tempfile
4343
import unittest
44+
import shutil
45+
import glob
4446

4547
is_enabled = 'ENABLE_STANDALONE_UNITTESTS' in os.environ and os.environ['ENABLE_STANDALONE_UNITTESTS'] == "true"
48+
MVN = shutil.which('mvn')
4649

4750
def get_executable(file):
4851
if os.path.isfile(file):
@@ -75,12 +78,25 @@ def get_gp():
7578
sep="\n",
7679
)
7780
assert False
81+
82+
print("Running tests for standalone module:")
83+
print(" __graalpython__.home:", __graalpython__.home)
84+
print(" java_home:", java_home)
85+
print(" graalpy:", graalpy)
86+
print(" java:", java)
87+
7888
return java_home, graalpy, java
7989

8090
def get_env(java_home):
8191
env = os.environ.copy()
8292
env.update({"JAVA_HOME" : java_home})
8393

94+
graalvm_home = os.environ.get("GRAALVM_HOME", java_home)
95+
if "*" in graalvm_home:
96+
graalvm_home = os.path.abspath(glob.glob(graalvm_home)[0])
97+
print("Patching GRAALVM_HOME: ", graalvm_home)
98+
env.update({"GRAALVM_HOME" : graalvm_home})
99+
84100
to_be_removed = []
85101
for k in env:
86102
# subprocess complaining about key names with "=" in them
@@ -93,7 +109,7 @@ def get_env(java_home):
93109

94110
return env
95111

96-
@unittest.skipUnless(is_enabled)
112+
@unittest.skipUnless(is_enabled, "ENABLE_STANDALONE_UNITTESTS is not true")
97113
def test_polyglot_app():
98114

99115
java_home, graalpy, java = get_gp()
@@ -105,40 +121,40 @@ def test_polyglot_app():
105121

106122
cmd = [graalpy, "-m", "standalone", "--verbose", "polyglot_app", "-o", target_dir]
107123
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
108-
out = p.stdout.decode()
109-
print(p.stdout.decode())
110-
print(p.stderr.decode())
124+
out = p.stdout.decode(errors='backslashreplace')
125+
print(p.stdout.decode(errors='backslashreplace'))
126+
print(p.stderr.decode(errors='backslashreplace'))
111127
assert "Creating polyglot java python application in directory " + target_dir in out
112128

113-
cmd = ["mvn", "package", "-Pnative"]
129+
cmd = [MVN, "package", "-Pnative"]
114130
p = subprocess.run(cmd, cwd=target_dir, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
115-
out = p.stdout.decode()
131+
out = p.stdout.decode(errors='backslashreplace')
116132
print(out)
117-
print(p.stderr.decode())
133+
print(p.stderr.decode(errors='backslashreplace'))
118134
assert "BUILD SUCCESS" in out
119135

120136
cmd = [os.path.join(target_dir, "target", "polyglot_app")]
121137
p = subprocess.run(cmd, cwd=target_dir, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
122-
out = p.stdout.decode()
138+
out = p.stdout.decode(errors='backslashreplace')
123139
print(out)
124-
print(p.stderr.decode())
140+
print(p.stderr.decode(errors='backslashreplace'))
125141
assert out.endswith("hello java\n")
126142

127-
cmd = ["mvn", "package", "-Pjar"]
143+
cmd = [MVN, "package", "-Pjar"]
128144
p = subprocess.run(cmd, cwd=target_dir, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
129-
out = p.stdout.decode()
145+
out = p.stdout.decode(errors='backslashreplace')
130146
print(out)
131-
print(p.stderr.decode())
147+
print(p.stderr.decode(errors='backslashreplace'))
132148
assert "BUILD SUCCESS" in out
133149

134150
cmd = [java, "-jar", os.path.join(target_dir, "target", "polyglot_app-1.0-SNAPSHOT.jar")]
135151
p = subprocess.run(cmd, cwd=target_dir, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
136-
out = p.stdout.decode()
152+
out = p.stdout.decode(errors='backslashreplace')
137153
print(out)
138-
print(p.stderr.decode())
154+
print(p.stderr.decode(errors='backslashreplace'))
139155
assert out.endswith("hello java\n")
140156

141-
@unittest.skipUnless(is_enabled)
157+
@unittest.skipUnless(is_enabled, "ENABLE_STANDALONE_UNITTESTS is not true")
142158
def test_native_executable_one_file():
143159
java_home, graalpy, java = get_gp()
144160
if graalpy is None or java is None:
@@ -156,19 +172,19 @@ def test_native_executable_one_file():
156172
cmd = [graalpy, "-m", "standalone", "--verbose", "native", "-m", source_file, "-o", target_file]
157173

158174
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
159-
out = p.stdout.decode()
175+
out = p.stdout.decode(errors='backslashreplace')
160176
print(out)
161-
print(p.stderr.decode())
177+
print(p.stderr.decode(errors='backslashreplace'))
162178
assert "Bundling Python resources into" in out
163179

164180
cmd = [target_file]
165181
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
166-
out = p.stdout.decode()
182+
out = p.stdout.decode(errors='backslashreplace')
167183
print(out)
168-
print(p.stderr.decode())
184+
print(p.stderr.decode(errors='backslashreplace'))
169185
assert "hello world" in out
170186

171-
@unittest.skipUnless(is_enabled)
187+
@unittest.skipUnless(is_enabled, "ENABLE_STANDALONE_UNITTESTS is not true")
172188
def test_native_executable_one_file_venv():
173189
java_home, graalpy, java = get_gp()
174190
if graalpy is None or java is None:
@@ -186,34 +202,34 @@ def test_native_executable_one_file_venv():
186202
venv_dir = os.path.join(target_dir, "venv")
187203
cmd = [graalpy, "-m", "venv", venv_dir]
188204
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
189-
out = p.stdout.decode()
205+
out = p.stdout.decode(errors='backslashreplace')
190206
print(out)
191-
print(p.stderr.decode())
207+
print(p.stderr.decode(errors='backslashreplace'))
192208

193-
pip = os.path.join(venv_dir, "bin", "pip")
194-
cmd = [pip, "install", "termcolor"]
209+
venv_python = os.path.join(venv_dir, "Scripts", "python.cmd") if os.name == "nt" else os.path.join(venv_dir, "bin", "python")
210+
cmd = [venv_python, "-m", "pip", "--no-cache-dir", "install", "termcolor"]
195211
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
196-
out = p.stdout.decode()
212+
out = p.stdout.decode(errors='backslashreplace')
197213
print(out)
198-
print(p.stderr.decode())
214+
print(p.stderr.decode(errors='backslashreplace'))
199215

200216
target_file = os.path.join(target_dir, "hello")
201217
cmd = [graalpy, "-m", "standalone", "--verbose", "native", "-Os", "-m", source_file, "--venv", venv_dir, "-o", target_file]
202218
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
203-
out = p.stdout.decode()
219+
out = p.stdout.decode(errors='backslashreplace')
204220
print(out)
205-
print(p.stderr.decode())
221+
print(p.stderr.decode(errors='backslashreplace'))
206222
assert "Bundling Python resources into" in out
207223

208224
cmd = [target_file]
209225
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
210-
out = p.stdout.decode()
226+
out = p.stdout.decode(errors='backslashreplace')
211227
print(out)
212-
print(p.stderr.decode())
228+
print(p.stderr.decode(errors='backslashreplace'))
213229

214230
assert "hello standalone world" in out
215231

216-
@unittest.skipUnless(is_enabled)
232+
@unittest.skipUnless(is_enabled, "ENABLE_STANDALONE_UNITTESTS is not true")
217233
def test_native_executable_module():
218234
java_home, graalpy, java = get_gp()
219235
if graalpy is None or java is None:
@@ -240,14 +256,14 @@ def test_native_executable_module():
240256
cmd = [graalpy, "-m", "standalone", "--verbose", "native", "-Os", "-m", module_dir, "-o", target_file]
241257

242258
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
243-
out = p.stdout.decode()
259+
out = p.stdout.decode(errors='backslashreplace')
244260
print(out)
245-
print(p.stderr.decode())
261+
print(p.stderr.decode(errors='backslashreplace'))
246262
assert "Bundling Python resources into" in out
247263

248264
cmd = [target_file]
249265
p = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
250-
out = p.stdout.decode()
266+
out = p.stdout.decode(errors='backslashreplace')
251267
print(out)
252-
print(p.stderr.decode())
253-
assert "hello standalone world" in out
268+
print(p.stderr.decode(errors='backslashreplace'))
269+
assert "hello standalone world" in out

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,11 @@ Object list(TruffleString dirPath, TruffleString filesListPath) {
971971
List<String> ret = list(dir);
972972
String parentPathString = dir.getParent().getAbsoluteFile().getPath();
973973
for (String f : ret) {
974-
bw.write(f.substring(parentPathString.length()));
974+
String tt = f.substring(parentPathString.length());
975+
if (tt.charAt(0) == '\\') {
976+
tt = tt.replace("\\", "/");
977+
}
978+
bw.write(tt);
975979
bw.write("\n");
976980
}
977981
} catch (IOException e) {

graalpython/lib-graalpython/modules/standalone/templates/Main.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,12 @@ public class Main {
5757
private static String PYTHON = "python";
5858

5959
public static void main(String[] args) throws IOException {
60+
VirtualFileSystem vfs = new VirtualFileSystem();
6061
Builder builder = Context.newBuilder()
6162
.allowExperimentalOptions(true)
6263
.allowAllAccess(true)
6364
.allowIO(true)
64-
.fileSystem(new VirtualFileSystem())
65+
.fileSystem(vfs)
6566
.option("python.PosixModuleBackend", "java")
6667
.option("python.DontWriteBytecodeFlag", "true")
6768
.option("python.VerboseFlag", System.getenv("PYTHONVERBOSE") != null ? "true" : "false")
@@ -70,12 +71,12 @@ public static void main(String[] args) throws IOException {
7071
.option("python.AlwaysRunExcepthook", "false")
7172
.option("python.ForceImportSite", "true")
7273
.option("python.RunViaLauncher", "false")
73-
.option("python.Executable", VENV_PREFIX + "/bin/python")
74-
.option("python.InputFilePath", PROJ_PREFIX)
75-
.option("python.CheckHashPycsMode", "never");
74+
.option("python.Executable", vfs.resourcePathToPlatformPath(VENV_PREFIX) + (VirtualFileSystem.isWindows() ? "\\Scripts\\python.cmd" : "/bin/python"))
75+
.option("python.InputFilePath", vfs.resourcePathToPlatformPath(PROJ_PREFIX))
76+
.option("python.CheckHashPycsMode", "never")
77+
.option("engine.WarnInterpreterOnly", "false");
7678
if(ImageInfo.inImageRuntimeCode()) {
77-
builder.option("engine.WarnInterpreterOnly", "false")
78-
.option("python.PythonHome", HOME_PREFIX);
79+
builder.option("python.PythonHome", vfs.resourcePathToPlatformPath(HOME_PREFIX));
7980
}
8081
Context context = builder.build();
8182

@@ -99,6 +100,5 @@ public static void main(String[] args) throws IOException {
99100
}
100101
}
101102
}
102-
103-
103+
104104
}

graalpython/lib-graalpython/modules/standalone/templates/Py2BinLauncher.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ public class Py2BinLauncher {
8484
private static final String PROJ_PREFIX = "/{vfs-proj-prefix}";
8585

8686
public static void main(String[] args) throws IOException {
87+
VirtualFileSystem vfs = new VirtualFileSystem();
8788
var builder = Context.newBuilder()
8889
.allowExperimentalOptions(true)
8990
.allowAllAccess(true)
9091
.allowIO(true)
91-
.fileSystem(new VirtualFileSystem())
92+
.fileSystem(vfs)
9293
.option("python.PosixModuleBackend", "java")
9394
.option("python.NativeModules", "")
9495
.option("python.DontWriteBytecodeFlag", "true")
@@ -98,9 +99,9 @@ public static void main(String[] args) throws IOException {
9899
.option("python.AlwaysRunExcepthook", "true")
99100
.option("python.ForceImportSite", "true")
100101
.option("python.RunViaLauncher", "true")
101-
.option("python.Executable", VENV_PREFIX + "/bin/python")
102-
.option("python.InputFilePath", PROJ_PREFIX)
103-
.option("python.PythonHome", HOME_PREFIX)
102+
.option("python.Executable", vfs.resourcePathToPlatformPath(VENV_PREFIX) + (VirtualFileSystem.isWindows() ? "\\Scripts\\python.cmd" : "/bin/python"))
103+
.option("python.InputFilePath", vfs.resourcePathToPlatformPath(PROJ_PREFIX))
104+
.option("python.PythonHome", vfs.resourcePathToPlatformPath(HOME_PREFIX))
104105
.option("python.CheckHashPycsMode", "never");
105106
if(ImageInfo.inImageRuntimeCode()) {
106107
builder.option("engine.WarnInterpreterOnly", "false");

0 commit comments

Comments
 (0)