chore: merge integ installable fix

This commit is contained in:
Abdessamad Derraz committed 2026-11-09 22:32:23 +01:00
commit c77aa7eed6
5 files changed
+84 -58

No files matched your search

+27 -29
View File
@@ -2771,19 +2771,6 @@ def system_dir_path(entry: dict, path: str) -> str:
return f"{directory}/{path}" if directory else path
def launched_both_ways(config: dict) -> set[str]:
"""The names a platform runs as a standalone emulator and as a core.
``dual_mode_cores`` names those its frontend offers both ways. A name it
gives a standalone emulator only, whose buildbot core its RetroArch can
download (``installable_cores``), runs both ways too: Batocera's x86_64
RetroArch installs the amiberry core beside its own standalone Amiberry.
"""
standalone = {str(c) for c in config.get("standalone_cores") or []}
installable = {str(c) for c in config.get("installable_cores") or []}
return {str(c) for c in config.get("dual_mode_cores") or []} | (standalone & installable)
def own_build_tags(config: dict, standalone: set[str]) -> set[str]:
"""The standalone names the platform's own builds answer to, tagged.
@@ -2810,7 +2797,16 @@ def standalone_set(config: dict) -> set[str]:
same set, tagged, so every reader of standalone_cores sees them.
"""
names = {str(c) for c in config.get("standalone_cores") or []}
names |= {DUAL_MODE_PREFIX + c for c in launched_both_ways(config)}
names |= {DUAL_MODE_PREFIX + str(c) for c in config.get("dual_mode_cores") or []}
# A buildbot core the platform's RetroArch installs under the name of an
# emulator it runs standalone is that emulator's libretro build: run
# both ways, as Batocera runs amiberry standalone and can fetch
# amiberry_libretro.
names |= {
DUAL_MODE_PREFIX + str(c)
for c in set(map(str, config.get("installable_cores") or []))
& set(map(str, config.get("standalone_cores") or []))
}
names |= own_build_tags(config, names)
# The system directory each core is handed travels the same way, so
# platform_layouts places a core's files below it for every reader.
@@ -3310,24 +3306,26 @@ def resolve_platform_cores(
# A name the platform launches both ways designates its libretro
# build too. Batocera, Recalbox and RetroBat run pcsx2 standalone and
# as LRPS2, two profiles: the key match kept the standalone one and
# LRPS2's files never reached their packs.
dual_names = {str(c) for c in config.get("dual_mode_cores") or []}
both_ways = {
profile: c
for c in sorted(launched_both_ways(config))
for profile in index.get(c, set())
if "libretro" in str(profiles[profile].get("type", ""))
and not profiles[profile].get("built_by")
and not replaced_by_own(profile, profiles[profile], libretro_only=True)
}
# LRPS2's files never reached their packs. A core its RetroArch
# installs is a libretro build as well (amiberry's buildbot core
# beside Batocera's standalone amiberry).
def libretro_builds(name: object) -> set[str]:
return {
profile
for profile in index.get(str(name), set())
if "libretro" in str(profiles[profile].get("type", ""))
and not profiles[profile].get("built_by")
and not replaced_by_own(profile, profiles[profile], libretro_only=True)
}
dual = {p for c in config.get("dual_mode_cores") or [] for p in libretro_builds(c)}
# A core reached only through the RetroArch downloader runs on the
# boards whose downloader offers it: Batocera's x86_64 RetroArch
# installs the amiberry core, its armv7 and aarch64 boards cannot.
downloaded_only = {
profile: c for profile, c in both_ways.items()
if c not in dual_names and profile not in result
}
result |= set(both_ways)
for c in config.get("installable_cores") or []:
for profile in libretro_builds(c) - dual - result:
downloaded_only.setdefault(profile, str(c))
result |= dual | set(downloaded_only)
# Support "all_libretro" as a list element: combines all libretro
# profiles with explicitly listed standalone cores (e.g. RetroDECK
# ships RetroArch + standalone emulators)
+8 -11
View File
@@ -14,7 +14,7 @@ import re
import sys
import urllib.error
import urllib.request
from collections.abc import Callable, Iterable
from collections.abc import Callable
from pathlib import Path
@@ -558,26 +558,23 @@ def boards_build(selection: BuildSelection, launchers: list[dict]) -> Callable[[
def installable_cores(
selection: BuildSelection,
cores: list[str],
standalone: Iterable[str] = (),
dual: Iterable[str] = (),
selection: BuildSelection, cores: list[str], standalone: list[str], dual: list[str],
) -> list[str]:
"""Buildbot cores a board's RetroArch core downloader installs, beyond
the cores the image builds.
the libretro cores the image builds.
The targets scraper names, per board, the RetroArch targets entry its
downloader reads (`downloads`): a Batocera x86_64 board installs any
core of linux-x86_64, an armv7 one any of linux-armhf. A name the image
gives a standalone emulator only (Batocera's amiberry, cemu, xemu) is
not that core: the buildbot one stays installable.
core of linux-x86_64, an armv7 one any of linux-armhf. A name compares
within its build mode: amiberry built standalone is another program
than amiberry_libretro, which the buildbot serves.
"""
found: set[str] = set()
for entry in selection.targets.values():
if entry.get("downloads"):
found |= load_target_config("retroarch", entry["downloads"]) or set()
standalone_only = set(standalone) - set(dual)
return sorted(found - (set(cores) - standalone_only))
built_libretro = (set(cores) - set(standalone)) | set(dual)
return sorted(found - built_libretro)
def records_run(launchers: list[dict], built: Callable[[str], bool]) -> list[dict]:
+12 -10
View File
@@ -3304,30 +3304,32 @@ class TestBumpCommit(unittest.TestCase):
self.assertNotIn("uphead", text)
def test_a_profile_one_platform_ships_waits_for_its_build(self):
"""EmuELEC alone ships RigelEngine and builds its package.mk
PKG_VERSION. A bulk advance moved fheroes2 and supertux past that
build, and rigelengine is a commit ahead of it already."""
"""KNULLI alone ships advanced_drastic and builds its
advanced_drastic.mk version. A bulk advance moved fheroes2 and
supertux past the build EmuELEC then pinned, and a pin ahead of the
one build a platform ships describes nothing anyone runs."""
root = Path(__file__).resolve().parents[1]
path = Path(self.tmp.name) / "rigelengine.yml"
path = Path(self.tmp.name) / "advanced_drastic.yml"
path.write_text(
SAMPLE.replace("\nnotes:", "\ntype: standalone\ncores: [rigelengine, RigelEngine]\n\nnotes:", 1),
SAMPLE.replace(
"\nnotes:", "\ntype: standalone\ncores: [advanced_drastic]\n\nnotes:", 1),
encoding="utf-8",
)
report = ProfileReport(
name="rigelengine", repo="o/n", pin="pin", head="newhead", entries=[],
name="advanced_drastic", repo="o/n", pin="pin", head="newhead", entries=[],
counts={}, skipped=profile_sync.NO_SOURCE_REF,
)
platforms = str(root / "platforms")
self.assertEqual(
profile_sync.shipping_platforms("rigelengine", self.tmp.name, platforms),
["emuelec"],
profile_sync.shipping_platforms("advanced_drastic", self.tmp.name, platforms),
["knulli"],
)
with contextlib.redirect_stderr(io.StringIO()) as err:
self.assertFalse(bump_commit(path, report, platforms_dir=platforms))
self.assertIn("only emuelec ships it", err.getvalue())
self.assertIn("only knulli ships it", err.getvalue())
path.write_text(
path.read_text(encoding="utf-8")
+ 'pin_follows: "EmuELEC builds the branch tip"\n',
+ 'pin_follows: "KNULLI builds the branch tip"\n',
encoding="utf-8",
)
self.assertTrue(bump_commit(path, report, platforms_dir=platforms))
+3 -2
View File
@@ -657,7 +657,6 @@ class AmiberryOnEachPlatform(unittest.TestCase):
self.assertNotIn("unplaced", entry)
self.assertEqual(entry["standalone_path"], f"{folder}/{layout}")
def test_retrobat_reads_its_folders_below_the_amiberry_emulator_folder(self) -> None:
# RetroBat writes rom_path and whdboot_path below the amiberry
# folder of its install and copies the kickstarts it finds in bios
@@ -681,7 +680,9 @@ class AmiberryOnEachPlatform(unittest.TestCase):
class AmiberryBuildEachPlatformShips(unittest.TestCase):
"""Each platform resolves the name amiberry to the build its own package
compiles. RetroBat keeps the 8.5.0 libretro core beside its standalone."""
compiles. RetroBat keeps the 8.5.0 libretro core beside its standalone,
and Batocera's x86_64 boards fetch it with RetroArch's core downloader
(installable_cores)."""
OWN = {
"rocknix": {"amiberry-5.6.5"},
+34 -6
View File
@@ -298,13 +298,41 @@ class CoreDownloaderReach(unittest.TestCase):
fetched |= load_target_config("retroarch", entry["downloads"], root) or set()
if entry["architecture"] == "aarch64":
self.assertNotIn("downloads", entry)
# A name the image gives a standalone emulator only is not the
# buildbot core of that name, which stays installable.
standalone_only = set(config.get("standalone_cores") or []) - set(
config.get("dual_mode_cores") or [])
with self.subTest(platform=platform):
self.assertEqual(set(config["installable_cores"]),
fetched - (set(config["cores"]) - standalone_only))
built = ((set(config["cores"]) - set(config.get("standalone_cores") or []))
| set(config.get("dual_mode_cores") or []))
self.assertEqual(set(config["installable_cores"]), fetched - built)
def test_a_standalone_name_keeps_its_buildbot_core(self):
"""Batocera runs amiberry standalone, and its x86_64 boards fetch
amiberry_libretro: removing every name the image builds lost the
libretro core to the name it shares with the standalone package."""
from common import DUAL_MODE_PREFIX, resolve_platform_cores, standalone_set # noqa: PLC0415
from scraper.batocera_scraper import installable_cores # noqa: PLC0415
from scraper.targets.batocera_targets_scraper import BuildSelection # noqa: PLC0415
selection = BuildSelection(
targets={"x86_64": {"architecture": "x86_64", "cores": [],
"downloads": "linux-x86_64"}},
emulators=frozenset(), listed=frozenset(), symbols=frozenset(), packages={},
)
found = installable_cores(selection, ["amiberry", "mgba", "dolphin"],
["amiberry", "dolphin"], ["dolphin"])
self.assertIn("amiberry", found)
self.assertNotIn("mgba", found)
self.assertNotIn("dolphin", found)
profiles = {
"amiberry": {"type": "libretro", "cores": ["amiberry"], "systems": ["amiga"]},
"amiberry-7": {"type": "standalone", "cores": ["amiberry"], "systems": ["amiga"],
"built_by": ["demo"], "source": "https://x/amiberry"},
}
config = {"_key": "demo", "cores": ["amiberry"], "standalone_cores": ["amiberry"],
"installable_cores": ["amiberry"]}
self.assertEqual(resolve_platform_cores(config, profiles), {"amiberry", "amiberry-7"})
self.assertEqual(resolve_platform_cores({**config, "installable_cores": []}, profiles),
{"amiberry-7"})
self.assertIn(DUAL_MODE_PREFIX + "amiberry", standalone_set(config))
class KnulliPerBoard(unittest.TestCase):