Files
NeitzelFXDesigner/scripts/check-library-example.py
T

85 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""Exercise a clean copy of NeitzelLib's actual fx-example in the packaged standalone host."""
import argparse
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import time
import zipfile
from native_crashes import NativeCrashGuard
ROOT = Path(__file__).resolve().parent.parent
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--library", type=Path, required=True)
parser.add_argument("--app", type=Path, required=True)
parser.add_argument("--java-home", type=Path, required=True,
help="JDK 25 for the external test agent compiler")
parser.add_argument("--target-java-home", type=Path, required=True)
args = parser.parse_args()
output = Path(tempfile.mkdtemp(prefix="designer-library-example-")).resolve()
print("Evidence: " + str(output), flush=True)
library = output / "NeitzelLib"
shutil.copytree(args.library, library,
ignore=shutil.ignore_patterns(".git", "target", ".idea", ".neitzel-fx-designer"))
app = output / "NeitzelFXDesigner.app"
shutil.copytree(args.app, app, symlinks=True)
local = library / ".neitzel-fx-designer"
local.mkdir()
settings = local / "runtimes.json"
settings.write_text(json.dumps({"schemaVersion": "1.0", "runtimes": {"java21": {
"build": str(args.target_java_home.resolve()),
"target": str(args.target_java_home.resolve())}}}))
classes = output / "agent-classes"
classes.mkdir()
jars = list((app / "Contents/app").glob("*.jar"))
subprocess.run([args.java_home / "bin/javac", "-cp", os.pathsep.join(map(str, jars)),
"-d", classes, ROOT / "integration-tests/fx-example/FxExampleProbe.java"], check=True)
agent = output / "probe.jar"
with zipfile.ZipFile(agent, "w") as jar:
jar.writestr("META-INF/MANIFEST.MF",
"Manifest-Version: 1.0\nPremain-Class: qualification.FxExampleProbe\n\n")
for file in classes.rglob("*.class"):
jar.write(file, str(file.relative_to(classes)))
config = app / "Contents/app/NeitzelFXDesigner.cfg"
options = [f"-javaagent:{agent}", f"-Dexample.output={output}", f"-Dexample.library={library}"]
config.write_text(config.read_text() + "\n" + "".join("java-options=" + opt + "\n" for opt in options))
env = dict(os.environ)
for key in ("JAVA_TOOL_OPTIONS", "JDK_JAVA_OPTIONS", "_JAVA_OPTIONS"):
env.pop(key, None)
command = [app / "Contents/MacOS/NeitzelFXDesigner", "--configuration",
library / "neitzel-fx-designer.json", "--settings", settings,
"--maven", ROOT / "mvnw",
library / "fx-example/src/main/resources/de/neitzel/fx/example/view/Desk.fxml"]
crashes = NativeCrashGuard(ROOT)
with (output / "launcher.log").open("w") as log:
process = subprocess.Popen(list(map(str, command)), env=env, cwd=output,
stdout=log, stderr=subprocess.STDOUT)
try:
code = process.wait(timeout=420)
except subprocess.TimeoutExpired:
process.terminate()
try:
process.wait(timeout=15)
except subprocess.TimeoutExpired:
process.kill()
process.wait(timeout=10)
raise
if code != 0 or not (output / "SUCCESS.txt").exists():
raise RuntimeError((output / "launcher.log").read_text()[-10000:])
for pid in (output / "workers.txt").read_text().splitlines():
until = time.monotonic() + 10
while time.monotonic() < until:
try:
os.kill(int(pid), 0)
except ProcessLookupError:
break
time.sleep(.1)
else:
raise AssertionError("Preview worker survived host: " + pid)
crashes.check()
print((output / "SUCCESS.txt").read_text(), end="")