From 895a520afdcfac61b6d59e79c2cb998e4490484c Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 6 Nov 2026 08:12:37 +0100 Subject: [PATCH] fix: verify --platform names uncached data dirs A platform entry that resolves only through a data directory tree read as missing with no cause on a checkout where data/ was never refreshed, while an online pack build refreshes the trees and packs it. verify_platform now reports the uncached trees and prints them when files are missing. --- scripts/verify.py | 14 ++++++ tests/test_verify_data_dir_notice.py | 74 ++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 tests/test_verify_data_dir_notice.py diff --git a/scripts/verify.py b/scripts/verify.py index 9fbdfa9a3..8689a4dcf 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -1575,6 +1575,13 @@ def verify_platform( "exclusion_notes": exclusions, "region_fallbacks": sorted(region_fallbacks), **({"left_out": left_out} if no_game_data else {}), + # Every tree of the registry answers a declaration by its tail, so + # one that was never refreshed leaves its files missing here while + # an online pack build refreshes it and packs them. + "data_dir_notices": sorted( + key for key, entry in (data_dir_registry or {}).items() + if not os.path.isdir(entry.get("local_cache", "")) + ), "details": details, "ground_truth_coverage": { "with_validation": with_validation, @@ -1952,6 +1959,13 @@ def print_platform_result( # them missing, as an offline build leaves them out. shown = ", ".join(fetched[:10]) + (f" (+{len(fetched) - 10})" if len(fetched) > 10 else "") print(f" Release assets fetched when the pack is built ({len(fetched)}): {shown}") + uncached = result.get("data_dir_notices") or [] + if uncached and result.get("status_counts", {}).get(Status.MISSING): + shown = ", ".join(uncached[:10]) + (f" (+{len(uncached) - 10})" if len(uncached) > 10 else "") + print( + f" Data directories not cached ({len(uncached)}), their files count missing " + f"until refresh_data_dirs.py runs (an online pack build refreshes them): {shown}" + ) for line in result.get("left_out") or []: print(f" {line}") fallbacks = result.get("region_fallbacks") or [] diff --git a/tests/test_verify_data_dir_notice.py b/tests/test_verify_data_dir_notice.py new file mode 100644 index 000000000..b9e4a71f9 --- /dev/null +++ b/tests/test_verify_data_dir_notice.py @@ -0,0 +1,74 @@ +"""verify --platform names the data directories that were never refreshed. + +A platform entry can resolve only through a data directory tree (AmberELEC's +Machines/*/config.ini in the blueMSX tree). On a checkout where data/ was +never refreshed, verify counted 200 such entries missing with no word on the +cause, while an online pack build refreshes the trees and packs them. +verify --emulator already named its uncached trees. +""" + +from __future__ import annotations + +import contextlib +import io +import os +import sys +import tempfile +import unittest +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(REPO_ROOT / "scripts")) + +import generate_db # noqa: E402 +from verify import print_platform_result, verify_platform # noqa: E402 + + +class UncachedDataDirectoryNotice(unittest.TestCase): + def setUp(self): + self._tmp = tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") + self._cwd = os.getcwd() + os.chdir(self._tmp.name) + Path("emulators").mkdir() + Path("data/present").mkdir(parents=True) + self.db = {"files": {}, "indexes": generate_db.build_indexes({}, {})} + self.config = { + "platform": "Tree", "verification_mode": "md5", + "systems": {"msx": {"files": [{ + "name": "config.ini", "destination": "Machines/MSX/config.ini", + }]}}, + } + self.registry = { + "absent": {"local_cache": "data/absent"}, + "present": {"local_cache": "data/present"}, + } + + def tearDown(self): + os.chdir(self._cwd) + self._tmp.cleanup() + + def _run(self) -> tuple[dict, str]: + result = verify_platform( + self.config, self.db, "emulators", {}, data_dir_registry=self.registry, + ) + out = io.StringIO() + with contextlib.redirect_stdout(out): + print_platform_result(result, ["Tree"]) + return result, out.getvalue() + + def test_an_uncached_tree_is_named(self): + result, printed = self._run() + self.assertEqual(result["data_dir_notices"], ["absent"]) + self.assertIn("Data directories not cached (1)", printed) + self.assertIn("refresh_data_dirs.py", printed) + self.assertIn(": absent", printed) + + def test_no_note_when_every_tree_is_cached(self): + Path("data/absent").mkdir() + result, printed = self._run() + self.assertEqual(result["data_dir_notices"], []) + self.assertNotIn("refresh_data_dirs", printed) + + +if __name__ == "__main__": + unittest.main()