mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-06 10:03:49 -06:00
fix: read the given profiles and platform files
Five generate_site helpers read ./emulators or ./platforms, and has_release_pack read platforms relative to the working directory: run from scripts/, a released setup's get page showed the No ZIP line. siterender's fallbacks and sitediagrams read the repository too. All of them now read siteinputs. platforms/_guides.yml stays the repository's: siteguides loads it at import, before any flag is parsed.
This commit is contained in:
1 parent
8022ef4cb3
commit
9b871db83a
5 files changed
+145
-51
No files matched your search
+44
-32
@@ -663,7 +663,7 @@ def release_line(platform_name: str, record: dict) -> list[str]:
|
||||
f"[SHA256SUMS.txt]({base}/SHA256SUMS.txt) and its "
|
||||
f"[signature]({base}/SHA256SUMS.txt.sig).",
|
||||
]
|
||||
config = load_platform_config(platform_name, "platforms")
|
||||
config = load_platform_config(platform_name, str(siteinputs.current().platforms))
|
||||
page_version = str(config.get("version") or "")
|
||||
pack_version = _pack_version(pack_name)
|
||||
if page_version and pack_version and page_version.lstrip("v") != pack_version.lstrip("v"):
|
||||
@@ -688,7 +688,7 @@ def setup_version(platform_name: str, record: dict | None = None) -> str:
|
||||
platform YAML was read at. Empty when neither says, or when the
|
||||
platform has no YAML to read a version from."""
|
||||
try:
|
||||
config = load_platform_config(platform_name, "platforms")
|
||||
config = load_platform_config(platform_name, str(siteinputs.current().platforms))
|
||||
except FileNotFoundError:
|
||||
return ""
|
||||
pack_name = release_record.pack_name_for(platform_name, record or {})
|
||||
@@ -715,8 +715,7 @@ NO_ZIP_FAQ = "wiki/faq.md#why-is-there-no-zip-for-my-setup"
|
||||
|
||||
def has_release_pack(platform_name: str) -> bool:
|
||||
"""Whether a release publishes a ZIP for the platform (`release_pack`)."""
|
||||
entry = load_platform_registry("platforms").get(platform_name) or {}
|
||||
return entry.get("release_pack") is True
|
||||
return platform_name in _release_pack_platforms()
|
||||
|
||||
|
||||
def no_zip_line(display: str) -> str:
|
||||
@@ -735,7 +734,7 @@ def get_page_title(platform_name: str, display: str) -> str:
|
||||
the system's own download. A setup that is also an emulator (BizHawk)
|
||||
names it last: "BizHawk BIOS files" is the title of its emulator page."""
|
||||
kind = "BIOS pack" if has_release_pack(platform_name) else "BIOS files"
|
||||
if (_REPO_ROOT / "emulators" / f"{platform_name}.yml").is_file():
|
||||
if (siteinputs.current().emulators / f"{platform_name}.yml").is_file():
|
||||
return f"{kind} for {display}"
|
||||
return f"{display} {kind}"
|
||||
|
||||
@@ -780,7 +779,7 @@ def _pack_buttons(platform_name: str, label: str = "Pack", prefix: str = "../",
|
||||
frontend user asks. A setup with no release pack gets the line that
|
||||
says so, and why."""
|
||||
if not has_release_pack(platform_name):
|
||||
display = display or load_platform_config(platform_name, "platforms").get(
|
||||
display = display or load_platform_config(platform_name, str(siteinputs.current().platforms)).get(
|
||||
"platform", platform_name)
|
||||
return f"{no_zip_line(display)} [Why no ZIP?]({prefix}{NO_ZIP_FAQ})"
|
||||
record = release_record.load_advertised()
|
||||
@@ -805,7 +804,7 @@ def generate_get_page(platform_name: str) -> str:
|
||||
the files of the pack the current release holds, read from release.json,
|
||||
or the command when no release publishes one. The release process
|
||||
never touches it: committing release.json rebuilds it."""
|
||||
config = load_platform_config(platform_name, "platforms")
|
||||
config = load_platform_config(platform_name, str(siteinputs.current().platforms))
|
||||
display = config.get("platform", platform_name)
|
||||
record = release_record.load_advertised()
|
||||
pack = release_record.pack_for(platform_name, record)
|
||||
@@ -824,7 +823,7 @@ def generate_get_page(platform_name: str) -> str:
|
||||
if released and pack and pack.get("assets"):
|
||||
parts = len(pack["assets"])
|
||||
release = release_line(platform_name, record)
|
||||
extract_to = (load_platform_registry("platforms").get(platform_name) or {}).get("extract_to")
|
||||
extract_to = (load_platform_registry(str(siteinputs.current().platforms)).get(platform_name) or {}).get("extract_to")
|
||||
lines += [
|
||||
"This address stays the same. It always gives the latest ZIP.",
|
||||
"",
|
||||
@@ -873,7 +872,7 @@ def generate_get_page(platform_name: str) -> str:
|
||||
def generate_get_index() -> str:
|
||||
"""get/: the permanent page of every setup, grouped as the home tiles
|
||||
are. A link trimmed to /get/ answered 404."""
|
||||
registry = load_platform_registry("platforms")
|
||||
registry = load_platform_registry(str(siteinputs.current().platforms))
|
||||
lines = [
|
||||
"---", "search: exclude",
|
||||
'description: "The BIOS files of every setup, one page each. Each address stays the same."',
|
||||
@@ -887,7 +886,7 @@ def generate_get_index() -> str:
|
||||
continue
|
||||
lines += [f"## {label}", ""]
|
||||
for name in names:
|
||||
display = load_platform_config(name, "platforms").get("platform", name)
|
||||
display = load_platform_config(name, str(siteinputs.current().platforms)).get("platform", name)
|
||||
lines.append(f"- [{get_page_title(name, display)}]({name}.md)")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
@@ -1068,10 +1067,13 @@ def _split_contract(config: dict) -> tuple[dict, dict]:
|
||||
return contract, registry
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _release_pack_platforms() -> frozenset[str]:
|
||||
return frozenset(list_release_pack_platforms(
|
||||
str(_REPO_ROOT / "platforms"), include_archived=True))
|
||||
return _release_packs_in(str(siteinputs.current().platforms))
|
||||
|
||||
|
||||
@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))
|
||||
|
||||
|
||||
# Per-entry fields a folder check needs beyond the hashes: an md5 is a ZIP
|
||||
@@ -2105,7 +2107,7 @@ def _short_sha256(item: dict, catalog: str) -> str:
|
||||
|
||||
def _platforms_without_a_list(platforms_dir: Path | None = None) -> list[str]:
|
||||
"""The names of the platforms whose registry says they keep no list."""
|
||||
platforms_dir = platforms_dir or _REPO_ROOT / "platforms"
|
||||
platforms_dir = platforms_dir or siteinputs.current().platforms
|
||||
names = []
|
||||
for key, entry in sorted(load_platform_registry(str(platforms_dir)).items()):
|
||||
if entry.get("native_list") != "none":
|
||||
@@ -3538,7 +3540,7 @@ def _system_named_link(sys_id: str, prefix: str = "") -> str:
|
||||
def _emulator_named_link(key: str, prefix: str = "") -> str:
|
||||
"""An emulator by the name its page carries, linked to that page. A
|
||||
profile with no page (an alias, a test) is named only."""
|
||||
profile = load_emulator_profiles(str(_REPO_ROOT / "emulators"), skip_aliases=False).get(key, {})
|
||||
profile = _profiles_on_disk().get(key, {})
|
||||
label = _escape_tags(str(profile.get("emulator") or key))
|
||||
if profile.get("type") in ("alias", "test"):
|
||||
return label
|
||||
@@ -3928,10 +3930,9 @@ def _platform_data_links(name: str) -> str:
|
||||
return ", ".join(links)
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _site_profiles() -> dict[str, dict]:
|
||||
"""Every emulator profile, read once for the citations of a page."""
|
||||
return load_emulator_profiles(str(_REPO_ROOT / "emulators"))
|
||||
return _profiles_in(str(siteinputs.current().emulators), skip_aliases=True)
|
||||
|
||||
|
||||
# Whose code a source reference cites, in one word: a platform page names
|
||||
@@ -4015,13 +4016,17 @@ def _category_evidence_md(evidence: dict, launched: list[str] | None = None) ->
|
||||
return f"No reader found ({cores})"
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _profiles_by_core_name() -> dict[str, list[str]]:
|
||||
"""Core name as a platform writes it -> the profiles with a page for it.
|
||||
|
||||
MinUI writes `mednafen_vb`, the profile and its page are `beetle_vb`.
|
||||
"""
|
||||
profiles = load_emulator_profiles(str(_REPO_ROOT / "emulators"))
|
||||
return _core_names_in(str(siteinputs.current().emulators))
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
def _core_names_in(emulators_dir: str) -> dict[str, list[str]]:
|
||||
profiles = _profiles_in(emulators_dir, skip_aliases=True)
|
||||
with_page = {k for k, v in profiles.items() if v.get("type") not in ("alias", "test")}
|
||||
return {
|
||||
core: sorted(k for k in keys if k in with_page)
|
||||
@@ -4191,7 +4196,7 @@ def _card_route(name: str, display: str, guide: Guide) -> list[str]:
|
||||
sees it is the reader's to name: no guide cites it."""
|
||||
if guide.on_card or _offline_line(name):
|
||||
return []
|
||||
extract_to = (load_platform_registry("platforms").get(name) or {}).get("extract_to")
|
||||
extract_to = (load_platform_registry(str(siteinputs.current().platforms)).get(name) or {}).get("extract_to")
|
||||
leaf = (extract_to or "bios").rstrip("/").rsplit("/", 1)[-1].lstrip("~") or "bios"
|
||||
tabs = guide.card_run or ("windows", "macos", "linux")
|
||||
args = {key: f"--platform {name} --dest "
|
||||
@@ -4392,7 +4397,7 @@ def generate_handheld_guide(guide: HandheldGuide) -> str:
|
||||
A handheld owner starts from the device name. The systems were named
|
||||
only in a closed note, with a path seen from inside the device."""
|
||||
uses = GUIDES[guide.uses]
|
||||
display = load_platform_config(guide.uses, "platforms").get("platform", guide.uses)
|
||||
display = load_platform_config(guide.uses, str(siteinputs.current().platforms)).get("platform", guide.uses)
|
||||
args = {"windows": f"--platform {guide.uses} --dest E:\\BIOS",
|
||||
"macos": f"--platform {guide.uses} --dest /path/to/card/BIOS",
|
||||
"linux": f"--platform {guide.uses} --dest /path/to/card/BIOS"}
|
||||
@@ -4447,7 +4452,7 @@ def _platform_guide(name: str, display: str, cov: dict, registry: dict, no_list:
|
||||
lines.append("")
|
||||
for note in guide.notes:
|
||||
lines += [note, ""]
|
||||
lines += [line for note in extract_notes("platforms", released_only=True)
|
||||
lines += [line for note in extract_notes(str(siteinputs.current().platforms), released_only=True)
|
||||
if f"The {display} pack " in note
|
||||
for line in (note, "")]
|
||||
if guide.more_folders:
|
||||
@@ -4922,7 +4927,7 @@ def _data_member_digests(
|
||||
from hashing import compute_hashes # noqa: PLC0415
|
||||
|
||||
if data_registry is None:
|
||||
data_registry = load_data_dir_registry(str(root / "platforms"))
|
||||
data_registry = load_data_dir_registry(str(siteinputs.current().platforms))
|
||||
found: dict[str, dict[str, str]] = {}
|
||||
for ref, tree in sorted(members.items()):
|
||||
cache = (data_registry.get(ref) or {}).get("local_cache")
|
||||
@@ -5810,7 +5815,7 @@ def _platform_display(name: str) -> str:
|
||||
display = _platform_names.get(name)
|
||||
if display is None:
|
||||
try:
|
||||
config = load_platform_config(name, str(_REPO_ROOT / "platforms"))
|
||||
config = load_platform_config(name, str(siteinputs.current().platforms))
|
||||
except FileNotFoundError:
|
||||
config = {}
|
||||
display = _platform_names[name] = str(config.get("platform") or name)
|
||||
@@ -6607,11 +6612,13 @@ def _reading_pairs(sha1: str, consumers: FileConsumers) -> list[tuple[str, dict]
|
||||
return pairs
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _profiles_on_disk() -> dict[str, dict]:
|
||||
from common import load_emulator_profiles # noqa: PLC0415
|
||||
return _profiles_in(str(siteinputs.current().emulators), skip_aliases=False)
|
||||
|
||||
return load_emulator_profiles(str(_REPO_ROOT / "emulators"), skip_aliases=False)
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
def _profiles_in(emulators_dir: str, skip_aliases: bool) -> dict[str, dict]:
|
||||
return load_emulator_profiles(emulators_dir, skip_aliases=skip_aliases)
|
||||
|
||||
|
||||
def _entry_systems(emulator: str, entry: dict) -> list[str]:
|
||||
@@ -8931,10 +8938,14 @@ def emulator_install_route(name: str, profile: dict) -> tuple[str, list[str], tu
|
||||
return command, setups, oses
|
||||
|
||||
|
||||
@functools.cache
|
||||
def _standalone_cores(platform: str) -> frozenset[str]:
|
||||
"""The emulators a setup launches as apps, by its platform file."""
|
||||
config = load_platform_config(platform, str(_REPO_ROOT / "platforms"))
|
||||
return _standalone_cores_in(str(siteinputs.current().platforms), platform)
|
||||
|
||||
|
||||
@functools.cache
|
||||
def _standalone_cores_in(platforms_dir: str, platform: str) -> frozenset[str]:
|
||||
config = load_platform_config(platform, platforms_dir)
|
||||
return frozenset(str(c) for c in config.get("standalone_cores") or [])
|
||||
|
||||
|
||||
@@ -11787,7 +11798,7 @@ def _own_root_folders(registry: dict) -> dict[str, str]:
|
||||
destination carries its root in every path."""
|
||||
folders = {}
|
||||
for key, entry in registry.items():
|
||||
config = load_platform_config(key, "platforms")
|
||||
config = load_platform_config(key, str(siteinputs.current().platforms))
|
||||
if config.get("base_destination") == "" and entry.get("extract_to"):
|
||||
folders[key] = entry["extract_to"]
|
||||
return folders
|
||||
@@ -11887,9 +11898,10 @@ def generate_which_pack() -> str:
|
||||
|
||||
The tiles are the choice. Open tables under them listed every setup a
|
||||
second time and made the page 11,800 px tall on a phone."""
|
||||
registry = load_platform_registry("platforms")
|
||||
registry = load_platform_registry(str(siteinputs.current().platforms))
|
||||
record = release_record.load_advertised()
|
||||
display = {key: load_platform_config(key, "platforms").get("platform", key) for key in registry}
|
||||
display = {key: load_platform_config(key, str(siteinputs.current().platforms)).get("platform", key)
|
||||
for key in registry}
|
||||
all_tabs = ("windows", "macos", "linux", "steamdeck", "android")
|
||||
lines = [
|
||||
"---",
|
||||
|
||||
+27
-10
@@ -36,6 +36,7 @@ from xml.sax.saxutils import escape
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "scripts"))
|
||||
|
||||
import siteinputs # noqa: E402
|
||||
import sitemarkup as markup # noqa: E402
|
||||
|
||||
PLACEHOLDER = re.compile(r"(?m)^([ \t]*)<!--\s*image:\s*([A-Za-z0-9_-]+)\s*-->[ \t]*$")
|
||||
@@ -314,21 +315,29 @@ def svg(figure: Figure, layout: str, suffix: str) -> str:
|
||||
# Data
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def registry() -> dict:
|
||||
return _registry_in(str(siteinputs.current().platforms))
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _registry_in(platforms_dir: str) -> dict:
|
||||
import yaml
|
||||
|
||||
with open(ROOT / "platforms" / "_registry.yml", encoding="utf-8") as handle:
|
||||
with open(Path(platforms_dir) / "_registry.yml", encoding="utf-8") as handle:
|
||||
return yaml.safe_load(handle).get("platforms", {})
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
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."""
|
||||
return _setups_in(str(siteinputs.current().platforms))
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _setups_in(platforms_dir: str) -> tuple[str, ...]:
|
||||
from common import list_registered_platforms
|
||||
|
||||
return tuple(sorted(list_registered_platforms(str(ROOT / "platforms"), include_archived=True)))
|
||||
return tuple(sorted(list_registered_platforms(platforms_dir, include_archived=True)))
|
||||
|
||||
|
||||
def setups_named(named: list[str]) -> str:
|
||||
@@ -339,15 +348,19 @@ def setups_named(named: list[str]) -> str:
|
||||
return ", ".join(named) + (f" and {others} more" if others else "")
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def platform_modes() -> dict[str, tuple[str, str, str | None]]:
|
||||
"""name -> (display name, verification mode, hash rule) for every platform."""
|
||||
return _platform_modes_in(str(siteinputs.current().platforms))
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _platform_modes_in(platforms_dir: str) -> dict[str, tuple[str, str, str | None]]:
|
||||
from common import load_platform_config
|
||||
|
||||
out: dict[str, tuple[str, str, str | None]] = {}
|
||||
for name in setups():
|
||||
config = load_platform_config(name, str(ROOT / "platforms"))
|
||||
rule = registry().get(name, {}).get("hash_rule") or config.get("hash_rule")
|
||||
for name in _setups_in(platforms_dir):
|
||||
config = load_platform_config(name, platforms_dir)
|
||||
rule = _registry_in(platforms_dir).get(name, {}).get("hash_rule") or config.get("hash_rule")
|
||||
out[name] = (config.get("platform", name), config.get("verification_mode", ""), rule)
|
||||
return out
|
||||
|
||||
@@ -365,13 +378,17 @@ def _folder(name: str) -> str:
|
||||
CHAIN_EXAMPLES = (("batocera", "duckstation"), ("emudeck", "pcsx2"), ("retroarch", "beetle_psx"))
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def emulator_names() -> dict[str, str]:
|
||||
return _emulator_names_in(str(siteinputs.current().emulators))
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _emulator_names_in(emulators_dir: str) -> dict[str, str]:
|
||||
import yaml
|
||||
|
||||
names: dict[str, str] = {}
|
||||
for _, emulator in CHAIN_EXAMPLES:
|
||||
with open(ROOT / "emulators" / f"{emulator}.yml", encoding="utf-8") as handle:
|
||||
with open(Path(emulators_dir) / f"{emulator}.yml", encoding="utf-8") as handle:
|
||||
label = str(yaml.safe_load(handle).get("emulator", emulator))
|
||||
names[emulator] = re.sub(r"\s*\(.*\)$", "", label)
|
||||
return names
|
||||
|
||||
@@ -7,6 +7,7 @@ import urllib.parse
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
|
||||
import siteinputs
|
||||
import sitemarkup as markup
|
||||
|
||||
|
||||
@@ -401,7 +402,8 @@ def _build_boards() -> None:
|
||||
|
||||
from common import load_emulator_profiles
|
||||
|
||||
database = _REPO_ROOT / "database.json"
|
||||
inputs = siteinputs.current()
|
||||
database = inputs.db
|
||||
if not database.exists():
|
||||
_archive_boards.clear()
|
||||
_board_names.clear()
|
||||
@@ -409,7 +411,7 @@ def _build_boards() -> None:
|
||||
return
|
||||
with open(database, encoding="utf-8") as handle:
|
||||
db = json.load(handle)
|
||||
profiles = load_emulator_profiles(str(_REPO_ROOT / "emulators"), skip_aliases=False)
|
||||
profiles = load_emulator_profiles(str(inputs.emulators), skip_aliases=False)
|
||||
_arcade_source[0] = (profiles, db)
|
||||
profiles, db = _arcade_source[0]
|
||||
files = db.get("files", {})
|
||||
@@ -780,9 +782,10 @@ def _ensure_console_sections() -> None:
|
||||
from common import load_emulator_profiles
|
||||
from generate_site import _group_by_manufacturer
|
||||
|
||||
with open(_REPO_ROOT / "database.json", encoding="utf-8") as handle:
|
||||
inputs = siteinputs.current()
|
||||
with open(inputs.db, encoding="utf-8") as handle:
|
||||
db = json.load(handle)
|
||||
profiles = load_emulator_profiles(str(_REPO_ROOT / "emulators"), skip_aliases=False)
|
||||
profiles = load_emulator_profiles(str(inputs.emulators), skip_aliases=False)
|
||||
set_console_sections(_group_by_manufacturer(db), program_names(profiles))
|
||||
|
||||
|
||||
@@ -1431,7 +1434,7 @@ def system_search_aliases(sys_id: str) -> list[str]:
|
||||
platform_system_names,
|
||||
)
|
||||
|
||||
platforms_dir = str(_REPO_ROOT / "platforms")
|
||||
platforms_dir = str(siteinputs.current().platforms)
|
||||
index: dict[str, set[str]] = {}
|
||||
for platform in list_registered_platforms(platforms_dir, include_archived=True):
|
||||
config = load_platform_config(platform, platforms_dir)
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
"""generate_site --db reaches every page.
|
||||
"""generate_site --db, --emulators-dir and --platforms-dir reach every page.
|
||||
|
||||
The run loaded the given database, but the page-finishing pass reloaded the
|
||||
repository's database.json: a card held only by the given collection stopped
|
||||
the whole run on a KeyError.
|
||||
the whole run on a KeyError. The emulator names and engine sections came from
|
||||
./emulators, and has_release_pack read `platforms` relative to the working
|
||||
directory, so a get/ page said "No ZIP" for a setup the API marked as released.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -19,6 +22,7 @@ REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
||||
|
||||
import generate_site # noqa: E402
|
||||
import sitediagrams # noqa: E402
|
||||
import siteinputs # noqa: E402
|
||||
|
||||
SHA1 = "0123456789ab" + "c" * 28
|
||||
@@ -47,7 +51,65 @@ class TheGivenDatabase(_Inputs):
|
||||
self.assertEqual(generate_site._collection_sha1_by_path(), {"bios/X/only-here.bin": SHA1})
|
||||
|
||||
|
||||
class GenerateInstallsTheInputs(unittest.TestCase):
|
||||
class TheGivenProfilesAndPlatforms(_Inputs):
|
||||
def setUp(self) -> None:
|
||||
tmp = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp" if (REPO_ROOT / "tmp").is_dir() else None))
|
||||
self.addCleanup(shutil.rmtree, tmp)
|
||||
self.emulators = tmp / "emulators"
|
||||
self.emulators.mkdir()
|
||||
(self.emulators / "fixturecore.yml").write_text(
|
||||
"emulator: Fixture Core\ntype: libretro\nsystems: [fixture-system]\nfiles: []\n")
|
||||
self.platforms = tmp / "platforms"
|
||||
shutil.copytree(REPO_ROOT / "platforms", self.platforms)
|
||||
|
||||
def test_emulator_names_come_from_the_given_profiles(self) -> None:
|
||||
self.use(emulators=self.emulators)
|
||||
self.assertEqual(set(generate_site._profiles_on_disk()), {"fixturecore"})
|
||||
self.assertEqual(generate_site._emulator_named_link("fixturecore"),
|
||||
"[Fixture Core](emulators/fixturecore.md)")
|
||||
|
||||
def test_release_pack_does_not_depend_on_the_working_directory(self) -> None:
|
||||
released = generate_site._release_pack_platforms()
|
||||
self.assertIn("retroarch", released)
|
||||
here = os.getcwd()
|
||||
os.chdir(REPO_ROOT / "scripts")
|
||||
self.addCleanup(os.chdir, here)
|
||||
self.assertTrue(generate_site.has_release_pack("retroarch"))
|
||||
self.assertEqual(generate_site.get_page_title("retroarch", "RetroArch"), "RetroArch BIOS pack")
|
||||
|
||||
def test_the_registry_comes_from_the_given_platforms(self) -> None:
|
||||
registry = self.platforms / "_registry.yml"
|
||||
registry.write_text(registry.read_text().replace("release_pack: true", "release_pack: false"))
|
||||
self.use(platforms=self.platforms)
|
||||
self.assertFalse(generate_site.has_release_pack("retroarch"))
|
||||
self.assertEqual(sitediagrams.registry()["retroarch"].get("release_pack"), False)
|
||||
|
||||
|
||||
class NoPageModuleReadsTheRepositoryInputs(unittest.TestCase):
|
||||
"""A helper that opens the repository's database, profiles or platform
|
||||
files itself bypasses the flags. siteinputs.current() is the one source."""
|
||||
|
||||
MODULES = ("generate_site.py", "siterender.py", "sitediagrams.py")
|
||||
INPUTS = {"database.json", "emulators", "platforms"}
|
||||
|
||||
def test_no_literal_input_path(self) -> None:
|
||||
found = []
|
||||
for module in self.MODULES:
|
||||
tree = ast.parse((REPO_ROOT / "scripts" / module).read_text(encoding="utf-8"))
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Div) \
|
||||
and getattr(node.left, "id", "") in ("_REPO_ROOT", "ROOT") \
|
||||
and isinstance(node.right, ast.Constant) and node.right.value in self.INPUTS:
|
||||
found.append(f"{module}:{node.lineno}")
|
||||
if isinstance(node, ast.Call) and getattr(node.func, "id", getattr(node.func, "attr", "")) in (
|
||||
"load_platform_config", "load_platform_registry", "load_emulator_profiles",
|
||||
"list_registered_platforms", "load_database", "extract_notes",
|
||||
"load_data_dir_registry"):
|
||||
for arg in node.args:
|
||||
if isinstance(arg, ast.Constant) and arg.value in self.INPUTS:
|
||||
found.append(f"{module}:{node.lineno}")
|
||||
self.assertEqual(found, [])
|
||||
|
||||
def test_generate_installs_the_inputs_first(self) -> None:
|
||||
source = ast.get_source_segment(
|
||||
(REPO_ROOT / "scripts" / "generate_site.py").read_text(encoding="utf-8"),
|
||||
|
||||
@@ -65,7 +65,7 @@ Every module in `tests/`, by the area it guards.
|
||||
| Pack probe | the cores a platform runs for a system, staging grown to a fixed point, runs mapped to pack and manifest entries, the line and its schema, the probe lock per run, that no page shows its lines. One class builds a real pack narrowed to PlayStation and lays it out both ways, from the archive and with `install.py --dest`, and skips without the collection | `test_pack_probe` |
|
||||
| Automation runner, disk cleanup, asset sync and bit-flip repair | fake jobs, git repositories with a bare origin and session worktrees, a committed file with one bit flipped, canned CI runs in place of `gh` | `test_autorun` |
|
||||
| Truth and native export | synthetic + cached originals | `test_export_counts`, `test_export_native_layer`, `test_export_report`, `test_exporters`, `test_truth_data_dir_readers`, `test_truth_diff`, `test_truth_layout` |
|
||||
| Scrapers, upstream and provenance | inline sources, synthetic | `test_batocera_md5_list`, `test_check_freshness`, `test_cited_lines`, `test_contributing_text`, `test_coverage_cache`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_dedup`, `test_doc_pages`, `test_doc_surfaces`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_optional_dependencies`, `test_pin_build`, `test_profile_sync`, `test_prose_style`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_retired_files`, `test_romset_recipes`, `test_schema_semantic_gate`, `test_scraper_contract`, `test_site_arcade_boards`, `test_site_availability`, `test_site_bootstrap`, `test_site_built_gate`, `test_site_components`, `test_site_console_folders`, `test_site_content_data`, `test_site_copy`, `test_site_cores`, `test_site_css`, `test_site_density_cards`, `test_site_emulator_page`, `test_site_emulators`, `test_site_entry`, `test_site_entry_tables`, `test_site_exports`, `test_site_funnel`, `test_site_images`, `test_site_integration`, `test_site_nav`, `test_site_picker`, `test_site_platform_density`, `test_site_platform_hashes`, `test_site_reference`, `test_site_render`, `test_site_search`, `test_site_system_links`, `test_site_system_names`, `test_site_system_sections`, `test_site_systems`, `test_site_validation`, `test_site_weight`, `test_site_wiki`, `test_site_write`, `test_source_ref_targets`, `test_upstream`, `test_upstream_index`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_version_basis`, `test_workflow_paths` |
|
||||
| Scrapers, upstream and provenance | inline sources, synthetic | `test_batocera_md5_list`, `test_check_freshness`, `test_cited_lines`, `test_contributing_text`, `test_coverage_cache`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_dedup`, `test_doc_pages`, `test_doc_surfaces`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_optional_dependencies`, `test_pin_build`, `test_profile_sync`, `test_prose_style`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_retired_files`, `test_romset_recipes`, `test_schema_semantic_gate`, `test_scraper_contract`, `test_site_arcade_boards`, `test_site_availability`, `test_site_bootstrap`, `test_site_built_gate`, `test_site_components`, `test_site_console_folders`, `test_site_content_data`, `test_site_copy`, `test_site_cores`, `test_site_css`, `test_site_density_cards`, `test_site_emulator_page`, `test_site_emulators`, `test_site_entry`, `test_site_entry_tables`, `test_site_exports`, `test_site_funnel`, `test_site_images`, `test_site_inputs`, `test_site_integration`, `test_site_nav`, `test_site_picker`, `test_site_platform_density`, `test_site_platform_hashes`, `test_site_reference`, `test_site_render`, `test_site_search`, `test_site_system_links`, `test_site_system_names`, `test_site_system_sections`, `test_site_systems`, `test_site_validation`, `test_site_weight`, `test_site_wiki`, `test_site_write`, `test_source_ref_targets`, `test_upstream`, `test_upstream_index`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_version_basis`, `test_workflow_paths` |
|
||||
| Games on the card | small DATs, listxml and setup sources, a fake fetcher, fixture install lists, and the committed data against its schemas | `test_arcade_parents`, `test_game_catalogs`, `test_game_headers`, `test_game_regions`, `test_games_index`, `test_romfolders_card`, `test_romfolders_es` |
|
||||
|
||||
## Test architecture
|
||||
|
||||
Reference in new issue
Block a user