fix: reports hold the data trees they read

generate_readme, generate_site and slots resolve against data/ but took no hold when run on their own, as the documented commands do. A refresh swapping a tree mid-read then gave counts from half of it. Each now holds the trees shared, like verify and the builder.
This commit is contained in:
Abdessamad Derraz committed 2026-10-20 00:32:26 +02:00
1 parent aea67e998f
commit 7e23815545
4 files changed
+50 -2

No files matched your search

+10 -1
View File
@@ -772,9 +772,18 @@ def main() -> None:
)
args = parser.parse_args()
import contextlib
from common import load_data_dir_registry
from refresh_data_dirs import hold_data_dirs
db = load_database(args.db)
readme = generate_readme(db, args.platforms_dir)
# Coverage resolves against data/: a refresh swapping a tree mid-read
# published counts taken from half of it.
with contextlib.ExitStack() as held:
hold_data_dirs(held, load_data_dir_registry(args.platforms_dir))
readme = generate_readme(db, args.platforms_dir)
status = "Generated" if write_if_changed("README.md", readme) else "Unchanged"
print(f"{status} ./README.md")
+8 -1
View File
@@ -4395,7 +4395,14 @@ def main() -> None:
try:
# Two runs over one docs/ delete each other's pages and scratch
# files in the sweep, so the second is refused instead.
with artifact_lock(args.docs_dir):
import contextlib
from common import load_data_dir_registry
from refresh_data_dirs import hold_data_dirs
# The coverage pages resolve against data/, held while they are read.
with artifact_lock(args.docs_dir), contextlib.ExitStack() as held:
hold_data_dirs(held, load_data_dir_registry(args.platforms_dir))
_generate(args)
except ArtifactLockBusy as exc:
print(f"ERROR: {exc}", file=sys.stderr)
+10
View File
@@ -894,6 +894,16 @@ def main() -> int:
)
args = parser.parse_args()
import contextlib
from common import load_data_dir_registry
from refresh_data_dirs import hold_data_dirs
# Claims resolve against data/: the trees stay put until the process
# ends, which releases the hold.
held = contextlib.ExitStack()
hold_data_dirs(held, load_data_dir_registry(args.platforms_dir))
db = load_database(args.db)
profiles = load_emulator_profiles(args.emulators_dir)
if args.platform:
+22
View File
@@ -5265,5 +5265,27 @@ class AHashScanningCoreContradictsNoPlatform(unittest.TestCase):
self.assertEqual(claimed, [])
class ReportsHoldTheDataTrees(unittest.TestCase):
"""Run on their own, the README, site and slot reports resolved against
data/ without the shared hold, so a concurrent refresh could swap a tree
while they read it and the published counts came from half of it."""
def test_each_entry_point_holds_them(self):
import ast
for script in ("generate_readme.py", "generate_site.py", "slots.py"):
tree = ast.parse((ROOT / "scripts" / script).read_text(encoding="utf-8"))
main = next(
node for node in tree.body
if isinstance(node, ast.FunctionDef) and node.name == "main"
)
with self.subTest(script=script):
self.assertTrue(any(
isinstance(call, ast.Call)
and getattr(call.func, "id", None) == "hold_data_dirs"
for call in ast.walk(main)
))
if __name__ == "__main__":
unittest.main()