fix: type the code written today for mypy

Every error outside mypy-baseline.txt is fixed in the code:
- common.py: the CRC32 step reused found, the name the layout branch
  gives a resolution tuple, for its list of matches. It now has its own
  name. bindings_of annotates its systems.
- launchers.py, retropie_launchers.py, install.py: an Optional value
  read before its None check.
- recalbox_launchers.py, rocknix_launchers.py: Launcher calls take
  typed keywords, a partial or named parameters, instead of a
  dict[str, object] spread. end_lineno falls back to lineno.
- retrobat_launchers.py: the StageRomKey match no longer reuses the
  str key, and record values are checked before they are iterated.
- batocera_launchers.py: the value of an assignment is read on an
  Assign or AnnAssign only, and the launcher list is annotated.
- emuelec_launchers.py, emuelec_scraper.py, rocknix_scraper.py: import
  fallbacks no importer reaches are dropped, a reused name renamed.
- batocera_targets_scraper.py: a submodule answer without a commit is
  refused.
The baseline loses the 30 entries these fixes resolved and gains
none.
This commit is contained in:
Abdessamad Derraz committed 2026-11-10 04:41:44 +01:00
1 parent b6129310e5
commit 13e60386be
16 files changed
+83 -119

No files matched your search

+1 -1
View File
@@ -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
+5 -2
View File
@@ -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:
+1 -1
View File
@@ -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
+8 -8
View File
@@ -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
},
{
-30
View File
@@ -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 <set> 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]
+6 -6
View File
@@ -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)
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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("<line naming a BIOS directory>") and settings.save(key, <BIOS directory>)."""
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)
+16 -30
View File
@@ -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()
+1 -4
View File
@@ -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"]}
+16 -18
View File
@@ -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)]),
)]
+10 -6
View File
@@ -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
+1 -1
View File
@@ -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)
+11 -4
View File
@@ -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,
)
+1 -4
View File
@@ -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})))
@@ -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: