diff --git a/scripts/generate_pack.py b/scripts/generate_pack.py index 090c98d4..8eb40f29 100644 --- a/scripts/generate_pack.py +++ b/scripts/generate_pack.py @@ -73,6 +73,7 @@ from nativemode import ( reads_file_contents, ) from validation import ( + existence_discrepancy, destination_owners, validated_choice, inner_rom_check, @@ -908,15 +909,9 @@ def generate_pack( # their code never reads the bytes. An upstream hash that # contradicts a local dump is reported, not acted on. if status == "hash_mismatch" and local_path: - declared = file_entry.get("md5", "") or file_entry.get( - "sha1", "" - ) - actual = compute_hashes(local_path) file_reasons.setdefault( dedup_key, - f"packed per {platform_display} existence check; " - f"declared hash {declared}, file md5 " - f"{actual['md5']} sha1 {actual['sha1']}", + existence_discrepancy(file_entry, local_path, platform_display), ) file_status.setdefault(dedup_key, "ok") diff --git a/scripts/validation.py b/scripts/validation.py index 16f9cf08..8661622f 100644 --- a/scripts/validation.py +++ b/scripts/validation.py @@ -559,3 +559,15 @@ def validated_choice( return better, None reason, emulators = check return local_path, f"{', '.join(emulators)} says {reason}" + + +def existence_discrepancy(file_entry: dict, local_path: str, platform_display: str) -> str: + """What an existence platform is told when its declared hash contradicts + the file it loads: the file is kept, the gap is said out loud. The pack + and verify both print this one line.""" + declared = file_entry.get("md5", "") or file_entry.get("sha1", "") + actual = compute_hashes(local_path) + return ( + f"packed per {platform_display} existence check; declared hash {declared}, " + f"file md5 {actual['md5']} sha1 {actual['sha1']}" + ) diff --git a/scripts/verify.py b/scripts/verify.py index 453b0443..8c4b2cdd 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -69,6 +69,7 @@ from nativemode import ( reads_file_contents, ) from validation import ( + existence_discrepancy, destination_owners, validated_choice, agnostic_substitute, @@ -124,6 +125,8 @@ def verify_entry_existence( db: dict | None = None, destination: str = "", owners: dict | None = None, + resolve_status: str = "", + platform_display: str = "", ) -> dict: """RetroArch verification: path_is_valid() -file exists = OK.""" name = file_entry.get("name", "") @@ -131,6 +134,13 @@ def verify_entry_existence( if not local_path: return {"name": name, "status": Status.MISSING, "required": required} result = {"name": name, "status": Status.OK, "required": required} + if resolve_status == "hash_mismatch": + # The frontend reads no bytes, so the file stays; the declared hash + # it contradicts is reported, as the pack does. + result["discrepancy"] = existence_discrepancy( + file_entry, local_path, platform_display + ) + return result if not validation_index: return result if db: @@ -874,6 +884,8 @@ def verify_platform( db, destination, validation_owners, + resolve_status, + config.get("platform", ""), ) elif digest_algorithm(mode) == "sha1": result = verify_entry_sha1(file_entry, local_path) diff --git a/tests/test_verify_listing.py b/tests/test_verify_listing.py index d52dff3f..95641bd2 100644 --- a/tests/test_verify_listing.py +++ b/tests/test_verify_listing.py @@ -115,5 +115,24 @@ class CoreArchivesAreCounted(unittest.TestCase): self.assertIn("1 required missing", out.getvalue()) self.assertIn("neogeo.zip", out.getvalue()) + +class ExistenceReportsWhatThePackReports(unittest.TestCase): + def test_a_contradicted_hash_is_a_discrepancy(self): + """30 RetroArch entries printed DISCREPANCY in the pack, nothing in verify.""" + import tempfile # noqa: PLC0415 + + sys.path.insert(0, str(REPO_ROOT / "scripts")) + import verify # noqa: PLC0415 + + with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp: + path = Path(tmp) / "aes.zip" + path.write_bytes(b"local dump") + entry = {"name": "aes.zip", "md5": "9d2ff2333e23910cf56f7f785609d36a"} + result = verify.verify_entry_existence( + entry, str(path), resolve_status="hash_mismatch", platform_display="RetroArch" + ) + self.assertEqual(result["status"], verify.Status.OK) + self.assertIn("declared hash 9d2ff233", result["discrepancy"]) + if __name__ == "__main__": unittest.main()