mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-20 10:23:16 -05:00
docs: rewrite half-dash asides in comments
Dropping the double-dash asides left 72 comments and docstrings with
half a dash glued to the next word ("shape -a size or a size range -is
all"). They now read as a colon, a comma or parentheses, and a prose
style test names any that comes back.
This commit is contained in:
1 parent
e424a35aee
commit
71b59eb2a3
22 files changed
+89
-71
No files matched your search
+1
-1
@@ -5,7 +5,7 @@
|
||||
1. Fork this repository
|
||||
2. Place the file in `bios/Manufacturer/Console/filename`
|
||||
3. Variants (alternate hashes for the same file): `bios/Manufacturer/Console/.variants/`
|
||||
4. Open a Pull Request - hashes are verified automatically and reported as a comment
|
||||
4. Open a pull request. Its hashes are checked automatically and reported in a comment
|
||||
|
||||
The [dump provenance](https://abdess.github.io/retrobios/provenance/) page lists catalogued dumps still
|
||||
missing from the collection, with their hashes. A file matching one of those is
|
||||
|
||||
@@ -31,8 +31,8 @@ def write_if_changed(
|
||||
Compares new and existing content after stripping timestamp lines.
|
||||
Returns True if the file was written, False if skipped (unchanged).
|
||||
|
||||
A caller that writes a file in two passes -a body, then the same body
|
||||
wrapped in front matter -passes ``normalize`` to reduce both sides to the
|
||||
A caller that writes a file in two passes (a body, then the same body
|
||||
wrapped in front matter) passes ``normalize`` to reduce both sides to the
|
||||
part it owns. Without it the second pass always sees a difference, the
|
||||
file is rewritten, and the fresh timestamp defeats the comparison.
|
||||
"""
|
||||
|
||||
+3
-3
@@ -847,7 +847,7 @@ def _resolve_agnostic(
|
||||
"""Any file of the right shape under the declared prefix.
|
||||
|
||||
Some cores accept whatever filename sits in their BIOS directory, so the
|
||||
shape -a size or a size range -is all that identifies a candidate. A
|
||||
shape (a size or a size range) is all that identifies a candidate. A
|
||||
declared hash outranks that, and stops this step being reached.
|
||||
"""
|
||||
if not file_entry.get("agnostic") or has_strong_hash:
|
||||
@@ -1557,7 +1557,7 @@ def resolve_local_file(
|
||||
if valid:
|
||||
primary = [c[0] for c in valid if "/.variants/" not in c[0]]
|
||||
return (primary[0] if primary else valid[0][0]), "hash_mismatch"
|
||||
# No candidate contains the zipped_file -fall through to step 5
|
||||
# No candidate contains the zipped_file: fall through to step 5
|
||||
elif not unsourceable:
|
||||
ordered = _by_affinity([c[0] for c in candidates], file_entry, dest_hint)
|
||||
primary = [c for c in ordered if "/.variants/" not in c]
|
||||
@@ -2557,7 +2557,7 @@ import re
|
||||
|
||||
|
||||
|
||||
# Validation and mode filtering -extracted to validation.py for SoC.
|
||||
# Validation and mode filtering: extracted to validation.py for SoC.
|
||||
# Re-exported below for backward compatibility.
|
||||
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ def _rsa_verify_pkcs1v15_sha256(
|
||||
) -> bool:
|
||||
"""Verify RSA-2048 PKCS#1 v1.5 with SHA-256.
|
||||
|
||||
Pure Python -uses Python's native int for modular exponentiation.
|
||||
Pure Python: uses Python's native int for modular exponentiation.
|
||||
Reproduces CryptoPP::RSASS<PKCS1v15, SHA256>::Verifier.
|
||||
"""
|
||||
n = int.from_bytes(modulus, "big")
|
||||
|
||||
+4
-4
@@ -122,7 +122,7 @@ def _plan_group_removals(
|
||||
Records clone groups in *mame_clones* and returns the paths to remove.
|
||||
"""
|
||||
true_dupes_to_remove: list[str] = []
|
||||
# Separate by filename -same name = true duplicate, different name = clone
|
||||
# Separate by filename: same name = true duplicate, different name = clone
|
||||
by_name: dict[str, list[str]] = defaultdict(list)
|
||||
for p in paths:
|
||||
by_name[os.path.basename(p)].append(p)
|
||||
@@ -147,7 +147,7 @@ def _plan_group_removals(
|
||||
]
|
||||
true_dupes_to_remove.extend(p for p in variants if p not in holders)
|
||||
|
||||
# Different filenames, same content -need special handling
|
||||
# Different filenames, same content: need special handling
|
||||
unique_names = sorted(by_name.keys())
|
||||
if len(unique_names) > 1:
|
||||
# Check if these are all in MAME/Arcade dirs AND all ZIPs
|
||||
@@ -171,7 +171,7 @@ def _plan_group_removals(
|
||||
true_dupes_to_remove.append(p)
|
||||
else:
|
||||
# Non-MAME different names (e.g., 64DD_IPL_US.n64 vs IPL_USA.n64)
|
||||
# Keep ALL -each name may be needed by a different emulator
|
||||
# Keep ALL: each name may be needed by a different emulator
|
||||
# Only remove true duplicates (same name in multiple dirs)
|
||||
pass
|
||||
|
||||
@@ -223,7 +223,7 @@ def deduplicate(bios_dir: str, dry_run: bool = False) -> dict:
|
||||
# Find the best canonical across all paths
|
||||
all_paths = [p for p in paths if p not in true_dupes_to_remove]
|
||||
if not all_paths:
|
||||
# All copies were marked for removal -keep the best one
|
||||
# All copies were marked for removal: keep the best one
|
||||
all_paths_sorted = sorted(paths, key=path_priority)
|
||||
all_paths = [all_paths_sorted[0]]
|
||||
true_dupes_to_remove = [p for p in paths if p != all_paths[0]]
|
||||
|
||||
@@ -994,7 +994,7 @@ def generate_pack(
|
||||
|
||||
# Emulator-level validation: informational only for platform packs.
|
||||
# Platform verification (existence/md5) is the authority for pack status.
|
||||
# Emulator checks are supplementary -logged but don't downgrade.
|
||||
# Emulator checks are supplementary: logged but don't downgrade.
|
||||
# When a discrepancy is found, try to find a file satisfying both.
|
||||
if file_status.get(dedup_key) == "ok":
|
||||
local_path, disagreement = validated_choice(
|
||||
@@ -1145,7 +1145,7 @@ def generate_pack(
|
||||
seen_parents,
|
||||
)
|
||||
|
||||
# README.txt for users -personalized step-by-step per platform
|
||||
# README.txt for users: personalized step-by-step per platform
|
||||
num_systems = len(pack_systems)
|
||||
_registry_path = Path(platforms_dir) / "_registry.yml"
|
||||
_pack_registry: dict = {}
|
||||
|
||||
@@ -689,7 +689,7 @@ def contributing_text(
|
||||
1. Fork this repository
|
||||
2. Place the file in `bios/Manufacturer/Console/filename`
|
||||
3. Variants (alternate hashes for the same file): `bios/Manufacturer/Console/.variants/`
|
||||
4. Open a Pull Request - hashes are verified automatically and reported as a comment
|
||||
4. Open a pull request. Its hashes are checked automatically and reported in a comment
|
||||
|
||||
The [dump provenance]({link("provenance")}) page lists catalogued dumps still
|
||||
missing from the collection, with their hashes. A file matching one of those is
|
||||
|
||||
@@ -212,7 +212,7 @@ def resolve_file(
|
||||
if path and status != "hash_mismatch":
|
||||
return path, status
|
||||
|
||||
# Large files from GitHub release assets -tried when local file is
|
||||
# Large files from GitHub release assets: tried when local file is
|
||||
# missing OR has a hash mismatch (wrong variant on disk)
|
||||
name = file_entry.get("name", "")
|
||||
if file_entry.get("type") == "directory" or name.endswith("/"):
|
||||
|
||||
@@ -30,12 +30,12 @@ SOURCE_URL = (
|
||||
|
||||
# Libretro cores that expect BIOS files in a subdirectory of system/.
|
||||
# System.dat lists filenames flat, and the scraper prepends the prefix.
|
||||
# ref: each core's libretro.c or equivalent -see platforms/README.md
|
||||
# ref: each core's libretro.c or equivalent: see platforms/README.md
|
||||
CORE_SUBDIR_MAP = {
|
||||
"nec-pc-98": "np2kai", # libretro-np2kai/sdl/libretro.c
|
||||
"sharp-x68000": "keropi", # px68k/libretro/libretro.c
|
||||
"sega-dreamcast": "dc", # flycast/shell/libretro/libretro.cpp
|
||||
"sega-dreamcast-arcade": "dc", # flycast -same subfolder
|
||||
"sega-dreamcast-arcade": "dc", # flycast: same subfolder
|
||||
}
|
||||
|
||||
SYSTEM_SLUG_MAP = {
|
||||
@@ -252,11 +252,11 @@ class Scraper(BaseScraper):
|
||||
|
||||
systems[req.system]["files"].append(requirement_entry(req))
|
||||
|
||||
# Systems not in System.dat but needed for RetroArch -added via
|
||||
# Systems not in System.dat but needed for RetroArch: added via
|
||||
# shared groups in _shared.yml. The includes directive is resolved
|
||||
# at load time by load_platform_config().
|
||||
EXTRA_SYSTEMS = {
|
||||
# ref: Vircon32/libretro.c -virtual console, single BIOS
|
||||
# ref: Vircon32/libretro.c, virtual console, single BIOS
|
||||
"vircon32": {
|
||||
"files": [
|
||||
{
|
||||
@@ -269,7 +269,7 @@ class Scraper(BaseScraper):
|
||||
"manufacturer": "Vircon",
|
||||
"docs": "https://docs.libretro.com/library/vircon32/",
|
||||
},
|
||||
# ref: xrick/src/sysvid.c, xrick/src/data.c -game data archive
|
||||
# ref: xrick/src/sysvid.c, xrick/src/data.c, game data archive
|
||||
"xrick": {
|
||||
"files": [
|
||||
{
|
||||
@@ -295,7 +295,7 @@ class Scraper(BaseScraper):
|
||||
# Arcade BIOS present in the repo but absent from System.dat.
|
||||
# FBNeo expects them in system/ or system/fbneo/.
|
||||
# ref: fbneo/src/burner/libretro/libretro.cpp
|
||||
# ref: fbneo/src/burner/libretro/libretro.cpp -search order:
|
||||
# ref: fbneo/src/burner/libretro/libretro.cpp, search order:
|
||||
# 1) romset dir 2) system/fbneo/ 3) system/
|
||||
EXTRA_ARCADE_FILES = [
|
||||
{"name": "namcoc69.zip", "destination": "namcoc69.zip", "required": True},
|
||||
@@ -339,7 +339,7 @@ class Scraper(BaseScraper):
|
||||
# Extra files missing from System.dat for specific systems.
|
||||
# Each traced to the core's source code.
|
||||
EXTRA_SYSTEM_FILES = {
|
||||
# melonDS DS DSi mode -ref: JesseTG/melonds-ds/src/libretro.cpp
|
||||
# melonDS DS DSi mode, ref: JesseTG/melonds-ds/src/libretro.cpp
|
||||
"nintendo-ds": [
|
||||
{
|
||||
"name": "dsi_bios7.bin",
|
||||
@@ -362,7 +362,7 @@ class Scraper(BaseScraper):
|
||||
"required": True,
|
||||
},
|
||||
],
|
||||
# bsnes SGB naming -ref: bsnes/target-libretro/libretro.cpp
|
||||
# bsnes SGB naming, ref: bsnes/target-libretro/libretro.cpp
|
||||
"nintendo-sgb": [
|
||||
{
|
||||
"name": "sgb.boot.rom",
|
||||
@@ -370,13 +370,13 @@ class Scraper(BaseScraper):
|
||||
"required": False,
|
||||
},
|
||||
],
|
||||
# JollyCV -ref: jollycv/libretro.c
|
||||
# JollyCV, ref: jollycv/libretro.c
|
||||
"coleco-colecovision": [
|
||||
{"name": "BIOS.col", "destination": "BIOS.col", "required": True},
|
||||
{"name": "coleco.rom", "destination": "coleco.rom", "required": True},
|
||||
{"name": "bioscv.rom", "destination": "bioscv.rom", "required": True},
|
||||
],
|
||||
# Kronos ST-V -ref: libretro-kronos/libretro/libretro.c
|
||||
# Kronos ST-V, ref: libretro-kronos/libretro/libretro.c
|
||||
"sega-saturn": [
|
||||
{
|
||||
"name": "stvbios.zip",
|
||||
@@ -384,7 +384,7 @@ class Scraper(BaseScraper):
|
||||
"required": True,
|
||||
},
|
||||
],
|
||||
# PCSX ReARMed / Beetle PSX alt BIOS -ref: pcsx_rearmed/libpcsxcore/misc.c
|
||||
# PCSX ReARMed / Beetle PSX alt BIOS, ref: pcsx_rearmed/libpcsxcore/misc.c
|
||||
# docs say PSXONPSP660.bin (uppercase) but core accepts any case
|
||||
"sony-playstation": [
|
||||
{
|
||||
@@ -393,7 +393,7 @@ class Scraper(BaseScraper):
|
||||
"required": False,
|
||||
},
|
||||
],
|
||||
# Dolphin GC -ref: DolphinLibretro/Boot.cpp:72-73,
|
||||
# Dolphin GC, ref: DolphinLibretro/Boot.cpp:72-73,
|
||||
# BootManager.cpp:200-217, CommonPaths.h:139 GC_IPL="IPL.bin"
|
||||
# Core searches system/dolphin-emu/Sys/ for data and BIOS.
|
||||
# System.dat gc-ntsc-*.bin names are NOT what Dolphin loads.
|
||||
@@ -414,7 +414,7 @@ class Scraper(BaseScraper):
|
||||
"destination": "dolphin-emu/Sys/GC/JAP/IPL.bin",
|
||||
"required": False,
|
||||
},
|
||||
# DSP firmware -ref: Source/Core/Core/HW/DSPLLE/DSPHost.cpp
|
||||
# DSP firmware, ref: Source/Core/Core/HW/DSPLLE/DSPHost.cpp
|
||||
{
|
||||
"name": "dsp_coef.bin",
|
||||
"destination": "dolphin-emu/Sys/GC/dsp_coef.bin",
|
||||
@@ -425,7 +425,7 @@ class Scraper(BaseScraper):
|
||||
"destination": "dolphin-emu/Sys/GC/dsp_rom.bin",
|
||||
"required": True,
|
||||
},
|
||||
# Fonts -ref: Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp
|
||||
# Fonts, ref: Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp
|
||||
{
|
||||
"name": "font_western.bin",
|
||||
"destination": "dolphin-emu/Sys/GC/font_western.bin",
|
||||
@@ -437,8 +437,8 @@ class Scraper(BaseScraper):
|
||||
"required": False,
|
||||
},
|
||||
],
|
||||
# minivmac casing -ref: minivmac/src/MYOSGLUE.c
|
||||
# doc says MacII.rom, repo has MacII.ROM -both work on case-insensitive FS
|
||||
# minivmac casing, ref: minivmac/src/MYOSGLUE.c
|
||||
# doc says MacII.rom, repo has MacII.ROM: both work on case-insensitive FS
|
||||
"apple-macintosh-ii": [
|
||||
{"name": "MacII.ROM", "destination": "MacII.ROM", "required": True},
|
||||
],
|
||||
@@ -458,7 +458,7 @@ class Scraper(BaseScraper):
|
||||
# Inject shared group references for systems that have core-specific
|
||||
# subdirectory requirements already defined in _shared.yml.
|
||||
# Note: fuse/ prefix NOT injected for sinclair-zx-spectrum.
|
||||
# Verified in fuse-libretro/src/compat/paths.c -core searches
|
||||
# Verified in fuse-libretro/src/compat/paths.c, core searches
|
||||
# system/ flat, not fuse/ subfolder. Docs are wrong on this.
|
||||
# A group System.dat already covers entry for entry injects nothing
|
||||
# (ep128emu, keropi and kronos were), and a correction made there
|
||||
@@ -484,12 +484,12 @@ class Scraper(BaseScraper):
|
||||
{"ref": "ppsspp-assets", "destination": "PPSSPP"},
|
||||
],
|
||||
# single buildbot ZIP contains both Databases/ and Machines/
|
||||
# ref: libretro.c:1118-1119 -system_dir/Machines + system_dir/Databases
|
||||
# ref: libretro.c:1118-1119, system_dir/Machines + system_dir/Databases
|
||||
"microsoft-msx": [
|
||||
{"ref": "bluemsx", "destination": ""},
|
||||
],
|
||||
# FreeIntv overlays -system/freeintv_overlays/<rom>.png
|
||||
# ref: FreeIntv/src/libretro.c:273 -stbi_load from system dir
|
||||
# FreeIntv overlays: system/freeintv_overlays/<rom>.png
|
||||
# ref: FreeIntv/src/libretro.c:273, stbi_load from system dir
|
||||
# ZIP contains FreeIntvTS_Overlays/ subfolder, cache preserves it
|
||||
# pack destination maps cache root to system/freeintv_overlays
|
||||
# so final path is system/freeintv_overlays/FreeIntvTS_Overlays/<rom>.png
|
||||
|
||||
@@ -184,7 +184,7 @@ def _resolve_path(p: str) -> str:
|
||||
def _extract_bios_entries(component_val: dict) -> list[dict]:
|
||||
"""Extract BIOS entries from all three possible locations in a component.
|
||||
|
||||
No dedup here -dedup is done in fetch_requirements() with full
|
||||
No dedup here: dedup is done in fetch_requirements() with full
|
||||
(system, filename) key to avoid dropping valid same-filename entries
|
||||
across different systems.
|
||||
"""
|
||||
@@ -368,13 +368,13 @@ class Scraper(BaseScraper):
|
||||
if resolved.startswith("saves"):
|
||||
continue
|
||||
|
||||
# Build destination -default to bios/ if no path specified
|
||||
# Build destination: default to bios/ if no path specified
|
||||
if resolved:
|
||||
destination = f"{resolved}/{filename}"
|
||||
else:
|
||||
destination = f"bios/{filename}"
|
||||
|
||||
# MD5 handling -sanitize upstream errors
|
||||
# MD5 handling: sanitize upstream errors
|
||||
md5_raw = entry.get("md5", "")
|
||||
if isinstance(md5_raw, list):
|
||||
parts = [str(m).strip().lower() for m in md5_raw if m]
|
||||
|
||||
@@ -132,7 +132,7 @@ def _check_atom(
|
||||
if tok.startswith('"'):
|
||||
pos += 1
|
||||
return True, pos
|
||||
# Unknown token -treat as true to avoid false negatives
|
||||
# Unknown token: treat as true to avoid false negatives
|
||||
pos += 1
|
||||
return True, pos
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Scraper for EmuDeck emulator targets.
|
||||
|
||||
Sources:
|
||||
SteamOS: dragoonDorise/EmuDeck -functions/EmuScripts/*.sh
|
||||
Windows: EmuDeck/emudeck-we -functions/EmuScripts/*.ps1
|
||||
SteamOS: dragoonDorise/EmuDeck, functions/EmuScripts/*.sh
|
||||
Windows: EmuDeck/emudeck-we, functions/EmuScripts/*.ps1
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -70,7 +70,7 @@ TARGETS: list[tuple[str, str, str]] = [
|
||||
("dingux/miyoo-arm32/latest", "miyoo-arm32", "armv5"),
|
||||
("webos/armv7a/latest", "webos-armv7a", "armv7"),
|
||||
("webos/aarch64/latest", "webos-aarch64", "aarch64"),
|
||||
# vita: only VPK bundles on buildbot -cores listed via libretro-super recipes
|
||||
# vita: only VPK bundles on buildbot, cores listed via libretro-super recipes
|
||||
]
|
||||
|
||||
# Recipe-based targets: (recipe_path_under_RECIPE_BASE_URL, target_name, architecture)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Implements GF(2^233) field arithmetic, elliptic curve point operations,
|
||||
and ECDSA-SHA256 verification for Nintendo 3DS OTP certificate checking.
|
||||
|
||||
Zero external dependencies -uses only Python stdlib.
|
||||
Zero external dependencies: uses only Python stdlib.
|
||||
|
||||
Curve: sect233r1 (NIST B-233, SEC 2 v2)
|
||||
Field: GF(2^233) with irreducible polynomial t^233 + t^74 + 1
|
||||
@@ -83,7 +83,7 @@ def _gf_inv(a: int) -> int:
|
||||
q ^= 1 << shift
|
||||
temp ^= r << shift
|
||||
remainder = temp
|
||||
# Multiply q * s in GF(2)[x] (no reduction -working in polynomial ring)
|
||||
# Multiply q * s in GF(2)[x] (no reduction: working in polynomial ring)
|
||||
qs = 0
|
||||
qt = q
|
||||
st = s
|
||||
|
||||
+2
-2
@@ -505,7 +505,7 @@ def generate_platform_truth(
|
||||
sys_cov["profiled"].add(emu_name)
|
||||
|
||||
# Ensure all systems of resolved cores have entries (even with 0 files).
|
||||
# This documents that the system is covered -the core was analyzed and
|
||||
# This documents that the system is covered: the core was analyzed and
|
||||
# needs no external files for this system.
|
||||
for emu_name in cores_profiled:
|
||||
profile = profiles[emu_name]
|
||||
@@ -778,7 +778,7 @@ def diff_platform_truth(truth: dict, scraped: dict) -> dict:
|
||||
else:
|
||||
summary["systems_fully_covered"] += 1
|
||||
|
||||
# Truth systems not matched by any scraped system -all files missing
|
||||
# Truth systems not matched by any scraped system: all files missing
|
||||
for t_sid in sorted(truth_systems):
|
||||
if t_sid in matched_truth:
|
||||
continue
|
||||
|
||||
@@ -23,7 +23,7 @@ from nativemode import SIZE_AND_ANY_HASH, digest_algorithm, hash_mismatch_exclud
|
||||
from ziptools import check_inside_zip
|
||||
|
||||
# Validation types that require console-specific cryptographic keys.
|
||||
# verify.py cannot reproduce these -size checks still apply if combined.
|
||||
# verify.py cannot reproduce these: size checks still apply if combined.
|
||||
_CRYPTO_CHECKS = frozenset({"signature", "crypto"})
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
index[fname]["max_size"] = (
|
||||
max(cur, f["max_size"]) if cur is not None else f["max_size"]
|
||||
)
|
||||
# Hash checks -collect all accepted hashes as sets (multiple valid
|
||||
# Hash checks: collect all accepted hashes as sets (multiple valid
|
||||
# versions of the same file, e.g. MT-32 ROM versions)
|
||||
if "crc32" in checks and f.get("crc32"):
|
||||
crc_val = f["crc32"]
|
||||
@@ -235,7 +235,7 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
for h in values:
|
||||
if str(h).strip():
|
||||
index[fname][hash_type].add(str(h).strip().lower())
|
||||
# Adler32 -stored as known_hash_adler32 field (not in validation: list
|
||||
# Adler32: stored as known_hash_adler32 field (not in validation: list
|
||||
# for Dolphin, but support it in both forms for future profiles)
|
||||
adler_val = f.get("known_hash_adler32") or f.get("adler32")
|
||||
for value in adler_val if isinstance(adler_val, list) else [adler_val] if adler_val else []:
|
||||
@@ -370,7 +370,7 @@ def check_file_validation(
|
||||
checks = entry["checks"]
|
||||
pe = entry.get("per_emulator", {})
|
||||
|
||||
# Size checks -sizes is a set of accepted values
|
||||
# Size checks: sizes is a set of accepted values
|
||||
if "size" in checks:
|
||||
actual_size = os.path.getsize(local_path)
|
||||
if entry["sizes"] and actual_size not in entry["sizes"]:
|
||||
@@ -384,7 +384,7 @@ def check_file_validation(
|
||||
emus = _emulators_for_check("size", pe)
|
||||
return f"size too large: max {entry['max_size']}, got {actual_size}", emus
|
||||
|
||||
# Hash checks -compute once, reuse for all hash types.
|
||||
# Hash checks: compute once, reuse for all hash types.
|
||||
# Each hash field is a set of accepted values (multiple valid ROM versions).
|
||||
need_hashes = any(
|
||||
h in checks and entry.get(h) for h in ("crc32", "md5", "sha1", "sha256")
|
||||
|
||||
+4
-4
@@ -109,7 +109,7 @@ _REPO_PLATFORMS = os.path.join(os.path.dirname(__file__), "..", "platforms")
|
||||
DEFAULT_EMULATORS_DIR = "emulators"
|
||||
|
||||
|
||||
# Status model -aligned with Batocera BiosStatus (batocera-systems:967-969)
|
||||
# Status model: aligned with Batocera BiosStatus (batocera-systems:967-969)
|
||||
|
||||
|
||||
class Status:
|
||||
@@ -420,8 +420,8 @@ def _candidate_verdict(
|
||||
"""Whether a profile entry can be a gap, and whether it is settled.
|
||||
|
||||
Three answers. "keep" means it is a candidate. "settled" means something
|
||||
has answered for it -the platform declares it, or the profile documents
|
||||
it as unsourceable -so the same requirement reached from another profile
|
||||
has answered for it (the platform declares it, or the profile documents
|
||||
it as unsourceable), so the same requirement reached from another profile
|
||||
must not be reconsidered. "skip" means it does not apply in this context,
|
||||
which leaves it open for a profile where it does: the same file can be
|
||||
libretro-only here and standalone-only there.
|
||||
@@ -735,7 +735,7 @@ def find_exclusion_notes(
|
||||
)
|
||||
continue
|
||||
|
||||
# Count standalone-only files -but only report as excluded if the
|
||||
# Count standalone-only files, but only report as excluded if the
|
||||
# platform does NOT use this emulator in standalone mode
|
||||
standalone_set = platform_standalone_set(config)
|
||||
is_standalone = runs_standalone(emu_name, profile, standalone_set)
|
||||
|
||||
@@ -171,7 +171,7 @@ class TestPackDeterminism(unittest.TestCase):
|
||||
sha1 = hashlib.sha1(payload).hexdigest()
|
||||
# A romset goes through the deterministic rebuild, which stages the
|
||||
# archive in a temporary file. Copying that file into the pack took
|
||||
# its mtime -the wall clock -so 348 members of the real Recalbox
|
||||
# its mtime, the wall clock, so 348 members of the real Recalbox
|
||||
# pack moved between two builds while every byte matched. Without a
|
||||
# romset here the fixture never reaches that path.
|
||||
romset = self.bios / "romset.zip"
|
||||
|
||||
+12
-12
@@ -574,7 +574,7 @@ class TestE2E(unittest.TestCase):
|
||||
"type": "libretro",
|
||||
"systems": ["console-a", "sys-md5"],
|
||||
"files": [
|
||||
# Size validation -correct size (16 bytes = len(b"PRESENT_REQUIRED"))
|
||||
# Size validation: correct size (16 bytes = len(b"PRESENT_REQUIRED"))
|
||||
{
|
||||
"name": "present_req.bin",
|
||||
"required": True,
|
||||
@@ -582,14 +582,14 @@ class TestE2E(unittest.TestCase):
|
||||
"size": 16,
|
||||
"source_ref": "test.c:10-20",
|
||||
},
|
||||
# Size validation -wrong expected size
|
||||
# Size validation: wrong expected size
|
||||
{
|
||||
"name": "present_opt.bin",
|
||||
"required": False,
|
||||
"validation": ["size"],
|
||||
"size": 9999,
|
||||
},
|
||||
# CRC32 validation -correct crc32
|
||||
# CRC32 validation: correct crc32
|
||||
{
|
||||
"name": "correct_hash.bin",
|
||||
"required": True,
|
||||
@@ -597,7 +597,7 @@ class TestE2E(unittest.TestCase):
|
||||
"crc32": "91d0b1d3",
|
||||
"source_ref": "hash.c:42",
|
||||
},
|
||||
# CRC32 validation -wrong crc32
|
||||
# CRC32 validation: wrong crc32
|
||||
{
|
||||
"name": "no_md5.bin",
|
||||
"required": False,
|
||||
@@ -611,28 +611,28 @@ class TestE2E(unittest.TestCase):
|
||||
"validation": ["crc32"],
|
||||
"crc32": "0179e92e",
|
||||
},
|
||||
# MD5 validation -correct md5
|
||||
# MD5 validation: correct md5
|
||||
{
|
||||
"name": "correct_hash.bin",
|
||||
"required": True,
|
||||
"validation": ["md5"],
|
||||
"md5": "4a8db431e3b1a1acacec60e3424c4ce8",
|
||||
},
|
||||
# SHA1 validation -correct sha1
|
||||
# SHA1 validation: correct sha1
|
||||
{
|
||||
"name": "correct_hash.bin",
|
||||
"required": True,
|
||||
"validation": ["sha1"],
|
||||
"sha1": "a2ab6c95c5bbd191b9e87e8f4e85205a47be5764",
|
||||
},
|
||||
# MD5 validation -wrong md5
|
||||
# MD5 validation: wrong md5
|
||||
{
|
||||
"name": "alias_target.bin",
|
||||
"required": False,
|
||||
"validation": ["md5"],
|
||||
"md5": "0000000000000000000000000000dead",
|
||||
},
|
||||
# Adler32 -known_hash_adler32 field
|
||||
# Adler32: known_hash_adler32 field
|
||||
{
|
||||
"name": "present_req.bin",
|
||||
"required": True,
|
||||
@@ -646,7 +646,7 @@ class TestE2E(unittest.TestCase):
|
||||
"min_size": 10,
|
||||
"max_size": 100,
|
||||
},
|
||||
# Signature -crypto check we can't reproduce, but size applies
|
||||
# Signature: crypto check we can't reproduce, but size applies
|
||||
{
|
||||
"name": "correct_hash.bin",
|
||||
"required": True,
|
||||
@@ -747,7 +747,7 @@ class TestE2E(unittest.TestCase):
|
||||
yaml.dump(emu_mixed_agnostic, fh)
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# THE TEST -one method per feature area, all using same fixtures
|
||||
# THE TEST: one method per feature area, all using same fixtures
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
def test_01_resolve_sha1(self):
|
||||
@@ -999,7 +999,7 @@ class TestE2E(unittest.TestCase):
|
||||
config, self.emulators_dir, self.db, profiles
|
||||
)
|
||||
names = {u["name"] for u in undeclared}
|
||||
# dd_covered.bin is a file entry, not data_dir content -still undeclared
|
||||
# dd_covered.bin is a file entry, not data_dir content: still undeclared
|
||||
self.assertIn("dd_covered.bin", names)
|
||||
|
||||
def test_44_cross_ref_skips_launchers(self):
|
||||
@@ -2197,7 +2197,7 @@ class TestE2E(unittest.TestCase):
|
||||
config = load_platform_config("test_existence", self.platforms_dir)
|
||||
profiles = load_emulator_profiles(self.emulators_dir)
|
||||
result = verify_platform(config, self.db, self.emulators_dir, profiles)
|
||||
# Simulate --json filtering (non-OK only) -ground_truth must survive
|
||||
# Simulate --json filtering (non-OK only): ground_truth must survive
|
||||
filtered = [d for d in result["details"] if d["status"] != Status.OK]
|
||||
for d in filtered:
|
||||
self.assertIn("ground_truth", d)
|
||||
|
||||
@@ -260,7 +260,7 @@ class CandidateVerdict(unittest.TestCase):
|
||||
"""Whether a profile entry can be a gap, and whether it is settled.
|
||||
|
||||
The filter chain mixed two kinds of skip. A settled entry is answered for
|
||||
-the platform declares it, the profile calls it unsourceable -so the same
|
||||
(the platform declares it, the profile calls it unsourceable), so the same
|
||||
requirement reached from another profile must not be reconsidered. A
|
||||
skipped one merely does not apply here: the same file can be libretro-only
|
||||
in one profile and standalone-only in another, and recording it from the
|
||||
|
||||
@@ -238,6 +238,24 @@ class NoClauseSemicolons(unittest.TestCase):
|
||||
self._check(files, _python_prose)
|
||||
|
||||
|
||||
def test_python_prose_has_no_lone_dash_asides(self):
|
||||
"""Removing " -- " asides left 72 comments reading "shape -a size or
|
||||
a size range -is all": half a dash glued to the next word. A command
|
||||
line flag quoted in prose (MAME's -listxml) is not an aside, and a
|
||||
quotation is left alone."""
|
||||
lone = re.compile(r"[A-Za-z0-9,)] -(?!listxml\b|lr\b|sa\b)[a-z]{2,}")
|
||||
offenders = [
|
||||
f"{path.relative_to(ROOT)}: {line.strip()[:100]}"
|
||||
for path in _tracked() if path.suffix == ".py"
|
||||
for line in re.sub(
|
||||
r'`[^`]*`|"[^"\n]*\n?[^"\n]*"',
|
||||
"",
|
||||
_python_prose(path.read_text(encoding="utf-8")).replace('"""', ""),
|
||||
).splitlines()
|
||||
if lone.search(line) and not re.search(r"\b(python|curl|unittest|sh)\b .* -", line)
|
||||
]
|
||||
self.assertEqual(offenders, [], "\n".join(offenders[:40]))
|
||||
|
||||
def test_schema_descriptions(self):
|
||||
offenders = []
|
||||
for path in sorted((ROOT / "schemas").glob("*.json")):
|
||||
|
||||
@@ -286,8 +286,8 @@ diff .cache/upstream-native/myplatform/<their file> \
|
||||
```
|
||||
|
||||
The export must not lose anything the platform already declares. If your
|
||||
format carries code as well as data - a script, a C# database, a manifest
|
||||
whose BIOS list sits beside launch configuration - say so with
|
||||
format carries code as well as data (a script, a C# database, a manifest
|
||||
whose BIOS list sits beside launch configuration), say so with
|
||||
`needs_original()` and patch their file rather than writing a new one. An
|
||||
exporter that regenerates such a file from BIOS data alone hands the
|
||||
maintainer something that no longer runs.
|
||||
|
||||
Reference in new issue
Block a user