diff --git a/platforms/knulli.yml b/platforms/knulli.yml index 2bbbad334..63aadbd72 100644 --- a/platforms/knulli.yml +++ b/platforms/knulli.yml @@ -5662,9 +5662,10 @@ launchers: depends_on_option: "bootdisk (not (messSysName[messMode] == '' or messMode == -1)\ \ and softList == '' and system.name == 'macintosh' and system.isOptSet('bootdisk')\ \ and not (system.config['bootdisk'] in ['macos30', 'macos608', 'macos701', 'macos75']))" + choices_from: "package/emulationstation/knulli-es-system/es_features.yml:11037-11043" source_ref: "package/system/knulli-configgen/configgen/configgen/generators/mame/mameGenerator.py:303-305,\ - \ 375-379, 384-385, package/emulationstation/knulli-es-system/es_features.yml:11037-11043" -- emulator: mame, mess, mamevirtual, same_cdi + \ 375-379, 384-385" +- emulator: mame build: libretro kind: fixed_name names: @@ -5685,7 +5686,7 @@ launchers: \ in ['macos30', 'macos608', 'macos701', 'macos75'])" source_ref: "package/system/knulli-configgen/configgen/configgen/generators/libretro/libretroMAMEConfig.py:64,\ \ 123, 197, 265-268, 270, 274" -- emulator: mame, mess, mamevirtual, same_cdi +- emulator: mame build: libretro kind: fixed_name names: @@ -5704,8 +5705,9 @@ launchers: \ 'plugnplay', 'vis']) and not (messSysName[messMode] == '') and not (softList\ \ != '') and system.name == 'macintosh' and system.isOptSet('bootdisk') and not\ \ (system.config['bootdisk'] in ['macos30', 'macos608', 'macos701', 'macos75']))" + choices_from: "package/emulationstation/knulli-es-system/es_features.yml:3727-3733" source_ref: "package/system/knulli-configgen/configgen/configgen/generators/libretro/libretroMAMEConfig.py:64,\ - \ 123, 197, 265-268, 273-274, package/emulationstation/knulli-es-system/es_features.yml:3727-3733" + \ 123, 197, 265-268, 273-274" - emulator: dolphin build: standalone kind: fixed_name diff --git a/platforms/retrobat.yml b/platforms/retrobat.yml index 185be4204..290d649fa 100644 --- a/platforms/retrobat.yml +++ b/platforms/retrobat.yml @@ -4259,7 +4259,8 @@ launchers: passes_to: "settings.ini [BIOS] PathNTSCJ = PathNTSCU = PathPAL = " fails_when_missing: not checked by the launcher depends_on_option: duck_bios - source_ref: "emulatorLauncher/Generators/Duckstation.Generator.cs:197-202, .emulationstation/es_features.cfg:12489-12497" + choices_from: ".emulationstation/es_features.cfg:12489-12497" + source_ref: "emulatorLauncher/Generators/Duckstation.Generator.cs:197-202" - emulator: eka2l1 build: standalone kind: passes_path @@ -4599,7 +4600,8 @@ launchers: passes_to: "hatari.cfg [ROM] szTosImageFileName=/hatari/tos/" fails_when_missing: ApplicationException 'Missing TOS file in 'bios' folder.' depends_on_option: hatari_tos - source_ref: "emulatorLauncher/Generators/Hatari.Generator.cs:410-415, 454, .emulationstation/es_features.cfg:13768-13774" + choices_from: ".emulationstation/es_features.cfg:13768-13774" + source_ref: "emulatorLauncher/Generators/Hatari.Generator.cs:410-415, 454" - emulator: hatari build: standalone kind: fixed_name @@ -4639,7 +4641,8 @@ launchers: passes_to: hatari_tosimage = , if the file is there | default fails_when_missing: hatari_tosimage = default depends_on_option: hatari2014_tos - source_ref: "emulatorLauncher/Generators/LibRetro.CoreOptions.cs:3409-3417, .emulationstation/es_features.cfg:7095-7102" + choices_from: ".emulationstation/es_features.cfg:7095-7102" + source_ref: "emulatorLauncher/Generators/LibRetro.CoreOptions.cs:3409-3417" - emulator: hatarib build: libretro kind: fixed_name @@ -4667,8 +4670,8 @@ launchers: passes_to: hatarib_tos = hatarib/ fails_when_missing: hatarib_tos = , or when bios holds it depends_on_option: hatarib_tos - source_ref: "emulatorLauncher/Generators/LibRetro.CoreOptions.cs:3434-3435, 3457-3474,\ - \ .emulationstation/es_features.cfg:7125-7134" + choices_from: ".emulationstation/es_features.cfg:7125-7134" + source_ref: "emulatorLauncher/Generators/LibRetro.CoreOptions.cs:3434-3435, 3457-3474" - emulator: hatarib build: libretro kind: copies @@ -4885,7 +4888,8 @@ launchers: fails_when_missing: falls back to dsi_nand.bin depends_on_option: melonds_console == "dsi", melonds_nandregion set, rom extension not ".bin" - source_ref: "emulatorLauncher/Generators/MelonDS.Generator.cs:193-202, .emulationstation/es_features.cfg:16816-16823" + choices_from: ".emulationstation/es_features.cfg:16816-16823" + source_ref: "emulatorLauncher/Generators/MelonDS.Generator.cs:193-202" - emulator: mesen build: standalone kind: copies @@ -5081,7 +5085,8 @@ launchers: passes_to: "kronos.ini [1.0] General\\Bios = /, only if the file exists" fails_when_missing: General\Bios not written depends_on_option: kronos_force_bios - source_ref: "emulatorLauncher/Generators/Kronos.Generator.cs:162-170, .emulationstation/es_features.cfg:14519-14524" + choices_from: ".emulationstation/es_features.cfg:14519-14524" + source_ref: "emulatorLauncher/Generators/Kronos.Generator.cs:162-170" - emulator: ssf build: standalone kind: core_option @@ -5094,7 +5099,8 @@ launchers: passes_to: "SSF.ini [Peripheral] SaturnBIOS = /, only if the file exists" fails_when_missing: SaturnBIOS not written depends_on_option: use_external_bios - source_ref: "emulatorLauncher/Generators/SSF.Generator.cs:76-83, .emulationstation/es_features.cfg:20762-20767" + choices_from: ".emulationstation/es_features.cfg:20762-20767" + source_ref: "emulatorLauncher/Generators/SSF.Generator.cs:76-83" - emulator: yabasanshiro build: standalone kind: fixed_name @@ -5119,7 +5125,8 @@ launchers: \ exists" fails_when_missing: General\Bios not written depends_on_option: yabasanshiro_force_bios - source_ref: "emulatorLauncher/Generators/Yabasanshiro.Generator.cs:123-131, .emulationstation/es_features.cfg:22724-22729" + choices_from: ".emulationstation/es_features.cfg:22724-22729" + source_ref: "emulatorLauncher/Generators/Yabasanshiro.Generator.cs:123-131" - emulator: ymir build: standalone kind: fixed_name @@ -5144,7 +5151,8 @@ launchers: \ check" fails_when_missing: path written without an existence check depends_on_option: ymir_force_bios - source_ref: "emulatorLauncher/Generators/Ymir.Generator.cs:120-125, .emulationstation/es_features.cfg:22784-22788" + choices_from: ".emulationstation/es_features.cfg:22784-22788" + source_ref: "emulatorLauncher/Generators/Ymir.Generator.cs:120-125" - emulator: ymir build: standalone kind: passes_path @@ -5222,7 +5230,8 @@ launchers: fails_when_missing: ApplicationException 'BIOS file does not exist in ''.' depends_on_option: lrps2_bios - source_ref: "emulatorLauncher/Generators/LibRetro.CoreOptions.cs:3695-3704, .emulationstation/es_features.cfg:5875-5881" + choices_from: ".emulationstation/es_features.cfg:5875-5881" + source_ref: "emulatorLauncher/Generators/LibRetro.CoreOptions.cs:3695-3704" - emulator: pcsx2 build: libretro kind: scans_dir @@ -5635,8 +5644,10 @@ launchers: search_dir: bios passes_to: "xemu.toml [sys.files] flashrom_path=/, default Complex_4627.bin" fails_when_missing: path written without an existence check - depends_on_option: xemu_flashrom - source_ref: "emulatorLauncher/Generators/Xemu.Generator.cs:286-289, .emulationstation/es_features.cfg:22081-22085" + depends_on_option: "xemu_flashrom, not (emulator == \"xemu-chihiro\" || system ==\ + \ \"chihiro\")" + choices_from: ".emulationstation/es_features.cfg:22081-22085" + source_ref: "emulatorLauncher/Generators/Xemu.Generator.cs:48, 284-289" - emulator: xemu build: standalone kind: names_searched @@ -5752,7 +5763,8 @@ launchers: - coco3h - coco3p - coco3ph - source_ref: "emulatorLauncher/Generators/Xroar.Generator.cs:76-80, .emulationstation/es_features.cfg:22650-22659" + choices_from: ".emulationstation/es_features.cfg:22650-22659" + source_ref: "emulatorLauncher/Generators/Xroar.Generator.cs:76-80" - emulator: xroar build: standalone kind: passes_path diff --git a/scripts/scraper/knulli_launchers.py b/scripts/scraper/knulli_launchers.py index e5a138afd..d2e464324 100644 --- a/scripts/scraper/knulli_launchers.py +++ b/scripts/scraper/knulli_launchers.py @@ -1001,6 +1001,14 @@ def boot_disks( emulator = ( ", ".join(_caller_cores(cg, spec.caller)) if spec.caller else cg.emulator(module) ) + if spec.caller and spec.feature[:2] == ("libretro", "cores"): + # The option is offered for one core of the system: es_features + # lists it under that core, the other cores the generator serves + # never see it (KNULLI's macintosh offers mame alone). + core = spec.feature[2] + if core not in emulator.split(", "): + src.fail(f"es_features offers the option for {core}, which the generator does not serve") + emulator = core found = 0 for chain in ast.walk(src.tree): if not ( @@ -1054,10 +1062,10 @@ def boot_disks( expands={option: values}, case_insensitive=False, search_dir=cg.bios, passes_to=f"command line {flag}", fails_when_missing=False, depends_on_option=f"{option} ({' and '.join(tests)})", - source_ref=", ".join([ - src.ref([*spans, src.span(statement), _lines(added)]), - f"{ES_FEATURES}:{lines[0]}-{lines[1]}" if not listed else "", - ]).rstrip(", "), + # The values the menu offers come from es_features.yml; + # the generator writing the choice is the evidence. + choices_from=None if listed else f"{ES_FEATURES}:{lines[0]}-{lines[1]}", + source_ref=src.ref([*spans, src.span(statement), _lines(added)]), )) if not found: src.fail("names no BIOS file from an option value") diff --git a/scripts/scraper/retrobat_launchers.py b/scripts/scraper/retrobat_launchers.py index 5405580c6..a49709194 100644 --- a/scripts/scraper/retrobat_launchers.py +++ b/scripts/scraper/retrobat_launchers.py @@ -14,6 +14,11 @@ import bisect import re from collections.abc import Callable, Iterator +try: + from .shell_launchers import is_feature_ref, split_ref +except ImportError: + from shell_launchers import is_feature_ref, split_ref # type: ignore[no-redef] + GENERATORS = "emulatorLauncher/Generators" FEATURES = ".emulationstation/es_features.cfg" @@ -1254,6 +1259,11 @@ def xemu(sources: dict[str, Source]) -> list[Record]: ) flash = src.find(r'isOptSet\("(xemu_flashrom)"\)', "xemu_flashrom") + # The flashrom is written outside a Chihiro launch only. + chihiro_set = src.find(r"(_chihiro) = \(([^;]+)\);", "Chihiro test") + chihiro_guard = src.find_all( + rf"if \(!{chihiro_set.group(1)}\)", "flashrom guard", end=flash.start() + )[-1] flash_default = src.find( r'ini\.WriteValue\("([\w.]+)", "(flashrom_path)", "\'" \+ Path\.Combine\(flashromPath, "([^"]+)"\)', "flashrom default", @@ -1267,7 +1277,10 @@ def xemu(sources: dict[str, Source]) -> list[Record]: "core_option", _unique([flash_default.group(3), *choices]), source_ref( - (src.path, [src.lines(flash.start(), flash_default.end())]), + (src.path, [ + src.lines(chihiro_set.start(), chihiro_set.end()), + src.lines(chihiro_guard.start(), flash_default.end()), + ]), (features.path, [choice_lines]), ), case_insensitive=True, @@ -1277,7 +1290,7 @@ def xemu(sources: dict[str, Source]) -> list[Record]: f" default {flash_default.group(3)}" ), fails_when_missing="path written without an existence check", - depends_on_option=flash.group(1), + depends_on_option=f"{flash.group(1)}, not ({chihiro_set.group(2)})", ) ) @@ -3890,4 +3903,23 @@ def extract_launchers(texts: dict[str, str]) -> list[Record]: if missing: raise LauncherPatternMissing(missing[0], "source file") sources = {path: Source(path, text) for path, text in texts.items()} - return [record for extractor in EXTRACTORS for record in extractor(sources)] + return [ + _choices_apart(record) for extractor in EXTRACTORS for record in extractor(sources) + ] + + +def _choices_apart(record: Record) -> Record: + """The es_features.cfg part of a record's source_ref, moved to choices_from. + + The feature file lists the values a menu option offers. The generator + writing the choice is the record's evidence, never the list. + """ + parts = split_ref(str(record["source_ref"])) + listed = [p for p in parts if is_feature_ref(p)] + if not listed: + return record + code = [p for p in parts if not is_feature_ref(p)] + if not code: + raise LauncherPatternMissing(listed[0], "generator code beside the option list") + moved = {k: v for k, v in record.items() if k != "source_ref"} + return {**moved, "choices_from": ", ".join(listed), "source_ref": ", ".join(code)} diff --git a/tests/test_launchers_knulli.py b/tests/test_launchers_knulli.py index 2657c8dd5..16500d681 100644 --- a/tests/test_launchers_knulli.py +++ b/tests/test_launchers_knulli.py @@ -598,10 +598,11 @@ class BootDisks(unittest.TestCase): self.assertEqual((hard.names, hard.passes_to), (["{bootdisk}.chd"], "command line -hard")) self.assertEqual(hard.expands, {"bootdisk": ["macos3", "mac755"]}) self.assertTrue(hard.depends_on_option.startswith("bootdisk (system.name == 'macintosh'")) - self.assertEqual( - hard.source_ref, - f"{G}/mame/mameGenerator.py:3-4, 9-10, {kl.ES_FEATURES}:8-10", - ) + # The menu's values are where the choices come from, the generator + # writing the choice is the evidence. + self.assertEqual(hard.source_ref, f"{G}/mame/mameGenerator.py:3-4, 9-10") + self.assertEqual(hard.choices_from, f"{kl.ES_FEATURES}:8-10") + self.assertIsNone(floppy.choices_from) def test_a_name_built_another_way_raises(self): broken = MAME.replace('"/userdata/bios/" + system.config["bootdisk"] + ".chd"', "disk")