refactor: drop the archived platform status

RetroPie was the only platform with status: archived, which kept it out
of verify --all, slots, the pipeline and list_platforms unless
--include-archived was typed. release_pack already decides which packs a
release publishes and the installer serves every platform, so the status
set nothing apart. The field, its schema entry and the flag are gone, and
RetroPie is covered by every full run like any other platform.
This commit is contained in:
Abdessamad Derraz committed 2026-11-06 11:52:34 +01:00
1 parent 2e98be9366
commit 4d3f589ef4
93 files changed
+251 -452

No files matched your search

-1
View File
@@ -533,7 +533,6 @@ def main() -> None:
if args.all:
platforms = list_registered_platforms(
args.platforms_dir,
include_archived=True,
)
elif args.platform:
require_platform(args.platform, args.platforms_dir)
+2 -2
View File
@@ -134,7 +134,7 @@ def release_pack_labels(root: Path = REPO_ROOT) -> dict[str, str]:
"""Platform -> the platform part of the release pack that serves it.
Only the platforms the registry marks release_pack have a pack, grouped
as the release builds them (pipeline.py --include-archived). install.py
as the release builds them (pipeline.py). install.py
refuses a pack whose name does not spell the platform, so a platform
outside these groups has no pack to copy, whatever its file list.
"""
@@ -146,7 +146,7 @@ def release_pack_labels(root: Path = REPO_ROOT) -> dict[str, str]:
from generate_pack import _name_part, _platform_pack_stem # noqa: PLC0415
platforms_dir = str(root / "platforms")
pool = list_release_pack_platforms(platforms_dir, include_archived=True)
pool = list_release_pack_platforms(platforms_dir)
labels: dict[str, str] = {}
for group, representative in group_identical_platforms(pool, platforms_dir):
stem = _platform_pack_stem(group, representative, platforms_dir)
+1 -1
View File
@@ -51,7 +51,7 @@ def bundled_only(db: dict, profiles: dict, platforms_dir: str, install_dir: Path
"""Collected files a bundled entry resolves to and nothing else needs."""
consumers = FileConsumers(db)
needed: set[str] = set(shipped_by_manifests(install_dir))
for name in list_registered_platforms(platforms_dir, include_archived=True):
for name in list_registered_platforms(platforms_dir):
config = load_platform_config(name, platforms_dir)
for system in config.get("systems", {}).values():
for entry in system.get("files", []):
+2 -2
View File
@@ -308,7 +308,7 @@ def _scrapable_platforms(platforms_dir: Path) -> list[tuple[str, str, Path]]:
with (platforms_dir / "_registry.yml").open(encoding="utf-8") as fh:
registry = (yaml_load(fh) or {}).get("platforms") or {}
rows = []
for name in list_registered_platforms(str(platforms_dir), include_archived=True):
for name in list_registered_platforms(str(platforms_dir)):
path = platforms_dir / f"{name}.yml"
if not path.is_file():
continue
@@ -513,7 +513,7 @@ def check_native(
except export_native.SourcesIndexUnreadable as exc:
return [Finding("native", index.name, ERROR, detail=str(exc))]
findings: list[Finding] = []
for name in list_registered_platforms(str(platforms_dir), include_archived=True):
for name in list_registered_platforms(str(platforms_dir)):
exporter_class = exporters.get(name)
if not exporter_class:
continue
+1 -1
View File
@@ -239,7 +239,7 @@ def main() -> int:
print(f"ERROR: {SUMS}: {exc}", file=sys.stderr)
return 2
released = set(list_release_pack_platforms(args.platforms_dir, include_archived=True))
released = set(list_release_pack_platforms(args.platforms_dir))
findings = compare_release(record, sums, assets, tag, local_files, released,
installer_files(args.install_dir))
if args.json:
+12 -24
View File
@@ -507,10 +507,7 @@ def load_platform_registry(platforms_dir: str = "platforms") -> dict:
return (yaml_load(f) or {}).get("platforms", {})
def list_registered_platforms(
platforms_dir: str = "platforms",
include_archived: bool = False,
) -> list[str]:
def list_registered_platforms(platforms_dir: str = "platforms") -> list[str]:
"""List platforms registered in _registry.yml.
Only registered platforms generate packs and appear in CI.
@@ -527,9 +524,6 @@ def list_registered_platforms(
registry = yaml_load(f) or {}
platforms = []
for name, meta in sorted(registry.get("platforms", {}).items()):
status = meta.get("status", "active")
if status == "archived" and not include_archived:
continue
config_path = os.path.join(platforms_dir, meta.get("config", f"{name}.yml"))
if not os.path.exists(config_path):
raise FileNotFoundError(
@@ -539,10 +533,7 @@ def list_registered_platforms(
return platforms
def list_release_pack_platforms(
platforms_dir: str = "platforms",
include_archived: bool = False,
) -> list[str]:
def list_release_pack_platforms(platforms_dir: str = "platforms") -> list[str]:
"""Registered platforms a release publishes a ZIP pack for.
`release_pack: true` in _registry.yml is the whole list: the build of
@@ -553,7 +544,7 @@ def list_release_pack_platforms(
registry = load_platform_registry(platforms_dir)
return [
name
for name in list_registered_platforms(platforms_dir, include_archived)
for name in list_registered_platforms(platforms_dir)
if registry.get(name, {}).get("release_pack") is True
]
@@ -641,7 +632,7 @@ def platform_arg(value: str) -> str:
key = re.sub(r"[^a-z0-9]", "", value.lower())
if yaml is None or not os.path.isdir("platforms"):
return value
known = list_registered_platforms("platforms", include_archived=True)
known = list_registered_platforms("platforms")
for name in known:
if re.sub(r"[^a-z0-9]", "", name.lower()) == key:
return name
@@ -665,7 +656,7 @@ def require_platform(name: str, platforms_dir: str = "platforms") -> None:
return
import difflib # noqa: PLC0415
known = list_registered_platforms(platforms_dir, include_archived=True)
known = list_registered_platforms(platforms_dir)
close = difflib.get_close_matches(name, known, n=1)
hint = f" Did you mean '{close[0]}'?" if close else ""
raise SystemExit(
@@ -3460,19 +3451,16 @@ def list_system_ids(emulators_dir: str) -> None:
def print_platform_listing(platforms_dir: str) -> None:
"""Every registered platform, one per line, marked when archived or
served by the installer only.
"""Every registered platform, one per line, marked when the installer
alone serves it.
Every platform takes --platform. --all covers the active ones, and the
pack builder's --all the release packs. Printed by --list-platforms in
Every platform takes --platform. --all covers every one, and the pack
builder's --all the release packs. Printed by --list-platforms in
verify.py and generate_pack.py, the name install.py gives it.
"""
active = set(list_registered_platforms(platforms_dir))
released = set(list_release_pack_platforms(platforms_dir, include_archived=True))
for name in list_registered_platforms(platforms_dir, include_archived=True):
marks = [m for m, on in (("archived", name not in active),
("installer only", name not in released)) if on]
print(f"{name} ({', '.join(marks)})" if marks else name)
released = set(list_release_pack_platforms(platforms_dir))
for name in list_registered_platforms(platforms_dir):
print(name if name in released else f"{name} (installer only)")
def list_platform_system_ids(platform_name: str, platforms_dir: str) -> None:
+4 -4
View File
@@ -83,7 +83,7 @@ def load_platform_files(
declared = {}
platform_data_dirs = {}
for platform_name in platforms or list_registered_platforms(
platforms_dir, include_archived=True
platforms_dir
):
config = load_platform_config(platform_name, platforms_dir)
for sys_id, system in config.get("systems", {}).items():
@@ -114,7 +114,7 @@ def declared_names(
[
load_platform_config(platform_name, platforms_dir)
for platform_name in platforms or list_registered_platforms(
platforms_dir, include_archived=True
platforms_dir
)
],
db,
@@ -133,7 +133,7 @@ def folded_declared_slots(
slots: set[str] = set()
for platform_name in platforms or list_registered_platforms(
platforms_dir, include_archived=True
platforms_dir
):
config = load_platform_config(platform_name, platforms_dir)
slots |= case_folded_slots(config, platform_declarations(config, db))
@@ -1257,7 +1257,7 @@ def main() -> None:
standalone_cores = merged_standalone_set(
load_platform_config(name, args.platforms_dir)
for name in list_registered_platforms(args.platforms_dir, include_archived=True)
for name in list_registered_platforms(args.platforms_dir)
)
if not profiles:
+1 -1
View File
@@ -215,7 +215,7 @@ def main() -> None:
if args.all:
platforms = list_registered_platforms(
args.platforms_dir, include_archived=True
args.platforms_dir
)
else:
require_platform(args.platform, args.platforms_dir)
-1
View File
@@ -1009,7 +1009,6 @@ def main() -> None:
if args.all:
platforms = list_registered_platforms(
args.platforms_dir,
include_archived=True,
)
else:
require_platform(args.platform, args.platforms_dir)
+1 -1
View File
@@ -623,7 +623,7 @@ def _collect_all_aliases(
platforms_dir = Path("platforms")
if platforms_dir.is_dir():
for platform_name in list_registered_platforms(
str(platforms_dir), include_archived=True
str(platforms_dir)
):
config_file = platforms_dir / f"{platform_name}.yml"
try:
+29 -57
View File
@@ -1779,7 +1779,7 @@ def generate_emulator_pack(
else:
report_missing(archive_name, archive_dest)
# Pack individual files (skip archived ones). The entries of one
# Pack individual files (skip archive members). The entries of one
# profile on one destination are the releases the code accepts
# there (raze's seven SW.GRP): the first one the core accepts
# fills the slot, as verify --emulator credits it, and the slot
@@ -2605,10 +2605,7 @@ def _resolve_systems(args: argparse.Namespace, parser: argparse.ArgumentParser)
config = None
systems = sorted({
sid
for name in list_registered_platforms(
args.platforms_dir,
include_archived=args.include_archived or args.manifest,
)
for name in list_registered_platforms(args.platforms_dir)
for sid in load_platform_config(name, args.platforms_dir).get("systems", {})
})
listing = "--platform <name> --list-systems"
@@ -2933,9 +2930,7 @@ def _run_verify_packs(args: argparse.Namespace) -> None:
elif args.all:
# The packs --all builds: a platform without release_pack has no pack
# to check, and its absence from the directory is no failure.
platforms = list_release_pack_platforms(
args.platforms_dir, include_archived=args.include_archived
)
platforms = list_release_pack_platforms(args.platforms_dir)
else:
raise ValueError("--verify-packs requires --platform or --all")
@@ -3334,15 +3329,6 @@ def _refuse_refresh_data(args: argparse.Namespace, parser: argparse.ArgumentPars
parser.error(f"{name} is incompatible with {flag}")
def _refuse_include_archived(
args: argparse.Namespace, parser: argparse.ArgumentParser
) -> None:
"""Only --all chooses among registered platforms. Every other mode names
its own platform, emulator, system or hash."""
if args.include_archived and not args.all:
parser.error("--include-archived requires --all")
def _refuse_unapplied_flags(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None:
"""Refuse every flag the requested mode would not apply.
@@ -3350,7 +3336,6 @@ def _refuse_unapplied_flags(args: argparse.Namespace, parser: argparse.ArgumentP
about an artifact the caller did not name. Run before any quick-exit
mode, since --verify-packs and --manifest-targets return early.
"""
_refuse_include_archived(args, parser)
# Parsed before the quick-exit modes: --verify-packs returns early and
# still needs the region priority list to narrow its expectation.
args.regions = []
@@ -3392,8 +3377,7 @@ QUICK_MODE_FLAGS: dict[str, set[str]] = {
# Checks packs already on disk against the platform's own list, narrowed
# by region and target and by nothing else.
"--verify-packs": {
"--platform", "--all", "--target", "--region", "--include-archived",
"--no-game-data",
"--platform", "--all", "--target", "--region", "--no-game-data",
},
# One manifest per hardware target, from the target files themselves.
"--manifest-targets": set(),
@@ -3430,7 +3414,6 @@ def _given_flags(args: argparse.Namespace) -> set[str]:
"--list-emulators": args.list_emulators,
"--list-systems": args.list_systems,
"--list-targets": args.list_targets,
"--include-archived": args.include_archived,
"--refresh-data": args.refresh_data,
"--no-refresh-data": args.no_refresh_data,
}
@@ -3486,9 +3469,6 @@ def _main(held: contextlib.ExitStack) -> None:
parser.add_argument(
"--list-systems", action="store_true", help="List available systems"
)
parser.add_argument(
"--include-archived", action="store_true", help="Include archived platforms"
)
parser.add_argument(
"--platforms-dir", default=DEFAULT_PLATFORMS_DIR,
help="platform YAML directory (default: %(default)s)",
@@ -3760,16 +3740,12 @@ def _main(held: contextlib.ExitStack) -> None:
# Platform mode
if args.all and args.manifest:
# Install manifests cover every registered platform: the installer
# serves each one, with or without a release pack. "Archived" keeps a
# platform out of the runs that cover every platform, not out of the
# installer: it has not lost its users.
platforms = list_registered_platforms(args.platforms_dir, include_archived=True)
# serves each one, with or without a release pack.
platforms = list_registered_platforms(args.platforms_dir)
elif args.all:
# A release publishes the packs the registry marks release_pack and
# nothing else: a pack built for another platform is one nobody uploads.
platforms = list_release_pack_platforms(
args.platforms_dir, include_archived=args.include_archived
)
platforms = list_release_pack_platforms(args.platforms_dir)
if not platforms:
parser.error("no registered platform has release_pack: true")
elif args.platform:
@@ -5291,31 +5267,27 @@ def _expected_pack_names(
for p in platforms
}
# Groups depend on which platforms a run built: the release packs of
# --all, alone or with --include-archived. Both compositions are names a
# pack can carry.
for include_archived in (False, True):
pool = list_release_pack_platforms(
platforms_dir, include_archived=include_archived
)
cache = None
if target_name:
try:
cache, pool = build_target_cores_cache(
pool, target_name, platforms_dir, is_all=True
)
except ValueError:
# No platform has the target: no pack was built under it.
continue
for group, representative in group_identical_platforms(
pool, platforms_dir, cache
):
if len(group) < 2:
continue
stem = _platform_pack_stem(group, representative, platforms_dir)
for tags in narrow_tags(representative):
for p in group:
if p in names:
names[p].add(f"{stem}{tags}_BIOS_Pack.zip")
# --all.
pool = list_release_pack_platforms(platforms_dir)
cache = None
if target_name:
try:
cache, pool = build_target_cores_cache(
pool, target_name, platforms_dir, is_all=True
)
except ValueError:
# No platform has the target: no pack was built under it.
return names
for group, representative in group_identical_platforms(
pool, platforms_dir, cache
):
if len(group) < 2:
continue
stem = _platform_pack_stem(group, representative, platforms_dir)
for tags in narrow_tags(representative):
for p in group:
if p in names:
names[p].add(f"{stem}{tags}_BIOS_Pack.zip")
return names
@@ -5442,7 +5414,7 @@ def verify_and_finalize_packs(
# By the exact name this run's reduction gives a platform's pack, never by
# substring: a _Custom or regional pack left by another run was judged
# against this run's expectation and failed it.
registered = list_registered_platforms(platforms_dir, include_archived=True)
registered = list_registered_platforms(platforms_dir)
expected = _expected_pack_names(
registered, platforms_dir, regions, target_name, no_game_data=no_game_data
)
+4 -21
View File
@@ -379,7 +379,6 @@ def _paragraphs(texts: list[str]) -> list[str]:
def download_table(
coverages: dict,
archived: set[str],
extract_paths: dict[str, str],
record: dict,
) -> list[str]:
@@ -389,12 +388,9 @@ def download_table(
"|----------|------:|---------------:|-----------|----------|",
]
for name, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]):
display = cov["platform"]
if name in archived:
display = f"{display} *"
files, size = release_totals(name, record)
lines.append(
f"| {display} | {f'{files:,}' if files else '-'} |"
f"| {cov['platform']} | {f'{files:,}' if files else '-'} |"
f" {format_size(size) if size else '-'} |"
f" {extract_paths.get(cov['platform'], '')} |"
f" {download_links(name, record, 'Download', site=SITE_URL)} |"
@@ -530,7 +526,7 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json"
total_size = db.get("total_size", 0)
ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
platform_names = list_registered_platforms(platforms_dir, include_archived=True)
platform_names = list_registered_platforms(platforms_dir)
from common import load_data_dir_registry
@@ -632,29 +628,16 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json"
# a pack whose entries already carry their own root (RetroDECK) extracts
# one level above it.
extract_paths = _extract_cells(platforms_dir)
archived = {
name
for name, entry in load_platform_registry(platforms_dir).items()
if entry.get("status") == "archived"
}
lines.extend(
download_table(
coverages, archived, extract_paths,
coverages, extract_paths,
release_record.load_advertised(platforms_dir=platforms_dir),
)
)
lines.extend(["", no_pack_line()])
lines.extend(_paragraphs(extract_notes(platforms_dir, released_only=True)))
if archived:
lines.extend(
[
"",
"\\* Archived: the installer serves it, and checks that cover every"
" setup include it only on request.",
]
)
lines.extend(
[
@@ -753,7 +736,7 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json"
)
for name, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]):
display = f"{cov['platform']} *" if name in archived else cov["platform"]
display = cov["platform"]
checked = check_label(cov["mode"], cov["config"].get("hash_rule"))
core_total = (
cov["core_present"] + cov["core_missing"] + cov["core_unsourceable"]
+9 -22
View File
@@ -1073,7 +1073,7 @@ def _release_pack_platforms() -> frozenset[str]:
@functools.lru_cache(maxsize=None)
def _release_packs_in(platforms_dir: str) -> frozenset[str]:
return frozenset(list_release_pack_platforms(platforms_dir, include_archived=True))
return frozenset(list_release_pack_platforms(platforms_dir))
# Per-entry fields a folder check needs beyond the hashes: an md5 is a ZIP
@@ -3393,28 +3393,23 @@ SETUP_TABLE_ANCHOR = "every-setup-at-a-glance"
SETUP_TABLE_LINK = f"{SETUP_TABLE_PAGE}#{SETUP_TABLE_ANCHOR}"
def setup_table(coverages: dict, registry: dict | None = None) -> list[str]:
def setup_table(coverages: dict) -> list[str]:
"""Every setup side by side: the files on its own list, the files in its
ZIP, and how it checks them. Written under the Reference level, on the
page that explains each way of checking."""
registry = registry or {}
lines = [
f"## Every setup at a glance {{ #{SETUP_TABLE_ANCHOR} }}",
"",
"| Setup | Files on its own list | Files in the ZIP | How it checks |",
"|-------|------:|------:|---------------|",
]
archived = False
for name, cov in sorted(coverages.items(), key=lambda item: item[1]["platform"].casefold()):
status = registry.get(name, {}).get("status")
archived |= status == "archived"
listed = f"{cov['total']:,}" if cov["total"] else "No list of its own"
files, _size = release_totals(name, release_record.load_advertised())
zipped = (f"{files:,}" if files
else "No ZIP yet" if has_release_pack(name) else "No ZIP")
lines.append(
f"| [{cov['platform']}](../platforms/{name}.md)"
f"{' (archived)' if status == 'archived' else ''} | {listed} | {zipped} | "
f"| [{cov['platform']}](../platforms/{name}.md) | {listed} | {zipped} | "
f"{check_label(cov['mode'], cov['config'].get('hash_rule'))} |"
)
lines += [
@@ -3424,16 +3419,13 @@ def setup_table(coverages: dict, registry: dict | None = None) -> list[str]:
]
lines += ["No ZIP: the setup is served by the command alone. "
f"[Why?](../{NO_ZIP_FAQ})", ""]
if archived:
lines += ["An archived setup keeps its page and the command. Checks that cover "
"every setup include it only on request.", ""]
return lines
def with_setup_table(page: str, coverages: dict, registry: dict | None = None) -> str:
def with_setup_table(page: str, coverages: dict) -> str:
"""The comparison table placed before the Next steps of its page, or at
its end."""
table = "\n".join(setup_table(coverages, registry))
table = "\n".join(setup_table(coverages))
marker = "\n## Next steps"
if marker in page:
head, tail = page.split(marker, 1)
@@ -4607,11 +4599,6 @@ def generate_platform_page(
"",
]
if registry.get(name, {}).get("status") == "archived":
lines.extend(markup.aside("warning", "Archived platform", [
f"{display}'s list is kept as last read. Its pack is still built.",
]))
summary = GUIDES[name].summary if name in GUIDES else ""
if summary:
lines += [summary + (f" [{display} website]({homepage})." if homepage else ""), ""]
@@ -12471,7 +12458,7 @@ def _generate(args: argparse.Namespace) -> None:
registry = (yaml_load(f) or {}).get("platforms", {})
platform_names = list_registered_platforms(
args.platforms_dir, include_archived=True
args.platforms_dir
)
from common import load_data_dir_registry
@@ -12767,7 +12754,7 @@ def _generate(args: argparse.Namespace) -> None:
table_page = docs / SETUP_TABLE_PAGE
if table_page.is_file():
write_if_changed(str(table_page), with_setup_table(
table_page.read_text(encoding="utf-8"), coverages, registry))
table_page.read_text(encoding="utf-8"), coverages))
# data-model.md is generated (contains live DB stats)
write_if_changed(
str(wiki_dest / "data-model.md"), generate_wiki_data_model(db, profiles)
@@ -12776,8 +12763,8 @@ def _generate(args: argparse.Namespace) -> None:
print("Generating which-pack page...")
write_if_changed(str(docs / "which-pack.md"), generate_which_pack())
# One permanent download address per registered platform, archived ones
# included: the README's table links each of them.
# One permanent download address per registered platform: the README's
# table links each of them.
print("Generating download pages...")
get_dir = docs / release_record.GET_DIR
get_dir.mkdir(parents=True, exist_ok=True)
-1
View File
@@ -91,7 +91,6 @@ def main(argv: list[str] | None = None) -> None:
if args.all:
platforms = list_registered_platforms(
args.platforms_dir,
include_archived=True,
)
else:
require_platform(args.platform, args.platforms_dir)
+7 -18
View File
@@ -1,13 +1,8 @@
#!/usr/bin/env python3
"""List the registered platforms.
Respects the `status` field in _registry.yml:
- active: listed by default
- archived: listed with --include-archived only
"""List the platforms registered in _registry.yml.
Usage:
python scripts/list_platforms.py # active platforms
python scripts/list_platforms.py --include-archived # archived ones too
python scripts/list_platforms.py
python scripts/list_platforms.py >> "$GITHUB_OUTPUT"
"""
@@ -24,22 +19,16 @@ from common import list_registered_platforms
PLATFORMS_DIR = "platforms"
def list_platforms(include_archived: bool = False) -> list[str]:
"""List platform config files, filtering by status from _registry.yml."""
return list_registered_platforms(PLATFORMS_DIR, include_archived=include_archived)
def list_platforms() -> list[str]:
"""Every registered platform."""
return list_registered_platforms(PLATFORMS_DIR)
def main() -> None:
parser = argparse.ArgumentParser(allow_abbrev=False, description="List available platforms")
# The name verify, generate_pack, slots and pipeline use. --all is the
# older spelling, still read so existing commands keep working.
parser.add_argument(
"--include-archived", "--all", dest="include_archived", action="store_true",
help="include archived platforms",
)
args = parser.parse_args()
parser.parse_args()
platforms = list_platforms(include_archived=args.include_archived)
platforms = list_platforms()
if not platforms:
print("No platform configs found", file=sys.stderr)
+1 -1
View File
@@ -43,7 +43,7 @@ def platform_cards() -> dict[str, tuple[str, str]]:
return {
f"platforms/{name}": (load_platform_config(name, str(platforms))["platform"],
PLATFORM_TAGLINE)
for name in list_registered_platforms(str(platforms), include_archived=True)
for name in list_registered_platforms(str(platforms))
}
+12 -29
View File
@@ -34,8 +34,7 @@ Steps, numbered as the run prints them:
come from .cache/large/ only.
Usage:
python scripts/pipeline.py # active platforms
python scripts/pipeline.py --include-archived # all platforms
python scripts/pipeline.py # every registered platform
python scripts/pipeline.py --skip-packs # skip steps 4, 4b, 4c, 5 and 6
python scripts/pipeline.py --skip-docs # skip steps 7, 8 and 8b
python scripts/pipeline.py --offline # no network, see above
@@ -326,13 +325,13 @@ def _match_key(label: str) -> set[str]:
} - {""}
def release_pack_keys(platforms_dir: str = "platforms", include_archived: bool = False) -> set[str]:
def release_pack_keys(platforms_dir: str = "platforms") -> set[str]:
"""Comparable identities of the platforms --all builds a pack for: their
registry ids and display names, normalized as _match_key does."""
from common import list_release_pack_platforms, load_platform_config # noqa: PLC0415
keys: set[str] = set()
for name in list_release_pack_platforms(platforms_dir, include_archived):
for name in list_release_pack_platforms(platforms_dir):
keys |= _match_key(name)
keys |= _match_key(str(load_platform_config(name, platforms_dir).get("platform", name)))
return keys
@@ -714,8 +713,7 @@ def narrowed_variants(
def check_narrowed_packs(
emulators_dir: str = "emulators", platforms_dir: str = "platforms",
db_path: str = "database.json", include_archived: bool = False,
full: bool = False,
db_path: str = "database.json", full: bool = False,
) -> bool:
"""Build each narrowed platform pack in memory and compare it with verify.
@@ -753,7 +751,7 @@ def check_narrowed_packs(
profiles = load_emulator_profiles(emulators_dir)
registry = load_data_dir_registry(platforms_dir)
groups = group_identical_platforms(
list_registered_platforms(platforms_dir, include_archived=include_archived),
list_registered_platforms(platforms_dir),
platforms_dir,
)
was_offline = packresolve._OFFLINE
@@ -837,7 +835,7 @@ def split_differences(
def check_split_packs(
emulators_dir: str = "emulators", platforms_dir: str = "platforms",
db_path: str = "database.json", include_archived: bool = False,
db_path: str = "database.json",
) -> bool:
"""Build each platform's --split parts in memory and compare them with
the full pack: the parts must add up to it, path for path and byte for
@@ -863,7 +861,7 @@ def check_split_packs(
profiles = load_emulator_profiles(emulators_dir)
registry = load_data_dir_registry(platforms_dir)
groups = group_identical_platforms(
list_registered_platforms(platforms_dir, include_archived=include_archived),
list_registered_platforms(platforms_dir),
platforms_dir,
)
was_offline = packresolve._OFFLINE
@@ -917,8 +915,6 @@ def integrity_command(args: argparse.Namespace) -> list[str]:
sys.executable, "scripts/generate_pack.py", "--all", "--verify-packs",
"--output-dir", args.output_dir,
]
if args.include_archived:
cmd.append("--include-archived")
# Without the target a targeted run reported every system the target
# removed as missing from a pack that was exactly right. Without
# --all-variants the five narrowed packs were never opened, and an empty
@@ -1073,9 +1069,6 @@ def _truth_steps(args: argparse.Namespace, results: dict) -> bool:
def main() -> None:
parser = argparse.ArgumentParser(allow_abbrev=False, description="Run the full retrobios pipeline")
parser.add_argument(
"--include-archived", action="store_true", help="Include archived platforms"
)
parser.add_argument(
"--skip-packs",
action="store_true",
@@ -1311,8 +1304,6 @@ def main() -> None:
sys.executable, "scripts/verify.py", "--all", "--strict",
"--destinations", destinations_file,
]
if args.include_archived:
verify_cmd.append("--include-archived")
if args.target:
verify_cmd.extend(["--target", args.target])
if args.offline:
@@ -1338,11 +1329,9 @@ def main() -> None:
# upstream declaration no build can repair, so this reports and never gates.
# A crash is not a report: without --strict slots.py exits 0 on every
# conflict, so a non-zero code means it never finished reading.
# The same platforms and cores verify judged: without these flags the
# arbitration of an --include-archived run never looked at RetroPie.
# The same cores verify judged: without the target the arbitration of a
# targeted run judged cores the target does not ship.
slots_cmd = [sys.executable, "scripts/slots.py"]
if args.include_archived:
slots_cmd.append("--include-archived")
if args.target:
slots_cmd.extend(["--target", args.target])
ok, _ = run(slots_cmd, "3b slot arbitration")
@@ -1381,8 +1370,6 @@ def main() -> None:
"--output-dir",
args.output_dir,
]
if args.include_archived:
pack_cmd.append("--include-archived")
if args.offline:
pack_cmd.append("--offline")
else:
@@ -1412,8 +1399,6 @@ def main() -> None:
"--output-dir",
"install",
]
if args.include_archived:
manifest_cmd.append("--include-archived")
if args.offline:
manifest_cmd.append("--offline")
else:
@@ -1479,15 +1464,13 @@ def main() -> None:
elif pack_output and verify_output:
ok = check_consistency(
verify_output, pack_output,
release_pack_keys(include_archived=args.include_archived),
release_pack_keys(),
)
# Counts can agree while the paths differ, both ways at once.
ok = check_pack_destinations(destinations_file, pack_output) and ok
ok = check_emulator_packs(full=args.full_narrowings) and ok
ok = check_narrowed_packs(
include_archived=args.include_archived, full=args.full_narrowings,
) and ok
ok = check_split_packs(include_archived=args.include_archived) and ok
ok = check_narrowed_packs(full=args.full_narrowings) and ok
ok = check_split_packs() and ok
print(
f"--- {step_title(STEP_LABELS['consistency'])}, counts and paths: "
f"{'OK' if ok else 'FAILED'} ---"
+2 -5
View File
@@ -3532,17 +3532,14 @@ def _platform_cores(emulators_dir: str, platforms_dir: str) -> tuple[tuple[str,
(platform, frozenset(resolve_platform_cores(
load_platform_config(platform, platforms_dir), profiles
)))
for platform in list_registered_platforms(platforms_dir, include_archived=True)
for platform in list_registered_platforms(platforms_dir)
)
def shipping_platforms(
name: str, emulators_dir: str, platforms_dir: str = "platforms",
) -> list[str]:
"""The registered platforms whose cores resolve to this profile.
Archived platforms count: RetroPie still builds the packages it lists.
"""
"""The registered platforms whose cores resolve to this profile."""
return [
platform
for platform, cores in _platform_cores(
+2 -2
View File
@@ -68,10 +68,10 @@ def _extract_folders(record: dict, platforms_dir: str) -> dict[str, str]:
def without_pack(platforms_dir: str) -> list[str]:
"""Display names of the registered setups no release publishes a ZIP for."""
released = set(list_release_pack_platforms(platforms_dir, include_archived=True))
released = set(list_release_pack_platforms(platforms_dir))
names = [
str(load_platform_config(key, platforms_dir).get("platform", key))
for key in list_registered_platforms(platforms_dir, include_archived=True)
for key in list_registered_platforms(platforms_dir)
if key not in released
]
return sorted(names, key=str.casefold)
+2 -2
View File
@@ -58,7 +58,7 @@ def release_owners(platforms_dir: str = "platforms") -> dict[str, list[str]]:
"""
import generate_pack
platforms = list_release_pack_platforms(platforms_dir, include_archived=True)
platforms = list_release_pack_platforms(platforms_dir)
owners: dict[str, list[str]] = {}
for platform, names in generate_pack._expected_pack_names(
platforms, platforms_dir, None, None
@@ -150,7 +150,7 @@ def advertised(record: dict, platforms_dir: str = "platforms") -> dict:
"""
if not record:
return {}
released = set(list_release_pack_platforms(platforms_dir, include_archived=True))
released = set(list_release_pack_platforms(platforms_dir))
packs = {}
for name, pack in record.get("packs", {}).items():
serves = [p for p in pack.get("platforms", ()) if p in released]
+1 -1
View File
@@ -111,7 +111,7 @@ class SystemResolver:
use[str(sid)] = use.get(str(sid), 0) + 1
ids = set(use)
native: dict[str, dict[str, set[str]]] = {}
for platform in list_registered_platforms(platforms_dir, include_archived=True):
for platform in list_registered_platforms(platforms_dir):
config = load_platform_config(platform, platforms_dir)
ids.update(config.get("systems", {}))
names: dict[str, set[str]] = {}
+1 -1
View File
@@ -293,7 +293,7 @@ def platform_targets(platforms_dir: str) -> dict[str, set[str]]:
their MD5 is not an archive hash and is skipped.
"""
targets: dict[str, set[str]] = defaultdict(set)
for name in list_registered_platforms(platforms_dir, include_archived=True):
for name in list_registered_platforms(platforms_dir):
config = load_platform_config(name, platforms_dir)
for system in config.get("systems", {}).values():
for entry in system.get("files", []) or []:
+1 -1
View File
@@ -533,7 +533,7 @@ def _write_release(args: argparse.Namespace) -> None:
def _platform_archives() -> list[tuple[str, str]]:
"""(file name, system) for every file a registered platform declares."""
stated: list[tuple[str, str]] = []
for name in list_registered_platforms(str(_PLATFORMS_DIR), include_archived=True):
for name in list_registered_platforms(str(_PLATFORMS_DIR)):
config = load_platform_config(name, str(_PLATFORMS_DIR))
for system, data in (config.get("systems") or {}).items():
for entry in (data or {}).get("files") or []:
+1 -1
View File
@@ -69,7 +69,7 @@ def relevant_archives(emulators_dir: str, platforms_dir: str) -> set[str]:
archive = entry.get("archive", "")
if archive:
names.add(archive)
for platform_name in list_registered_platforms(platforms_dir, include_archived=True):
for platform_name in list_registered_platforms(platforms_dir):
config = load_platform_config(platform_name, platforms_dir)
for system in config.get("systems", {}).values():
for entry in system.get("files", []) or []:
+3 -3
View File
@@ -328,8 +328,8 @@ def _registry_in(platforms_dir: str) -> dict:
def setups() -> tuple[str, ...]:
"""The registered setups, archived ones included: each has its own page,
pack and file list, so every count of setups on the site is this one."""
"""The registered setups: each has its own page, pack and file list, so
every count of setups on the site is this one."""
return _setups_in(str(siteinputs.current().platforms))
@@ -337,7 +337,7 @@ def setups() -> tuple[str, ...]:
def _setups_in(platforms_dir: str) -> tuple[str, ...]:
from common import list_registered_platforms
return tuple(sorted(list_registered_platforms(platforms_dir, include_archived=True)))
return tuple(sorted(list_registered_platforms(platforms_dir)))
def setups_named(named: list[str]) -> str:
+5 -6
View File
@@ -288,9 +288,9 @@ def _handheld_guide(data: object, registry: dict, guides: dict, where: str) -> H
def load_guides(path: Path = GUIDES_FILE, registry: dict | None = None) -> dict:
"""The guides file, checked against the registry.
Every registered platform, archived ones included, has a guide and a
device group the file describes. A mistake raises GuideError naming the
key, so the site is never built from half a guide.
Every registered platform has a guide and a device group the file
describes. A mistake raises GuideError naming the key, so the site is
never built from half a guide.
"""
yaml = require_yaml()
if registry is None:
@@ -413,9 +413,8 @@ def _plain_folders(name: str) -> str:
def setup_count() -> int:
"""Setups the site covers: every registered platform, archived ones
included, since each keeps its page, its pack and its command. The one
count every page states."""
"""Setups the site covers: every registered platform, since each keeps
its page, its pack and its command. The one count every page states."""
return len(GUIDES)
+1 -1
View File
@@ -1436,7 +1436,7 @@ def system_search_aliases(sys_id: str) -> list[str]:
platforms_dir = str(siteinputs.current().platforms)
index: dict[str, set[str]] = {}
for platform in list_registered_platforms(platforms_dir, include_archived=True):
for platform in list_registered_platforms(platforms_dir):
config = load_platform_config(platform, platforms_dir)
names = platform_system_names(config, list(config.get("systems", {})))
for owner, spelled in names.items():
+1 -9
View File
@@ -999,10 +999,6 @@ def main() -> int:
help="emulator profile directory (default: %(default)s)",
)
parser.add_argument("--json", action="store_true", help="JSON output")
parser.add_argument(
"--include-archived", action="store_true",
help="with all platforms, the archived ones too (RetroPie)",
)
parser.add_argument(
"--target", "-t", help="judge only the cores a hardware target builds",
)
@@ -1028,14 +1024,10 @@ def main() -> int:
profiles = load_emulator_profiles(args.emulators_dir)
if args.platform:
require_platform(args.platform, args.platforms_dir)
if args.include_archived and args.platform:
parser.error("--include-archived widens the list of all platforms; --platform names one")
names = (
[args.platform]
if args.platform
else list_registered_platforms(
args.platforms_dir, include_archived=args.include_archived
)
else list_registered_platforms(args.platforms_dir)
)
target_cores: dict[str, set[str] | None] = {}
if args.target:
+1 -1
View File
@@ -193,7 +193,7 @@ def load_platform_hashes(platforms_dir: str, db: dict | None = None) -> dict:
# and a Recalbox md5 field split into the revisions it lists. The raw
# file kept "a,b,c" as one value, so a PR adding the seventh accepted
# falcon.img was told its hash differs.
for name in list_registered_platforms(platforms_dir, include_archived=True):
for name in list_registered_platforms(platforms_dir):
try:
config = load_platform_config(name, platforms_dir)
except (OSError, yaml.YAMLError) as exc:
+4 -6
View File
@@ -416,8 +416,8 @@ def _registry_contract() -> list[str]:
"""The registry against its schema, and a release that still ships a pack.
`release_pack` is the only list of the ZIPs a release publishes: a
registry where no active platform carries it would cut a release with
no pack at all, and every download link would lead to the command.
registry where no platform carries it would cut a release with no pack
at all, and every download link would lead to the command.
"""
registry_path = ROOT / "platforms" / "_registry.yml"
if not registry_path.is_file():
@@ -428,12 +428,10 @@ def _registry_contract() -> list[str]:
out = _errors(_validator("registry.schema.json"), registry, label)
platforms = registry.get("platforms") or {}
if isinstance(platforms, dict) and not any(
isinstance(entry, dict)
and entry.get("release_pack") is True
and entry.get("status", "active") == "active"
isinstance(entry, dict) and entry.get("release_pack") is True
for entry in platforms.values()
):
out.append(f"{label}: no active platform has release_pack: true")
out.append(f"{label}: no platform has release_pack: true")
return out
+2 -2
View File
@@ -410,9 +410,9 @@ def _check_get_pages(
if not (platforms_dir / "_registry.yml").is_file():
return [f"no platform registry in {platforms_dir}"]
record = release_record.load_advertised(record_path, str(platforms_dir))
released = set(list_release_pack_platforms(str(platforms_dir), include_archived=True))
released = set(list_release_pack_platforms(str(platforms_dir)))
issues: list[str] = []
for platform in list_registered_platforms(str(platforms_dir), include_archived=True):
for platform in list_registered_platforms(str(platforms_dir)):
rel = f"{release_record.GET_DIR}/{platform}/index.html"
page = pages.get((site / rel).resolve())
if page is None or page.redirect:
+2 -11
View File
@@ -18,7 +18,6 @@ Cross-references emulator profiles to detect undeclared files used by available
Usage:
python scripts/verify.py --all
python scripts/verify.py --platform batocera
python scripts/verify.py --all --include-archived
python scripts/verify.py --all --json
"""
@@ -2366,7 +2365,7 @@ def verify_emulator(
emu_results: dict[str, list[tuple[dict, bool, bool]]] = {}
for file_entry in files:
# Skip archived files (verified as archive units above)
# Skip archive members (verified as archive units above)
if file_entry.get("archive"):
continue
@@ -2754,7 +2753,6 @@ def _refuse_listing_narrowings(
("--region", getattr(args, "region", None)),
("--target", getattr(args, "target", None)),
("--standalone", args.standalone),
("--include-archived", args.include_archived),
("--json", args.json),
("--strict", args.strict),
("--verbose", args.verbose),
@@ -2774,7 +2772,6 @@ def _refuse_mode_flags(args: argparse.Namespace, parser: argparse.ArgumentParser
"--standalone requires --emulator or --system"),
(args.standalone and args.platform,
"--standalone is incompatible with --platform"),
(args.include_archived and not args.all, "--include-archived requires --all"),
(args.target and not (args.platform or args.all),
"--target requires --platform or --all"),
(args.target and (args.emulator or (args.system and not args.platform)),
@@ -2840,10 +2837,6 @@ def _main(held: contextlib.ExitStack) -> None:
parser.add_argument(
"--list-platforms", action="store_true", help="List available platforms"
)
parser.add_argument(
"--include-archived", action="store_true",
help="With --all, also verify the archived platforms (RetroPie)",
)
parser.add_argument("--target", "-t", help="Hardware target (e.g., switch, rpi4)")
parser.add_argument(
"--region", help="Region priority list, best first (e.g. us,eu,jp)"
@@ -2981,9 +2974,7 @@ def _main(held: contextlib.ExitStack) -> None:
# Platform mode (existing)
if args.all:
platforms = list_registered_platforms(
args.platforms_dir, include_archived=args.include_archived
)
platforms = list_registered_platforms(args.platforms_dir)
elif args.platform:
platforms = [args.platform]
else: