fix: keep truth model notes out of the native rows

check_freshness --only native rebuilds the truth model to compare it, and
the hash conflict notes generate_truth reports opened the freshness output.
They are dropped there, and any other stderr line still passes through.
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 05:13:59 +02:00
1 parent 9c2f49720d
commit 842d313a88
2 files changed
+57 -16

No files matched your search

+38 -16
View File
@@ -472,6 +472,27 @@ def _transcribed_at(platforms_dir: Path, platform: str) -> float:
return newest
# How the truth model settles two cores' hashes: generate_truth reports it,
# and it says nothing about whether a cached original is current.
_MODEL_NOTES = ("WARNING: hash conflict",)
@contextlib.contextmanager
def _without_model_notes():
"""Keep the model build's own notes out of the freshness report.
Anything else written to stderr passes through.
"""
sink = io.StringIO()
try:
with contextlib.redirect_stderr(sink):
yield
finally:
for line in sink.getvalue().splitlines(keepends=True):
if not line.startswith(_MODEL_NOTES):
sys.stderr.write(line)
def check_native(
platforms_dir: Path, cache_dir: Path, truth_dir: Path,
published: Path = Path("exports"),
@@ -484,24 +505,25 @@ def check_native(
exporter_class = exporters.get(name)
if not exporter_class:
continue
try:
truth, scraped = export_native.load_inputs(name, truth_dir, str(platforms_dir))
except export_native.StaleTruth as exc:
findings.append(Finding("native", name, STALE, detail=str(exc)))
continue
systems, _ = build_native_model(truth or {}, scraped)
wanted = export_native.wanted_sources(exporter_class(), systems, scraped)
reason = native_cache_state(
wanted, cache_dir / name, recorded, index, _transcribed_at(platforms_dir, name)
)
if reason:
reason += ", export_native.py --refresh-cache fetches it"
else:
reason = published_export_state(
name, exporter_class, truth_dir, platforms_dir, cache_dir, published
with _without_model_notes():
try:
truth, scraped = export_native.load_inputs(name, truth_dir, str(platforms_dir))
except export_native.StaleTruth as exc:
findings.append(Finding("native", name, STALE, detail=str(exc)))
continue
systems, _ = build_native_model(truth or {}, scraped)
wanted = export_native.wanted_sources(exporter_class(), systems, scraped)
reason = native_cache_state(
wanted, cache_dir / name, recorded, index, _transcribed_at(platforms_dir, name)
)
if reason:
reason += f", export_native.py --platform {name} writes it again"
reason += ", export_native.py --refresh-cache fetches it"
else:
reason = published_export_state(
name, exporter_class, truth_dir, platforms_dir, cache_dir, published
)
if reason:
reason += f", export_native.py --platform {name} writes it again"
findings.append(
Finding(
"native",
+19
View File
@@ -87,6 +87,25 @@ class NativeCacheTests(unittest.TestCase):
self.assertEqual({r.status for r in rows}, {cf.STALE})
self.assertIn("batocera", {r.subject for r in rows})
def test_the_model_build_notes_stay_out_of_the_report(self):
"""generate_truth reports how two cores' hashes were settled. Under
`--only native` they opened the report and named no step to take."""
import contextlib
import io
def noisy(truth, scraped):
print("WARNING: hash conflict for GameIndex.yaml (sha1: a vs b, core yaps2)",
file=sys.stderr)
print("other diagnostic", file=sys.stderr)
return {}, None
err = io.StringIO()
with mock.patch.object(cf, "build_native_model", side_effect=noisy), \
contextlib.redirect_stderr(err):
cf.check_native(REPO_ROOT / "platforms", self.cache, self.cache / "truth")
self.assertNotIn("hash conflict", err.getvalue())
self.assertIn("other diagnostic", err.getvalue())
class PublishedExportTests(unittest.TestCase):
"""exports/ is committed and published, and CI cannot rebuild it."""