mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-01 00:27:20 -05:00
fix: record each platform's own list version
install/<platform>.json wrote the constant "1.0" as the version of the list it was built from. The manifest now carries the version the platform YAML records, and generate_pack refuses a YAML without one. inherits: no longer passes a parent's version to a child: Lakka was published as RetroArch v1.22.2 in its manifest, pack name and site page. lakka.yml records v6.1, the Lakka-LibreELEC tag its target list is read at. The MiSTer scraper refuses a BiosDB without a timestamp instead of writing an empty version. A pack's manifest.json records list_version, so an install from the pack alone knows it too. Manifests regenerated twice and compared: only version and generated changed.
This commit is contained in:
1 parent
1f6c018006
commit
25c356669b
37 files changed
+197
-52
No files matched your search
@@ -5,8 +5,8 @@
|
||||
"categorized": true,
|
||||
"platform": "amberelec",
|
||||
"display_name": "AmberELEC",
|
||||
"version": "1.0",
|
||||
"generated": "2026-10-26T22:11:28Z",
|
||||
"version": "prerelease-20261019_1835",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "batocera",
|
||||
"display_name": "Batocera",
|
||||
"version": "1.0",
|
||||
"version": "43.1",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"categorized": true,
|
||||
"platform": "bizhawk",
|
||||
"display_name": "BizHawk",
|
||||
"version": "1.0",
|
||||
"generated": "2026-10-26T22:11:28Z",
|
||||
"version": "2.11.1",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "Firmware",
|
||||
"detect": [
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "emudeck",
|
||||
"display_name": "EmuDeck",
|
||||
"version": "1.0",
|
||||
"version": "2.7EA",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "emuelec",
|
||||
"display_name": "EmuELEC",
|
||||
"version": "1.0",
|
||||
"version": "4.8",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "knulli",
|
||||
"display_name": "KNULLI",
|
||||
"version": "1.0",
|
||||
"version": "20260511",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "lakka",
|
||||
"display_name": "Lakka",
|
||||
"version": "1.0",
|
||||
"version": "v6.1",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "system",
|
||||
"detect": [
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@
|
||||
"categorized": true,
|
||||
"platform": "minui",
|
||||
"display_name": "MinUI",
|
||||
"version": "1.0",
|
||||
"generated": "2026-10-26T22:11:28Z",
|
||||
"version": "2025-11-27",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"categorized": true,
|
||||
"platform": "misterfpga",
|
||||
"display_name": "MiSTer FPGA",
|
||||
"version": "1.0",
|
||||
"generated": "2026-10-26T22:11:28Z",
|
||||
"version": "2026-09-29",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "games",
|
||||
"detect": [
|
||||
{
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"categorized": true,
|
||||
"platform": "myminui",
|
||||
"display_name": "MyMinUI",
|
||||
"version": "1.0",
|
||||
"generated": "2026-10-26T22:11:28Z",
|
||||
"version": "2026-08-09",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@
|
||||
"categorized": true,
|
||||
"platform": "nextui",
|
||||
"display_name": "NextUI",
|
||||
"version": "1.0",
|
||||
"generated": "2026-10-26T22:11:28Z",
|
||||
"version": "2026-10-20",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "recalbox",
|
||||
"display_name": "Recalbox",
|
||||
"version": "1.0",
|
||||
"version": "10.1.1",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "retroarch",
|
||||
"display_name": "RetroArch",
|
||||
"version": "1.0",
|
||||
"version": "v1.22.2",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "system",
|
||||
"detect": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "retrobat",
|
||||
"display_name": "RetroBat",
|
||||
"version": "1.0",
|
||||
"version": "8.3.1",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "retrodeck",
|
||||
"display_name": "RetroDECK",
|
||||
"version": "1.0",
|
||||
"version": "0.10.10b",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "retropie",
|
||||
"display_name": "RetroPie",
|
||||
"version": "1.0",
|
||||
"version": "4.8.12",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "BIOS",
|
||||
"detect": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"categorized": true,
|
||||
"platform": "rocknix",
|
||||
"display_name": "ROCKNIX",
|
||||
"version": "1.0",
|
||||
"version": "20261001",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@
|
||||
"categorized": true,
|
||||
"platform": "romm",
|
||||
"display_name": "RomM",
|
||||
"version": "1.0",
|
||||
"generated": "2026-10-26T22:11:28Z",
|
||||
"version": "5.4.0",
|
||||
"generated": "2026-10-27T10:27:58Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
{
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
inherits: retroarch
|
||||
platform: Lakka
|
||||
homepage: "https://www.lakka.tv"
|
||||
# Version is inherited from retroarch.yml (fetched dynamically by scraper)
|
||||
# Lakka-LibreELEC's release tag, the revision platforms/targets/lakka.yml
|
||||
# reads its cores at. A version is never inherited from retroarch.yml.
|
||||
version: v6.1
|
||||
# Lakka uses the same BIOS requirements as RetroArch
|
||||
@@ -67,7 +67,8 @@
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Version of the platform's own list this manifest was built from."
|
||||
"minLength": 1,
|
||||
"description": "Version of the platform's own list this manifest was built from, as the platform YAML records it (inherits: resolved): the release tag the scraper read (Batocera 43.1, Recalbox 10.1.1). A list kept on a branch with no release records what the scraper pinned instead: MinUI, MyMinUI and NextUI the date of the pinned commit, MiSTer the timestamp of the BiosDB it read. RetroArch and Lakka name the RetroArch release current when System.dat was read at its pinned commit, RetroPie the __version of RetroPie-Setup at its pinned commit."
|
||||
},
|
||||
"generated": {
|
||||
"type": "string",
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
"type": "object",
|
||||
"additionalProperties": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"list_version": {
|
||||
"description": "Version of the platform's list the pack was built from, the version of its install manifest. The installer compares it with the version the machine runs when it installs from the pack alone. The version key above numbers this file's format.",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"list_records": {
|
||||
"description": "What the platform's install list narrows by: the installer names that list as the remedy for --core or --region given with the pack alone only when it records them.",
|
||||
"type": "array",
|
||||
|
||||
@@ -235,6 +235,10 @@ def _inherited_yaml(platform_name: str, platforms_dir: str) -> tuple[dict, list[
|
||||
return config, [platform_name]
|
||||
|
||||
merged, chain = _inherited_yaml(config["inherits"], platforms_dir)
|
||||
# A version names one platform's release, never its parent's: Lakka
|
||||
# read as RetroArch v1.22.2 in its manifest, pack name and site page.
|
||||
# dat_version stays, it is the version of the inherited list itself.
|
||||
merged.pop("version", None)
|
||||
merged.update(
|
||||
{k: v for k, v in config.items() if k not in ("inherits", "overrides")}
|
||||
)
|
||||
|
||||
@@ -351,6 +351,23 @@ def _platform_pack_stem(
|
||||
return "_".join(_name_part(n) for n in names) + version_tag
|
||||
|
||||
|
||||
def platform_list_version(config: dict, platform: str) -> str:
|
||||
"""The version of the list a platform's YAML transcribes: the release
|
||||
tag the scraper read, or for a list kept on a branch with no release,
|
||||
the date of the commit it pinned. load_platform_config never passes a
|
||||
parent's version to a child, Lakka is not RetroArch v1.22.2.
|
||||
|
||||
The installer compares it with the version a machine runs, so a missing
|
||||
value is refused rather than written as a stand-in.
|
||||
"""
|
||||
version = str(config.get("version") or "").strip()
|
||||
if not version:
|
||||
raise ValueError(
|
||||
f"{platform}: the platform YAML records no version of its own"
|
||||
)
|
||||
return version
|
||||
|
||||
|
||||
# What the builder writes into a platform pack beside the files it carries.
|
||||
PACK_DOCUMENTS = ("README.txt", "manifest.json")
|
||||
|
||||
@@ -2568,6 +2585,9 @@ def _run_manifest_mode(
|
||||
alias_manifest["display_name"] = alias_cfg.get(
|
||||
"platform", alias_plat
|
||||
)
|
||||
alias_manifest["version"] = platform_list_version(
|
||||
alias_cfg, alias_plat
|
||||
)
|
||||
alias_manifest["base_destination"] = alias_cfg.get(
|
||||
"base_destination", ""
|
||||
)
|
||||
@@ -4600,7 +4620,7 @@ def generate_manifest(
|
||||
**({"no_game_data": True} if no_game_data else {}),
|
||||
"platform": platform_name,
|
||||
"display_name": platform_display,
|
||||
"version": "1.0",
|
||||
"version": platform_list_version(config, platform_name),
|
||||
"generated": now,
|
||||
"base_destination": base_dest,
|
||||
"detect": detect,
|
||||
@@ -4772,13 +4792,18 @@ def pack_systems(install_manifest: dict) -> dict:
|
||||
records.add("cores")
|
||||
if records or any("regions" in entry for entry in entries):
|
||||
records.add("regions")
|
||||
return {
|
||||
systems = {
|
||||
"files": {entry["dest"]: list(entry.get("systems") or [])
|
||||
for entry in files if "systems" in entry},
|
||||
"system_titles": dict(install_manifest.get("system_titles") or {}),
|
||||
"system_names": dict(install_manifest.get("system_names") or {}),
|
||||
"list_records": sorted(records),
|
||||
}
|
||||
# The version of the platform's list, which the installer compares with
|
||||
# the one the machine runs when it has the pack alone.
|
||||
if install_manifest.get("version"):
|
||||
systems["list_version"] = install_manifest["version"]
|
||||
return systems
|
||||
|
||||
|
||||
def annotate_pack_systems(manifest: dict, systems: dict | None) -> None:
|
||||
@@ -4793,8 +4818,9 @@ def annotate_pack_systems(manifest: dict, systems: dict | None) -> None:
|
||||
for key in ("system_titles", "system_names"):
|
||||
if systems.get(key):
|
||||
manifest[key] = systems[key]
|
||||
if "list_records" in systems:
|
||||
manifest["list_records"] = systems["list_records"]
|
||||
for key in ("list_records", "list_version"):
|
||||
if key in systems:
|
||||
manifest[key] = systems[key]
|
||||
|
||||
|
||||
def inject_manifest(zip_path: str, manifest: dict) -> None:
|
||||
|
||||
@@ -215,12 +215,12 @@ class Scraper(BaseScraper):
|
||||
if not entry["docs"]:
|
||||
del entry["docs"]
|
||||
|
||||
# The BiosDB has no release: the date it was built is the only
|
||||
# version the list carries, and the manifest needs one.
|
||||
timestamp = data.get("timestamp")
|
||||
released = (
|
||||
datetime.fromtimestamp(timestamp, timezone.utc).strftime("%Y-%m-%d")
|
||||
if isinstance(timestamp, (int, float))
|
||||
else ""
|
||||
)
|
||||
if not isinstance(timestamp, (int, float)):
|
||||
raise RuntimeError(f"{self.url}: the BiosDB records no timestamp")
|
||||
released = datetime.fromtimestamp(timestamp, timezone.utc).strftime("%Y-%m-%d")
|
||||
|
||||
return {
|
||||
"platform": "MiSTer FPGA",
|
||||
|
||||
@@ -2080,6 +2080,59 @@ def _git_paths(*args: str, stdin: list[str] | None = None) -> set[str] | None:
|
||||
return {p for p in result.stdout.split("\0") if p}
|
||||
|
||||
|
||||
class ManifestVersionIsThePlatformsOwn(unittest.TestCase):
|
||||
"""Every install manifest named its list "1.0", and an inheriting YAML
|
||||
took its parent's version: Lakka was published as RetroArch v1.22.2.
|
||||
The installer compares the list's version with the one a machine runs,
|
||||
so each manifest states the version its own platform YAML records."""
|
||||
|
||||
def setUp(self):
|
||||
from scripts.common import _platform_config_cache
|
||||
_platform_config_cache.clear()
|
||||
|
||||
def test_committed_manifests_state_their_platform_version(self):
|
||||
from scripts.common import load_platform_config
|
||||
manifests = sorted((ROOT / "install").glob("*.json"))
|
||||
self.assertTrue(manifests)
|
||||
for path in manifests:
|
||||
with self.subTest(manifest=path.name):
|
||||
data = json.loads(path.read_text())
|
||||
config = load_platform_config(data["platform"], str(ROOT / "platforms"))
|
||||
self.assertTrue(config.get("version"))
|
||||
self.assertEqual(data["version"], str(config["version"]))
|
||||
|
||||
def test_no_child_shows_its_parents_version(self):
|
||||
from scripts.common import load_platform_config
|
||||
platforms = ROOT / "platforms"
|
||||
children = {}
|
||||
for path in sorted(platforms.glob("*.yml")):
|
||||
raw = yaml.safe_load(path.read_text()) or {}
|
||||
if isinstance(raw, dict) and raw.get("inherits"):
|
||||
children[path.stem] = raw
|
||||
self.assertIn("lakka", children)
|
||||
for name, raw in children.items():
|
||||
with self.subTest(platform=name):
|
||||
parent = yaml.safe_load(
|
||||
(platforms / f"{raw['inherits']}.yml").read_text())
|
||||
version = load_platform_config(name, str(platforms)).get("version")
|
||||
self.assertEqual(version, raw.get("version"))
|
||||
self.assertNotEqual(version, parent.get("version"))
|
||||
|
||||
def test_an_unversioned_child_has_no_version(self):
|
||||
from scripts.common import load_platform_config
|
||||
with tempfile.TemporaryDirectory(dir=TMP_ROOT) as tmp:
|
||||
Path(tmp, "parent.yml").write_text("platform: P\nversion: '2.0'\nsystems: {}\n")
|
||||
Path(tmp, "child.yml").write_text("inherits: parent\nplatform: C\n")
|
||||
self.assertNotIn("version", load_platform_config("child", tmp))
|
||||
|
||||
def test_lakka_names_the_release_its_cores_are_read_at(self):
|
||||
platforms = ROOT / "platforms"
|
||||
lakka = yaml.safe_load((platforms / "lakka.yml").read_text())
|
||||
targets = yaml.safe_load((platforms / "targets" / "lakka.yml").read_text())
|
||||
tag = re.search(r"/blob/([^/]+)/", targets["source"]).group(1)
|
||||
self.assertEqual(lakka["version"], tag)
|
||||
|
||||
|
||||
class EveryManifestEntryIsFetchable(unittest.TestCase):
|
||||
"""An install manifest may not list a file the installer cannot get.
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ class ACoreFileFillsAFreeDeclaration(unittest.TestCase):
|
||||
self.emulators.mkdir()
|
||||
(self.platforms / "fakeplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "FakePlat",
|
||||
"version": "2.1",
|
||||
"verification_mode": "existence",
|
||||
"base_destination": "system",
|
||||
"cores": ["fakecore"],
|
||||
@@ -118,7 +119,7 @@ class AFileDeclaredUnderAnotherName(unittest.TestCase):
|
||||
(root / "platforms").mkdir()
|
||||
(root / "emulators").mkdir()
|
||||
(root / "platforms" / "fakeplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "FakePlat", "verification_mode": "existence",
|
||||
"platform": "FakePlat", "version": "2.1", "verification_mode": "existence",
|
||||
"base_destination": "system", "cores": ["gs"],
|
||||
"systems": {"apple-iigs": {"files": [
|
||||
{"name": "ROM1", "destination": "ROM1", "md5": md5},
|
||||
@@ -156,7 +157,7 @@ class AMissingDataDirectoryFailsTheRun(unittest.TestCase):
|
||||
(root / "emulators").mkdir()
|
||||
(root / "bios").mkdir()
|
||||
(root / "platforms" / "fakeplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "FakePlat", "verification_mode": "existence",
|
||||
"platform": "FakePlat", "version": "2.1", "verification_mode": "existence",
|
||||
"base_destination": "system", "cores": [],
|
||||
"systems": {"console-a": {"files": [], "data_directories": [
|
||||
{"ref": "assets", "destination": "assets"},
|
||||
@@ -197,7 +198,7 @@ class AFileNobodyHoldsIsAnOmission(unittest.TestCase):
|
||||
for folder in ("platforms", "emulators", "bios"):
|
||||
(root / folder).mkdir()
|
||||
(root / "platforms" / "fakeplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "FakePlat", "verification_mode": "existence",
|
||||
"platform": "FakePlat", "version": "2.1", "verification_mode": "existence",
|
||||
"base_destination": "system", "cores": ["devil"],
|
||||
"systems": {"diablo": {"files": []}},
|
||||
}))
|
||||
@@ -238,7 +239,7 @@ class AMemberNameIsNotALooseFile(unittest.TestCase):
|
||||
(root / "platforms").mkdir()
|
||||
(root / "emulators").mkdir()
|
||||
(root / "platforms" / "fakeplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "FakePlat", "verification_mode": "existence",
|
||||
"platform": "FakePlat", "version": "2.1", "verification_mode": "existence",
|
||||
"base_destination": "system", "cores": ["naomi2core"],
|
||||
"systems": {"sega-naomi2": {"files": []}},
|
||||
}))
|
||||
@@ -283,7 +284,7 @@ class TwoDeclarationsOfOnePath(unittest.TestCase):
|
||||
for folder in ("platforms", "emulators"):
|
||||
(root / folder).mkdir()
|
||||
(root / "platforms" / "fakeplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "FakePlat", "verification_mode": "existence",
|
||||
"platform": "FakePlat", "version": "2.1", "verification_mode": "existence",
|
||||
"base_destination": "system", "cores": [],
|
||||
"systems": {
|
||||
"a-system": {"files": [{"name": first, "destination": "shared.bin"}]},
|
||||
@@ -335,7 +336,7 @@ class ANamelessWhitelistEntry(unittest.TestCase):
|
||||
(root / folder).mkdir()
|
||||
values = [md5.upper(), f"{'0' * 32},{md5}", "f" * 32]
|
||||
(root / "platforms" / "fakeplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "FakePlat", "verification_mode": "md5",
|
||||
"platform": "FakePlat", "version": "2.1", "verification_mode": "md5",
|
||||
"base_destination": "bios", "cores": [],
|
||||
"systems": {"sony-playstation": {"files": [
|
||||
{"name": f"sony-playstation:{v}", "destination": "", "md5": v}
|
||||
|
||||
@@ -76,7 +76,7 @@ class _Collection(unittest.TestCase):
|
||||
}}
|
||||
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
||||
self.config = {
|
||||
"platform": "Exist", "verification_mode": "existence",
|
||||
"platform": "Exist", "version": "2.1", "verification_mode": "existence",
|
||||
"cores": ["sized", "unsized"],
|
||||
"systems": {"mac": {"files": []}, "iigs": {"files": []}},
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ files:
|
||||
|
||||
PLATFORM = {
|
||||
"platform": "Demo",
|
||||
"version": "2.1",
|
||||
"verification_mode": "existence",
|
||||
"base_destination": "",
|
||||
"cores": ["demo"],
|
||||
|
||||
@@ -224,6 +224,7 @@ class TestE2E(unittest.TestCase):
|
||||
def _create_existence_platform(self):
|
||||
config = {
|
||||
"platform": "TestExistence",
|
||||
"version": "9.1",
|
||||
"verification_mode": "existence",
|
||||
"base_destination": "system",
|
||||
"systems": {
|
||||
@@ -3676,6 +3677,51 @@ class TestE2E(unittest.TestCase):
|
||||
self.assertIsInstance(f["size"], int)
|
||||
self.assertGreater(len(f["sha1"]), 0)
|
||||
|
||||
def test_91_manifest_version_is_the_platform_list_version(self):
|
||||
"""The manifest names the version of the list it was built from.
|
||||
|
||||
It was the constant "1.0" for every platform, so the installer could
|
||||
not tell which Batocera or Recalbox release a list described. Two
|
||||
platforms of different versions show the value comes from each YAML.
|
||||
A YAML without one, an inheriting child included, is refused rather
|
||||
than written with a stand-in or its parent's version.
|
||||
"""
|
||||
from common import _platform_config_cache
|
||||
from generate_pack import generate_manifest
|
||||
|
||||
registry_path = os.path.join(self.platforms_dir, "_test_registry_version.yml")
|
||||
with open(registry_path, "w") as fh:
|
||||
yaml.dump({"platforms": {}}, fh)
|
||||
with open(os.path.join(self.platforms_dir, "test_md5.yml")) as fh:
|
||||
config = yaml.safe_load(fh)
|
||||
config["version"] = "41"
|
||||
with open(os.path.join(self.platforms_dir, "versioned_md5.yml"), "w") as fh:
|
||||
yaml.dump(config, fh)
|
||||
del config["version"]
|
||||
with open(os.path.join(self.platforms_dir, "unversioned.yml"), "w") as fh:
|
||||
yaml.dump(config, fh)
|
||||
_platform_config_cache.clear()
|
||||
|
||||
def version_of(name: str) -> str:
|
||||
return generate_manifest(
|
||||
name, self.platforms_dir, self.db, self.bios_dir, registry_path,
|
||||
emulators_dir=self.emulators_dir, offline=True,
|
||||
)["version"]
|
||||
|
||||
self.assertEqual(version_of("test_existence"), "9.1")
|
||||
self.assertEqual(version_of("versioned_md5"), "41")
|
||||
for name in ("unversioned", "test_inherited"):
|
||||
with self.subTest(platform=name), \
|
||||
self.assertRaisesRegex(ValueError, "records no version"):
|
||||
version_of(name)
|
||||
with open(os.path.join(self.platforms_dir, "test_inherited.yml")) as fh:
|
||||
child = yaml.safe_load(fh)
|
||||
child["version"] = "2"
|
||||
with open(os.path.join(self.platforms_dir, "test_inherited.yml"), "w") as fh:
|
||||
yaml.dump(child, fh)
|
||||
_platform_config_cache.clear()
|
||||
self.assertEqual(version_of("test_inherited"), "2")
|
||||
|
||||
def test_91b_manifest_hash_points_at_a_fetchable_file(self):
|
||||
"""A declared hash no local file carries must not blank repo_path.
|
||||
|
||||
@@ -5726,6 +5772,7 @@ struct BurnDriver BurnDrvneogeo = {
|
||||
self.db = self._build_db()
|
||||
config = {
|
||||
"platform": "RegionPlat",
|
||||
"version": "3.0",
|
||||
"verification_mode": "existence",
|
||||
"systems": {
|
||||
"region-console": {
|
||||
|
||||
@@ -47,6 +47,7 @@ class FrontendDigestDecides(unittest.TestCase):
|
||||
)
|
||||
(self.platforms / "digestplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "DigestPlat",
|
||||
"version": "2.1",
|
||||
"verification_mode": "md5",
|
||||
"base_destination": "bios",
|
||||
"systems": {"psx": {"files": [{
|
||||
|
||||
@@ -1021,7 +1021,7 @@ class AHeldFileTheInstallerCannotFetch(unittest.TestCase):
|
||||
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
||||
Path("platforms").mkdir()
|
||||
Path("platforms/p.yml").write_text(json.dumps({
|
||||
"platform": "P", "verification_mode": "existence", "cores": ["core"],
|
||||
"platform": "P", "version": "2.1", "verification_mode": "existence", "cores": ["core"],
|
||||
"systems": {"sys": {"files": []}},
|
||||
}))
|
||||
Path("platforms/_registry.yml").write_text(
|
||||
@@ -1096,7 +1096,7 @@ class AStandaloneLayoutBelowTheBiosFolder(unittest.TestCase):
|
||||
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
||||
Path("platforms").mkdir()
|
||||
Path("platforms/p.yml").write_text(json.dumps({
|
||||
"platform": "P", "verification_mode": "existence",
|
||||
"platform": "P", "version": "2.1", "verification_mode": "existence",
|
||||
"base_destination": "bios", "cores": ["dsa", "other"],
|
||||
"standalone_cores": ["dsa"], "systems": {"sys": {"files": []}},
|
||||
}))
|
||||
|
||||
@@ -193,6 +193,7 @@ class PackPlacesCoreFilesUnderTheTag(unittest.TestCase):
|
||||
|
||||
platform = {
|
||||
"platform": "MinUI Test",
|
||||
"version": "2025-11-27",
|
||||
"base_destination": "",
|
||||
"verification_mode": "existence",
|
||||
"cores": ["gambatte", "arcadecore", "unlisted"],
|
||||
|
||||
@@ -92,7 +92,7 @@ class _Fixture(unittest.TestCase):
|
||||
for key, profile in PROFILES.items():
|
||||
(self.emulators / f"{key}.yml").write_text(yaml.dump(profile))
|
||||
platform = {
|
||||
"platform": "Handheld", "verification_mode": "existence",
|
||||
"platform": "Handheld", "version": "2.1", "verification_mode": "existence",
|
||||
"cores": ["emu", "doomcore"],
|
||||
"systems": {
|
||||
"console": {"files": [{"name": "firmware.rom", "destination": "firmware.rom"}]},
|
||||
|
||||
@@ -52,6 +52,7 @@ files:
|
||||
|
||||
PLATFORM = {
|
||||
"platform": "Demo",
|
||||
"version": "2.1",
|
||||
"verification_mode": "existence",
|
||||
"base_destination": "",
|
||||
"cores": ["demo"],
|
||||
@@ -494,7 +495,7 @@ class RefusedFilesAreNotPresent(unittest.TestCase):
|
||||
}
|
||||
db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
||||
config = {
|
||||
"platform": "Hashy", "verification_mode": "md5", "base_destination": "bios",
|
||||
"platform": "Hashy", "version": "2.1", "verification_mode": "md5", "base_destination": "bios",
|
||||
"systems": {"sys": {"files": [
|
||||
{"name": "good.bin", "destination": "good.bin",
|
||||
"md5": hashlib.md5(b"good.bin").hexdigest()},
|
||||
|
||||
@@ -51,6 +51,7 @@ class RequiredTwins(unittest.TestCase):
|
||||
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
||||
platform = {
|
||||
"platform": "Twins",
|
||||
"version": "2.1",
|
||||
"verification_mode": "md5",
|
||||
"base_destination": "bios",
|
||||
"cores": [],
|
||||
|
||||
@@ -243,7 +243,7 @@ class _Fixture(unittest.TestCase):
|
||||
"required": False}]}
|
||||
for name in ("testra", "testnosave"):
|
||||
(self.platforms / f"{name}.yml").write_text(yaml.safe_dump({
|
||||
"platform": name, "verification_mode": "existence",
|
||||
"platform": name, "version": "2.1", "verification_mode": "existence",
|
||||
"base_destination": "system", "cores": ["corex"],
|
||||
"systems": {"test-console": system},
|
||||
}))
|
||||
@@ -399,7 +399,7 @@ class AFolderPerSystem(_Fixture):
|
||||
"required": False}]}
|
||||
for name in ("testbato", "testrb"):
|
||||
(self.platforms / f"{name}.yml").write_text(yaml.safe_dump({
|
||||
"platform": name, "verification_mode": "existence",
|
||||
"platform": name, "version": "2.1", "verification_mode": "existence",
|
||||
"base_destination": "bios", "cores": ["corex", "corey"],
|
||||
"systems": {"test-console": system},
|
||||
# Two systems run CoreX, none runs CoreY.
|
||||
|
||||
@@ -58,6 +58,7 @@ class SlugPlatform(unittest.TestCase):
|
||||
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
||||
self.config = {
|
||||
"platform": "Slugs",
|
||||
"version": "2.1",
|
||||
"verification_mode": "md5",
|
||||
"base_destination": "bios",
|
||||
"cores": ["dosbox"],
|
||||
@@ -139,7 +140,7 @@ class RegionKeysForEveryClaimant(unittest.TestCase):
|
||||
)
|
||||
common._emulator_profiles_cache.clear()
|
||||
profiles = common.load_emulator_profiles("emulators")
|
||||
config = {"platform": "P", "verification_mode": "existence", "cores": ["one", "two"],
|
||||
config = {"platform": "P", "version": "2.1", "verification_mode": "existence", "cores": ["one", "two"],
|
||||
"systems": {"sys": {"files": []}}}
|
||||
_groups, extra_dests = platform_region_groups(
|
||||
config, config["systems"], "emulators", db, "", profiles
|
||||
@@ -178,7 +179,7 @@ class FlatFirmwareFolder(unittest.TestCase):
|
||||
}
|
||||
db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
||||
config = {
|
||||
"platform": "Flat", "verification_mode": "md5",
|
||||
"platform": "Flat", "version": "2.1", "verification_mode": "md5",
|
||||
"base_destination": "bios", "cores": ["psx"],
|
||||
"systems": {
|
||||
"psx": {"files": [{"name": "scph5501.bin",
|
||||
@@ -300,7 +301,7 @@ class OnePathCountsOnce(unittest.TestCase):
|
||||
common._emulator_profiles_cache.clear()
|
||||
self.addCleanup(common._emulator_profiles_cache.clear)
|
||||
profiles = common.load_emulator_profiles("emulators")
|
||||
config = {"platform": "P", "verification_mode": "existence", "cores": ["one", "two"],
|
||||
config = {"platform": "P", "version": "2.1", "verification_mode": "existence", "cores": ["one", "two"],
|
||||
"systems": {"amiga": {"files": []}}}
|
||||
report = verify_platform(config, db, "emulators", profiles)
|
||||
claims = [u for u in report["undeclared_files"] if u["name"] == "rom.key"]
|
||||
|
||||
Reference in new issue
Block a user