diff --git a/install.ps1 b/install.ps1 index 32699e0d1..225b6eb28 100644 --- a/install.ps1 +++ b/install.ps1 @@ -16,7 +16,7 @@ # and Invoke-WebRequest throws on a cut transfer before the hash is read: # the site's build rewrites this line there (scripts/sitebootstrap.py). $mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that." - $defaultInstallSha256 = "68d93a9905c324bc378ead0c0a7cbbecaf47a3c113265cb9f7c40ad40338b9a3" + $defaultInstallSha256 = "f91bc28bd52885ba24c7d5b0b882731f8ed51a2ffb03a74bde6c83f2248b537c" # The pin above refuses any changed byte: this cap only stops a body that # cannot be the installer (a sign-in portal's page) before it is hashed. $maximumInstallerBytes = 8MB diff --git a/install.py b/install.py index 0f8a6d6c7..40eafffc8 100644 --- a/install.py +++ b/install.py @@ -5538,8 +5538,11 @@ def place_emulator_entries( layout["config"], "emulators_directory.config", colons=False).parts) if layout else None ) - matches = bool(layout) and bios_path.name == layout.get("bios_folder") and config.is_file() - moved = _config_keys(config) if matches else set() + if config is not None and bios_path.name == layout.get("bios_folder") and config.is_file(): + moved = _config_keys(config) + matches = True + else: + moved, matches = set(), False kept: list[dict] = [] unplaced: list[dict] = [] for entry in files: diff --git a/install.sh b/install.sh index 88f7d3b79..0514b2204 100755 --- a/install.sh +++ b/install.sh @@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins # curl or wget stop on a cut transfer before the hash is read: the site's # build rewrites this line there (scripts/sitebootstrap.py). MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that." -DEFAULT_INSTALL_SHA256="68d93a9905c324bc378ead0c0a7cbbecaf47a3c113265cb9f7c40ad40338b9a3" +DEFAULT_INSTALL_SHA256="f91bc28bd52885ba24c7d5b0b882731f8ed51a2ffb03a74bde6c83f2248b537c" # The pin above refuses any changed byte: this cap only stops a body that # cannot be the installer (a sign-in portal's page) before it is hashed. MAX_INSTALLER_BYTES=8388608 diff --git a/install/launchers/index.json b/install/launchers/index.json index eec6fb563..f07135a2e 100644 --- a/install/launchers/index.json +++ b/install/launchers/index.json @@ -27,8 +27,8 @@ { "dest": "roms/ports/retrobios/install.py", "repo_path": "install.py", - "size": 1151002, - "sha256": "68d93a9905c324bc378ead0c0a7cbbecaf47a3c113265cb9f7c40ad40338b9a3", + "size": 1151055, + "sha256": "f91bc28bd52885ba24c7d5b0b882731f8ed51a2ffb03a74bde6c83f2248b537c", "executable": false }, { @@ -71,8 +71,8 @@ "muos": { "archive": { "dest": "ARCHIVE/RetroBIOS.muxapp", - "size": 1204627, - "sha256": "45d6a1c8ccdf2309783c391be51e274939890b25c5b78ee10b435155a934c271" + "size": 1204680, + "sha256": "2bfaf40568f66bb52eb7c01b9c3ca9b999b3974d67804107a4b18f49618eae16" }, "members": [ { @@ -92,8 +92,8 @@ { "name": "RetroBIOS/install.py", "repo_path": "install.py", - "size": 1151002, - "sha256": "68d93a9905c324bc378ead0c0a7cbbecaf47a3c113265cb9f7c40ad40338b9a3", + "size": 1151055, + "sha256": "f91bc28bd52885ba24c7d5b0b882731f8ed51a2ffb03a74bde6c83f2248b537c", "executable": false }, { @@ -166,8 +166,8 @@ { "dest": ".config/modules/retrobios/install.py", "repo_path": "install.py", - "size": 1151002, - "sha256": "68d93a9905c324bc378ead0c0a7cbbecaf47a3c113265cb9f7c40ad40338b9a3", + "size": 1151055, + "sha256": "f91bc28bd52885ba24c7d5b0b882731f8ed51a2ffb03a74bde6c83f2248b537c", "executable": false }, { diff --git a/mypy-baseline.txt b/mypy-baseline.txt index 6031a5fe0..d0a73e3ad 100644 --- a/mypy-baseline.txt +++ b/mypy-baseline.txt @@ -698,29 +698,6 @@ scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "ref" of "Source" scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "ref" of "Source" has incompatible type "list[tuple[int, Optional[int]]]"; expected "list[tuple[int, int]]" [arg-type] scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "setdefault" of "MutableMapping" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [arg-type] scripts/scraper/recalbox_launchers.py:0: error: Argument 4 to "record" has incompatible type "list[tuple[int, Optional[int]]]"; expected "list[tuple[int, int]]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type] -scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type] scripts/scraper/recalbox_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe] scripts/scraper/recalbox_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe] scripts/scraper/recalbox_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe] @@ -814,13 +791,6 @@ scripts/scraper/rocknix_launchers.py:0: error: Argument "search_dir" to "Launche scripts/scraper/rocknix_launchers.py:0: error: Argument 1 to "get" of "dict" has incompatible type "Union[str, Match[str]]"; expected "str" [arg-type] scripts/scraper/rocknix_launchers.py:0: error: Argument 1 to has incompatible type "Optional[int]"; expected "int" [arg-type] scripts/scraper/rocknix_launchers.py:0: error: Argument 2 to "next" has incompatible type "None"; expected "Match[str]" [arg-type] -scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type] -scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type] -scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type] -scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type] -scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type] -scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type] -scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type] scripts/scraper/rocknix_launchers.py:0: error: Generator has incompatible item type "str"; expected "Match[str]" [misc] scripts/scraper/rocknix_launchers.py:0: error: Name "Launcher" already defined (possibly by an import) [no-redef] scripts/scraper/rocknix_launchers.py:0: error: Name "LauncherPatternMissing" already defined (possibly by an import) [no-redef] diff --git a/scripts/common.py b/scripts/common.py index f11f86c44..09d2900e2 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -1686,20 +1686,20 @@ def resolve_local_file( and not sha256_candidates ): by_crc32 = db.get("indexes", {}).get("by_crc32", {}) - found: list[tuple[str, str]] = [] + crc_matches: list[tuple[str, str]] = [] for crc in crc_candidates: match = by_crc32.get(crc) if match and match in files_db: path = files_db[match]["path"] status = _record_match_status(match) if status and os.path.exists(path): - found.append((path, status)) + crc_matches.append((path, status)) # A primary copy over a .variants/ one, as everywhere else. - for path, status in found: + for path, status in crc_matches: if "/.variants/" not in path: return path, status - if found: - return found[0] + if crc_matches: + return crc_matches[0] # 2. MD5 direct lookup (skip for zipped_file: md5 is inner ROM, not container) # Guard: only accept if the found file's name matches the requested name @@ -3074,7 +3074,7 @@ def platform_layouts( family.setdefault(system, set()).update(entry_launch_systems(f, index) - own) def bindings_of(entry: dict) -> dict[str, tuple[str, str]]: - systems = frozenset() + systems: frozenset[str] = frozenset() if per_system: own = entry_launch_systems(entry, {}) systems = entry_launch_systems(entry, index) diff --git a/scripts/launchers.py b/scripts/launchers.py index b0cb6e1ab..0e19a267d 100644 --- a/scripts/launchers.py +++ b/scripts/launchers.py @@ -501,7 +501,7 @@ def handed_directories(config: dict) -> list[HandedDirectory]: ), systems=systems, holds_declared=bool(folder) and any( - d.startswith(f"{folder.lower()}/") for d in declared + d.startswith(f"{(folder or '').lower()}/") for d in declared ), )) return found diff --git a/scripts/scraper/batocera_launchers.py b/scripts/scraper/batocera_launchers.py index 951c79612..723e7d5ad 100644 --- a/scripts/scraper/batocera_launchers.py +++ b/scripts/scraper/batocera_launchers.py @@ -113,9 +113,9 @@ def configs_root(cg: Configgen) -> dict[str, str]: spans = [] for node in reversed(src.tree.body): name = _assigned_name(node) - if name in wanted: + if name in wanted and isinstance(node, (ast.Assign, ast.AnnAssign)) and node.value: spans.append((node.lineno, node.end_lineno or node.lineno)) - wanted |= {n.id for n in ast.walk(node.value) if isinstance(n, ast.Name)} # type: ignore[union-attr] + wanted |= {n.id for n in ast.walk(node.value) if isinstance(n, ast.Name)} return { "path": cg.paths["CONFIGS"], "from_bios": posixpath.relpath(cg.paths["CONFIGS"], cg.bios), @@ -943,7 +943,7 @@ def config_directories( """file.write("") and settings.save(key, ).""" prefix = cg.bios.rstrip("/") inside = re.compile(rf"{re.escape(prefix)}(?:/[^\s\"';]*)?") - launchers = [] + launchers: list[Launcher] = [] for module in modules: src = cg.generator(module) constants = dict(cg.paths) diff --git a/scripts/scraper/emuelec_launchers.py b/scripts/scraper/emuelec_launchers.py index 4698c8795..440e02818 100644 --- a/scripts/scraper/emuelec_launchers.py +++ b/scripts/scraper/emuelec_launchers.py @@ -17,32 +17,18 @@ import re from collections.abc import Callable from dataclasses import dataclass, field -try: - from .configgen_launchers import Launcher - from .rocknix_launchers import fixed_paths - from .shell_launchers import ( - LauncherPatternMissing, - Link, - RepoTree, - Script, - describe_keys, - settings, - source_ref, - words, - ) -except ImportError: - from configgen_launchers import Launcher - from rocknix_launchers import fixed_paths - from shell_launchers import ( - LauncherPatternMissing, - Link, - RepoTree, - Script, - describe_keys, - settings, - source_ref, - words, - ) +from .configgen_launchers import Launcher +from .rocknix_launchers import fixed_paths +from .shell_launchers import ( + LauncherPatternMissing, + Link, + RepoTree, + Script, + describe_keys, + settings, + source_ref, + words, +) SX05RE = "packages/sx05re" BIN = f"{SX05RE}/emuelec/bin" @@ -515,11 +501,11 @@ def advancemame(tree: RepoTree, runs: Runs) -> list[Launcher]: by_value: dict[tuple[tuple[str, str], ...], list[tuple[str, set[int], int]]] = {} for mk_line, file in installs: path = f"{package}/config/{file}" - found = [s for s in settings(tree.read(path), separator=" ") if _under(s.value)] - if not found: + keys = [s for s in settings(tree.read(path), separator=" ") if _under(s.value)] + if not keys: raise LauncherPatternMissing(path, f"key naming a folder under {BIOS_ROOT}") - value = tuple((s.key, s.value) for s in found) - by_value.setdefault(value, []).append((path, {s.line for s in found}, mk_line)) + value = tuple((s.key, s.value) for s in keys) + by_value.setdefault(value, []).append((path, {s.line for s in keys}, mk_line)) if len(by_value) != 1: raise mk.missing("one set of BIOS folders for every device") ((value, configs),) = by_value.items() diff --git a/scripts/scraper/emuelec_scraper.py b/scripts/scraper/emuelec_scraper.py index 7e7c21c96..1d544f4ad 100644 --- a/scripts/scraper/emuelec_scraper.py +++ b/scripts/scraper/emuelec_scraper.py @@ -249,10 +249,7 @@ class Scraper(BaseScraper): engines depend on emuelec-ports, which no package of an image depends on, and flycast-dojo is in no device list (UNBUILT there). """ - try: - from .targets.emuelec_targets_scraper import Scraper as DeviceTargets - except ImportError: - from scraper.targets.emuelec_targets_scraper import Scraper as DeviceTargets + from .targets.emuelec_targets_scraper import Scraper as DeviceTargets targets = DeviceTargets().device_targets(self.tag)["targets"] return {name for entry in targets.values() for name in entry["cores"]} diff --git a/scripts/scraper/recalbox_launchers.py b/scripts/scraper/recalbox_launchers.py index 90e259685..d56feabef 100644 --- a/scripts/scraper/recalbox_launchers.py +++ b/scripts/scraper/recalbox_launchers.py @@ -17,6 +17,7 @@ import ast import posixpath import re from collections.abc import Callable, Mapping +from functools import partial from typing import Any from .configgen_launchers import ( @@ -849,22 +850,21 @@ def amiberry(cg: Configgen) -> list[Launcher]: types = ", ".join(ast.unparse(t).removeprefix("RomType.") for t in entry.elts[0].elts) names = kick.literal(entry.elts[1], "kickstart names") ref = f"{kick.ref([kick.span(entry), *tail])}, {config_ref}" - common = dict(emulator=emulator, build="standalone", slot=system, - case_insensitive=False, search_dir=search_dir, - depends_on_option=f"rom type {types}", source_ref=ref) + make = partial(Launcher, emulator=emulator, build="standalone", slot=system, + case_insensitive=False, search_dir=search_dir, + depends_on_option=f"rom type {types}", source_ref=ref) if any("|" in name for name in names): if len(names) != 1: kick.fail(f"line {entry.lineno}: several kickstart pairs are not read") - launchers.append(Launcher( + launchers.append(make( kind="fixed_name", names=names[0].split("|"), passes_to=f"{rom_key}, {ext_key}", - fails_when_missing=", ".join(messages), **common, + fails_when_missing=", ".join(messages), )) else: - launchers.append(Launcher( + launchers.append(make( kind="names_searched", names=names, passes_to=rom_key, fails_when_missing=False if system in computers else messages[0], - **common, )) launchers.append(Launcher( emulator=emulator, build="standalone", kind="fixed_name", slot=", ".join(computers), @@ -956,30 +956,28 @@ def pcsx2(cg: Configgen) -> list[Launcher]: if _assigned_name(n) in {c for c in constants.values()}] ref = src.ref([(min(names_lines), max(names_lines)), (chooser.lineno, chooser.end_lineno), (writes[0].lineno, writes[0].end_lineno)]) - common = dict(emulator=cg.emulator(PCSX2), build="standalone", case_insensitive=False, - search_dir=search_dir, passes_to=f"[{section}] {key}", - fails_when_missing=False, source_ref=ref) + make = partial(Launcher, emulator=cg.emulator(PCSX2), build="standalone", + case_insensitive=False, search_dir=search_dir, + passes_to=f"[{section}] {key}", fails_when_missing=False, source_ref=ref) launchers = [] for (given, tested), tokens in groups.items(): slot = constants.get(given, given).removeprefix("BIOS_") depends = f"rom name contains {', '.join(tokens)}" if tested == given: - launchers.append(Launcher( + launchers.append(make( kind="names_searched", slot=slot, names=list(dict.fromkeys([given, *fallback])), - depends_on_option=depends, **common, + depends_on_option=depends, )) else: # The name written is not the one tested: no search, one name. - launchers.append(Launcher( + launchers.append(make( kind="fixed_name", slot=slot, names=[given], depends_on_option=f"{depends} and {tested} is present", - **common, )) - launchers.append(Launcher( + launchers.append(make( kind="names_searched", slot="default", names=fallback, depends_on_option="rom name with no region token, or its BIOS absent", - **common, )) return launchers @@ -1180,7 +1178,7 @@ def core_file_options(cg: Configgen, directories: list[Launcher]) -> list[Launch names=[call.args[1].value.strip('"')], search_dir=directory.search_dir, passes_to=f"core option {option}", depends_on_option=f"system {', '.join(systems)}", - source_ref=f"{src.ref([(function.lineno, function.end_lineno), *spans])}, " + source_ref=f"{src.ref([(function.lineno, function.end_lineno or function.lineno), *spans])}, " f"{directory.source_ref}", )) found = {str(launcher.passes_to).split()[-1] for launcher in launchers} @@ -1210,7 +1208,7 @@ def xroar(cg: Configgen) -> list[Launcher]: return [Launcher( emulator=cg.emulator(XROAR), build="standalone", kind="passes_path", names=[], search_dir=directory, passes_to="command line -rompath", - source_ref=src.ref([(flag.lineno, value.end_lineno)]), + source_ref=src.ref([(flag.lineno, value.end_lineno or value.lineno)]), )] diff --git a/scripts/scraper/retrobat_launchers.py b/scripts/scraper/retrobat_launchers.py index 6124e7b90..ce223bec8 100644 --- a/scripts/scraper/retrobat_launchers.py +++ b/scripts/scraper/retrobat_launchers.py @@ -845,8 +845,8 @@ def amiberry(sources: dict[str, Source]) -> list[Record]: depends_on_option="first name found, the target is absent, smaller or older", ) ) - key = src.find(r"private void StageRomKey\(\)", "StageRomKey") - key_body = src.block_at(key.end()) + stage_key = src.find(r"private void StageRomKey\(\)", "StageRomKey") + key_body = src.block_at(stage_key.end()) key_text = src.text[key_body[0]:key_body[1]] named = re.search(r'FindBios\(new\[\] \{ "([^"]+)" \}\)', key_text) if not named or not re.search( @@ -861,7 +861,7 @@ def amiberry(sources: dict[str, Source]) -> list[Record]: "copies", [named.group(1)], source_ref((src.path, [head, src.lines(roms.start(), roms.end()), - (src.line(key.start()), src.lines(*key_body)[1]), method_span])), + (src.line(stage_key.start()), src.lines(*key_body)[1]), method_span])), case_insensitive=True, search_dir=search, passes_to=f"{home}/{roms.group(2)}/{named.group(1)}", @@ -3386,11 +3386,12 @@ def xroar(sources: dict[str, Source]) -> list[Record]: # runs a CoCo 3 for coco, so its ROMs are read from that system's folder. features = sources[FEATURES] for record in records: - if not record.get("systems"): + systems = record.get("systems") + if not isinstance(systems, list) or not systems: continue machines: list[str] = [] lines = [] - for system in record["systems"]: + for system in systems: choices, span = system_feature_choices(features, "xroar", "xroar_machine", system) machines += [m for m in choices if m not in machines] lines.append(span) @@ -3441,11 +3442,14 @@ def _per_system(src: Source, record: Record) -> list[Record]: return [record] default, chosen, system = branch.groups() flag = str(record["passes_to"]).removesuffix(rendered).strip() + names = record["names"] + if not isinstance(names, list): + raise LauncherPatternMissing(src.path, "names of a directory choice") out = [] for directory, systems in ((default, None), (chosen, [system])): split = {k: v for k, v in record.items() if k != "source_ref"} split.update( - names=list(record["names"]), search_dir=directory, passes_to=f"{flag} {directory}" + names=list(names), search_dir=directory, passes_to=f"{flag} {directory}" ) if systems: split["systems"] = systems diff --git a/scripts/scraper/retropie_launchers.py b/scripts/scraper/retropie_launchers.py index 6a488b935..a56cd9a2c 100644 --- a/scripts/scraper/retropie_launchers.py +++ b/scripts/scraper/retropie_launchers.py @@ -840,7 +840,7 @@ class PackageReader: """ suffix = " is a symlink to it" linked = [ - record.passes_to.removesuffix(suffix).rstrip("/") + (record.passes_to or "").removesuffix(suffix).rstrip("/") for record in self.records if record.kind == "links" and not record.names and (record.passes_to or "").endswith(suffix) diff --git a/scripts/scraper/rocknix_launchers.py b/scripts/scraper/rocknix_launchers.py index cea8d298f..303d92365 100644 --- a/scripts/scraper/rocknix_launchers.py +++ b/scripts/scraper/rocknix_launchers.py @@ -192,7 +192,7 @@ def config_records( package: str, file: str, passes_to_suffix: str = "", - **fields: object, + depends_on_option: str | None = None, ) -> list[Launcher]: """fixed_name records for the bios paths of a config installed per device.""" configs = device_configs(tree, package, file) @@ -218,7 +218,7 @@ def config_records( (described + passes_to_suffix) if value.names else f"{described} left empty" ), device=device, - **fields, + depends_on_option=depends_on_option, ) ) return records @@ -335,7 +335,13 @@ def amiberry(tree: RepoTree) -> list[Launcher]: return records -def link_record(emulator: str, script: Script, link: Link, **fields: object) -> Launcher: +def link_record( + emulator: str, + script: Script, + link: Link, + case_insensitive: bool | None = None, + fails_when_missing: bool | str = False, +) -> Launcher: return Launcher( emulator=emulator, build="standalone", @@ -345,7 +351,8 @@ def link_record(emulator: str, script: Script, link: Link, **fields: object) -> expands=link.expands or None, search_dir=link.bios_side, passes_to=f"symlink {link.link} -> {link.target}", - **fields, + case_insensitive=case_insensitive, + fails_when_missing=fails_when_missing, ) diff --git a/scripts/scraper/rocknix_scraper.py b/scripts/scraper/rocknix_scraper.py index b4aa7e4ab..7580aeb7d 100644 --- a/scripts/scraper/rocknix_scraper.py +++ b/scripts/scraper/rocknix_scraper.py @@ -199,10 +199,7 @@ class Scraper(BaseScraper): the targets scraper, where every libretro profile counted before. A standalone package no device carries is not run either. """ - try: - from .targets.rocknix_targets_scraper import Scraper as DeviceTargets - except ImportError: - from scraper.targets.rocknix_targets_scraper import Scraper as DeviceTargets + from .targets.rocknix_targets_scraper import Scraper as DeviceTargets builds = DeviceTargets().device_builds(self.tag or launcher_revision(self.url)) libretro = sorted({core for _arch, lr, _sa in builds.values() for core in lr}) carried = set(standalone_emulators(sorted({p for *_rest, sa in builds.values() for p in sa}))) diff --git a/scripts/scraper/targets/batocera_targets_scraper.py b/scripts/scraper/targets/batocera_targets_scraper.py index 83b8e31c1..a6aec9414 100644 --- a/scripts/scraper/targets/batocera_targets_scraper.py +++ b/scripts/scraper/targets/batocera_targets_scraper.py @@ -559,6 +559,8 @@ class Scraper(BaseTargetScraper): repos = [("", self.REPO, self.tag)] for prefix, repo in self.SUBMODULES.items(): pin = _fetch_json(self._api(prefix.rstrip("/"))) + if not isinstance(pin, dict) or not isinstance(pin.get("sha"), str): + raise RuntimeError(f"no submodule commit for {prefix} at {self.tag}") repos.append((prefix, repo, pin["sha"])) found: dict[str, str] = {} for prefix, repo, ref in repos: