|
43 | 43 | # ---------------------------------------------------------------------------------- |
44 | 44 |
|
45 | 45 | BASE_DIR = Path(__file__).resolve().parent |
| 46 | +TANK_ROYALE_HOME = Path(os.environ.get("COMPAT_TANK_ROYALE_HOME", r"C:\Code\tank-royale")) |
| 47 | + |
| 48 | + |
| 49 | +def local_bot_api_jar(): |
| 50 | + """Returns the locally built Bot API jar, or the expected path when it has not been built.""" |
| 51 | + libs = TANK_ROYALE_HOME / "bot-api" / "java" / "build" / "libs" |
| 52 | + jars = [path for path in libs.glob("robocode-tankroyale-bot-api-*.jar") |
| 53 | + if not path.name.endswith(("-javadoc.jar", "-sources.jar"))] |
| 54 | + if jars: |
| 55 | + return str(max(jars, key=lambda path: path.stat().st_mtime)) |
| 56 | + return str(libs / "robocode-tankroyale-bot-api-local.jar") |
46 | 57 |
|
47 | 58 | DEFAULTS = { |
48 | 59 | "collection_dir": os.environ.get("COMPAT_COLLECTION_DIR", r"C:\Code\LiteRumble robots"), |
49 | 60 | "robocode_home": os.environ.get("COMPAT_ROBOCODE_HOME", r"C:\robocode"), |
50 | 61 | "runner_jar": os.environ.get( |
51 | 62 | "COMPAT_RUNNER_JAR", |
52 | | - r"C:\Code\tank-royale\runner\examples\lib\robocode-tankroyale-runner.jar"), |
| 63 | + str(TANK_ROYALE_HOME / "runner" / "examples" / "lib" / "robocode-tankroyale-runner.jar")), |
53 | 64 | "bridge_api_jar": os.environ.get( |
54 | 65 | "COMPAT_BRIDGE_API_JAR", |
55 | 66 | r"C:\Code\robocode-api-bridge\robocode-api\build\libs\robocode-api-0.5.0.jar"), |
56 | 67 | "wrapper_jar": os.environ.get( |
57 | 68 | "COMPAT_WRAPPER_JAR", |
58 | 69 | r"C:\Code\robocode-api-bridge\robots-wrapper\build\libs\robots-wrapper-0.3.1.jar"), |
59 | | - # NOTE: must be protocol/API compatible with what the bridge's robocode-api jar was |
60 | | - # compiled against AND with the server embedded in the runner jar. Publish it with |
61 | | - # `gradlew :bot-api:java:publishToMavenLocal` in the tank-royale repository. |
| 70 | + # The bridge uses a locally built Bot API and runner from the same Tank Royale revision; |
| 71 | + # override only with another matched local pair. Build the API with |
| 72 | + # `gradlew :bot-api:java:publishToMavenLocal` and runner with `:runner:copyRunnerJar`. |
62 | 73 | # (0.33.1 had an event-queue bug dropping deferred same-priority events, e.g. every |
63 | 74 | # other scan event for bots that call blocking methods inside onScannedRobot.) |
64 | 75 | "bot_api_jar": os.environ.get( |
65 | 76 | "COMPAT_BOT_API_JAR", |
66 | | - os.path.expanduser(r"~\.m2\repository\dev\robocode\tankroyale" |
67 | | - r"\robocode-tankroyale-bot-api\1.0.2" |
68 | | - r"\robocode-tankroyale-bot-api-1.0.2.jar")), |
| 77 | + local_bot_api_jar()), |
69 | 78 | # Classic Robocode installs a SecurityManager to sandbox robots. JDK 24 removed |
70 | 79 | # SecurityManager support outright, so -Djava.security.manager=allow is no longer a |
71 | 80 | # deprecation warning but a fatal VM error, and the classic side cannot start at all. |
@@ -880,6 +889,8 @@ def parse_args(): |
880 | 889 | conf.add_argument("--conformance", metavar="JAR", |
881 | 890 | help="run one robot jar on one engine and print the result, " |
882 | 891 | "including each participant's console output, as JSON") |
| 892 | + conf.add_argument("--conformance-source", type=Path, |
| 893 | + help="compile this bridge-owned robot source against classic before running it") |
883 | 894 | conf.add_argument("--engine", choices=("rc", "tr"), default="rc", |
884 | 895 | help="which engine --conformance drives") |
885 | 896 | conf.add_argument("--robot-class", |
@@ -1044,6 +1055,24 @@ def compile_trace_robot(opts): |
1044 | 1055 | return out_dir, None |
1045 | 1056 |
|
1046 | 1057 |
|
| 1058 | +def compile_conformance_robot(opts, source: Path): |
| 1059 | + """Compiles a bridge-owned conformance probe against the classic API.""" |
| 1060 | + out_dir = WORK_DIR / "conformance-probe-classes" |
| 1061 | + clean_dir(out_dir) |
| 1062 | + if not source.exists(): |
| 1063 | + return None, f"conformance probe source not found: {source}" |
| 1064 | + |
| 1065 | + classpath = str(Path(opts.robocode_home) / "libs" / "*") |
| 1066 | + cmd = [javac_beside(opts.rc_java_exe), "-cp", classpath, "-d", str(out_dir), str(source)] |
| 1067 | + try: |
| 1068 | + completed = subprocess.run(cmd, capture_output=True, text=True, timeout=180) |
| 1069 | + except (OSError, subprocess.SubprocessError) as e: |
| 1070 | + return None, f"could not compile conformance probe: {e}" |
| 1071 | + if completed.returncode != 0: |
| 1072 | + return None, f"conformance probe did not compile:\n{completed.stdout}\n{completed.stderr}" |
| 1073 | + return out_dir, None |
| 1074 | + |
| 1075 | + |
1047 | 1076 | def javac_beside(java_exe): |
1048 | 1077 | """The javac that ships next to a given java executable. |
1049 | 1078 |
|
@@ -1204,7 +1233,17 @@ def run_conformance(opts): |
1204 | 1233 | if opts.participants is not None: |
1205 | 1234 | setup["participants"] = opts.participants |
1206 | 1235 |
|
1207 | | - if jar.is_dir(): |
| 1236 | + if opts.conformance_source: |
| 1237 | + class_dir, error = compile_conformance_robot(opts, opts.conformance_source) |
| 1238 | + if error: |
| 1239 | + print(json.dumps({"ok": False, "fatal": error})) |
| 1240 | + return 2 |
| 1241 | + packaged, error = package_test_robot_jar(class_dir, classname, WORK_DIR / "conformance") |
| 1242 | + if error: |
| 1243 | + print(json.dumps({"ok": False, "fatal": error})) |
| 1244 | + return 2 |
| 1245 | + jar, version = packaged, "1.0" |
| 1246 | + elif jar.is_dir(): |
1208 | 1247 | # Package the one robot under test, for both engines. |
1209 | 1248 | # |
1210 | 1249 | # The bridge side needs a real robot jar because the wrapper finds robots by their |
|
0 commit comments