feat: a platform package can differ from upstream

bundled describes the emulator's own release, and a platform package can differ both ways: Batocera's hcl package installs the binary alone and sends users to fetch the data, while its blueMSX core package copies the machines and databases beside the core. not_bundled_on and installed_on name those platforms, and the builder reads them through one rule.
This commit is contained in:
Abdessamad Derraz committed 2026-10-20 06:11:10 +02:00
1 parent 36e30beac0
commit f7d57dd91d
6 files changed
+77 -4

No files matched your search

+20
View File
@@ -276,6 +276,16 @@
"type": "boolean",
"description": "Installed with the emulator for the build mode names, so packs leave the tree out."
},
"installed_on": {
"type": "array",
"items": {"type": "string"},
"description": "Platforms (registry keys) whose own package installs this beside the emulator, so their packs leave it out."
},
"not_bundled_on": {
"type": "array",
"items": {"type": "string"},
"description": "Platforms (registry keys) whose package leaves out a file the emulator's release bundles, so their packs bring it."
},
"source_ref": {
"type": "string"
}
@@ -450,6 +460,16 @@
"type": "boolean",
"description": "Installed with the emulator for the build mode names (all builds when mode is absent): already on the user's machine, so packs and install manifests leave it out."
},
"installed_on": {
"type": "array",
"items": {"type": "string"},
"description": "Platforms (registry keys) whose own package installs this beside the emulator, so their packs leave it out."
},
"not_bundled_on": {
"type": "array",
"items": {"type": "string"},
"description": "Platforms (registry keys) whose package leaves out a file the emulator's release bundles, so their packs bring it."
},
"config_key": {
"type": "string"
},
+3
View File
@@ -353,6 +353,9 @@ def load_platform_config(platform_name: str, platforms_dir: str = "platforms") -
for sys_id, system in config.get("systems", {}).items()
}
# The registry key, which per-platform profile fields (installed_on,
# not_bundled_on) name: the display name differs (MiSTer FPGA).
config["_key"] = platform_name
_platform_config_cache[cache_key] = config
return config
+19 -2
View File
@@ -525,7 +525,21 @@ def filter_files_by_mode(files: list[dict], standalone: bool) -> list[dict]:
return result
def deliverable(entries: list[dict], standalone: bool) -> list[dict]:
def installed_with_emulator(entry: dict, platform: str = "") -> bool:
"""Whether the emulator as this platform installs it already brings the entry.
`bundled` describes the emulator's own release. A platform package can
differ both ways: Batocera's hcl package installs the binary alone and
sends users to fetch the data (`not_bundled_on`), while its blueMSX core
package copies the machines and databases beside the core
(`installed_on`).
"""
if platform and platform in (entry.get("installed_on") or []):
return True
return bool(entry.get("bundled")) and platform not in (entry.get("not_bundled_on") or [])
def deliverable(entries: list[dict], standalone: bool, platform: str = "") -> list[dict]:
"""The entries of one build a pack has to bring.
A file or tree installed with the emulator is already on the user's
@@ -533,7 +547,10 @@ def deliverable(entries: list[dict], standalone: bool) -> list[dict]:
`mode` like any entry, so PPSSPP's assets, shipped by the standalone
release and not by the libretro core, still reach a RetroArch pack.
"""
return [e for e in filter_files_by_mode(entries, standalone) if not e.get("bundled")]
return [
e for e in filter_files_by_mode(entries, standalone)
if not installed_with_emulator(e, platform)
]
def find_validated_variant(
+2 -1
View File
@@ -96,6 +96,7 @@ from validation import (
check_file_validation,
deliverable,
filter_files_by_mode,
installed_with_emulator,
outside_gap_scope,
)
@@ -650,7 +651,7 @@ def find_undeclared_files(
"path": dest,
"required": f.get("required", False),
"hle_fallback": f.get("hle_fallback", False),
"bundled": f.get("bundled", False),
"bundled": installed_with_emulator(f, config.get("_key", "")),
"category": f.get("category", "bios"),
"in_repo": in_repo,
"note": f.get("note", ""),
+3 -1
View File
@@ -80,7 +80,9 @@ class BundledHashIsProof(unittest.TestCase):
wrong = []
for name, profile in sorted(load_emulator_profiles("emulators", skip_aliases=False).items()):
for entry in profile.get("files") or []:
if not entry.get("bundled") or entry.get("unsourceable"):
# A bundled entry is packed only where a platform's package
# leaves it out: there the copy has to be the declared bytes.
if not entry.get("not_bundled_on") or entry.get("unsourceable"):
continue
if not any(entry.get(k) for k in ("sha1", "md5", "sha256", "crc32")):
continue
+30
View File
@@ -4579,6 +4579,36 @@ class BundledFilesAreNotToSource(unittest.TestCase):
["ppsspp-assets"])
self.assertEqual(deliverable(entries, True), [])
def test_a_platform_package_can_differ_both_ways(self):
"""Batocera's hcl package installs the binary alone, its blueMSX core
package copies the machines beside the core."""
sys.path.insert(0, str(ROOT / "scripts"))
from validation import installed_with_emulator
hcl = {"name": "data.pak", "bundled": True, "not_bundled_on": ["batocera"]}
machines = {"name": "Machines/MSX/config.ini", "installed_on": ["batocera", "retropie"]}
self.assertTrue(installed_with_emulator(hcl, "retrobat"))
self.assertFalse(installed_with_emulator(hcl, "batocera"))
self.assertTrue(installed_with_emulator(machines, "retropie"))
self.assertFalse(installed_with_emulator(machines, "retroarch"))
self.assertTrue(installed_with_emulator(hcl))
def test_every_platform_named_is_registered(self):
sys.path.insert(0, str(ROOT / "scripts"))
from common import list_registered_platforms, load_emulator_profiles
known = set(list_registered_platforms(str(ROOT / "platforms"), include_archived=True))
unknown = sorted({
(name, platform)
for name, profile in load_emulator_profiles(str(ROOT / "emulators")).items()
for entry in (profile.get("files") or []) + (profile.get("data_directories") or [])
if isinstance(entry, dict)
for field in ("installed_on", "not_bundled_on")
for platform in entry.get(field) or []
if platform not in known
})
self.assertEqual(unknown, [])
def test_the_pack_builder_skips_it(self):
source = (ROOT / "scripts" / "packextras.py").read_text(encoding="utf-8")
self.assertIn('if u.get("bundled"):', source)