fix: file system cards by board, machine, engine

Every board set sits on its board page whatever folder holds it, a set a
reviewed machine owns joins that machine (neogeo.zip under SNK, the Atom
under Acorn, the MZ-2000 under Sharp), and a game engine's files form one
section named after it. Board pages drop the heading that repeated their
title, parts drop the Part of line their crumbs already say, and pages
that moved redirect.
This commit is contained in:
Abdessamad Derraz committed 2026-10-24 01:19:56 +02:00
1 parent 7d3d5b5efd
commit 4dd3800f11
7 files changed
+353 -52

No files matched your search

+2 -1
View File
@@ -361,7 +361,8 @@ class AVariantShowsWhoPinsIt(unittest.TestCase):
platforms={"c" * 40: {"batocera", "retrobat"}}, emulators={"a" * 40: {"mame"}})
page = generate_site.generate_system_page(
"Entex", {"Adventure Vision": [primary, variant]}, consumers)
block = page[page.index("<summary>Variants (1)</summary>"):]
# Another revision of a set sits open beside it (round 5, 6.3).
block = page[page.index('id="sha1-' + "c" * 12 + '"'):]
self.assertIn("<dt>Collection path</dt><dd><code>bios/Entex/Adventure Vision/"
".variants/advision.zip.1c086064</code>", block)
self.assertIn('<a href="../platforms/batocera.md">Batocera</a>', block)
+27 -1
View File
@@ -84,10 +84,36 @@ class MetaFields(unittest.TestCase):
match = re.search(r'data-pagefind-meta="aliases:([^"]*)"', text)
self.assertIsNotNone(match, "no aliases field on the PlayStation page")
self.assertIn("psx", unescape(match[1]).split())
dreamcast = (DOCS / "systems" / "sega-dreamcast.md").read_text(encoding="utf-8")
# The Dreamcast section's page: its own, or Sega's when it fits there.
own = DOCS / "systems" / "sega-dreamcast.md"
dreamcast = (own if own.is_file() else DOCS / "systems" / "sega.md").read_text(
encoding="utf-8")
self.assertRegex(dreamcast, r'data-pagefind-meta="aliases:[^"]*\bdc\b')
class SystemPartsSitUnderTheirMaker(unittest.TestCase):
"""The crumbs say where a system part sits, read from its parent: field.
The "Part of" line under them said it again (round 5, 6.9)."""
def test_every_part_names_its_maker_as_parent(self) -> None:
pages = sorted((DOCS / "systems").glob("*.md"))
if not pages:
self.skipTest("site pages not generated")
makers = {page.stem for page in pages}
orphans = []
for page in pages:
text = page.read_text(encoding="utf-8")
front = text.split("\n---\n", 1)[0]
parent = re.search(r"^parent:\n label: .+\n link: /retrobios/systems/([a-z0-9-]+)/$",
front, re.M)
if parent is None:
continue
if parent[1] not in makers:
orphans.append(page.name)
self.assertNotIn("\nPart of [", text, page.name)
self.assertEqual(orphans, [])
class MovedPlatformPages(unittest.TestCase):
def test_a_setups_list_for_one_console_is_a_reference(self) -> None:
source = Path(generate_site.__file__).read_text(encoding="utf-8")
+12 -7
View File
@@ -42,7 +42,7 @@ UNLINKED: dict[str, str] = {
"namco-nb1": "Arcade > FBNeo",
"omicron": "Other > omicron",
"rpgmaker": "RPG Maker > easyrpg",
"sdlpal": "Other > sdlpal",
"sdlpal": "the SDLPAL section under its own top, named after the program",
"sega-system16b": "Arcade > FBNeo, and isgsm.zip is also the ISG Selection Master's",
"smbx": "Game Engines > TheXTech",
"thomson-mo6": "Other > Clock Signal",
@@ -50,7 +50,6 @@ UNLINKED: dict[str, str] = {
# Files filed with another machine: a link would name the wrong one.
"commodore-c64-supercpu": "VICE's tree under the C128",
"emerson-arcadia-2001": "ar_bios.zip is filed with the Saturn",
"sega-dreamcast-arcade": "NAOMI, NAOMI 2 and Atomiswave sets, three boards",
"spectravideo": "the SVI ROMs are filed with the MSX",
"taito-type-x": "mame2010 files taitogn.zip, the G-NET BIOS, under this id",
"vvvvvv": "SDL's controller database",
@@ -105,7 +104,7 @@ class SystemLinks(unittest.TestCase):
load_platform_config,
resolve_local_file,
)
from generate_site import _copy_places, _group_by_manufacturer
from generate_site import _group_by_manufacturer, arcade_board_sections
with open("database.json", encoding="utf-8") as handle:
db = json.load(handle)
@@ -117,8 +116,9 @@ class SystemLinks(unittest.TestCase):
# (round 4, 6.4) and record it. The built pages are checked by
# the round 4 gate.
siterender.reset_console_pages()
for board in siterender.arcade_boards():
siterender.record_board_section(board)
# The sections as the system pages hold them: each board, the
# sets a reviewed machine owns under that machine.
cls.sections, _installs = arcade_board_sections(cls.manufacturers, {})
platforms = [
load_platform_config(name, "platforms")
for name in list_registered_platforms("platforms", include_archived=True)
@@ -141,7 +141,12 @@ class SystemLinks(unittest.TestCase):
for owner in owners:
entries.setdefault(owner, []).append(fe)
places = _copy_places(db)
# Where each content has a card.
places: dict[str, set[tuple[str, str, str]]] = {}
for mfr, consoles in cls.sections.items():
for console, files in consoles.items():
for f in files:
places.setdefault(f["sha1"], set()).add((mfr, console, f["name"]))
by_path = {entry.get("path"): sha1 for sha1, entry in db["files"].items()}
# Id -> the (manufacturer, console) sections holding its files.
cls.held: dict[str, set[tuple[str, str]]] = {}
@@ -210,7 +215,7 @@ class SystemLinks(unittest.TestCase):
def test_parents_are_sections(self) -> None:
sections = {
(mfr, console)
for mfr, consoles in self.manufacturers.items() for console in consoles
for mfr, consoles in self.sections.items() for console in consoles
}
self.assertEqual(
sorted(k for k, v in siterender.SYSTEM_PARENTS.items() if v not in sections), [])
+4 -3
View File
@@ -59,7 +59,6 @@ STAYS_PLAIN = {
"fpinball": "scripten.exe, filed with Windows",
"pv1000": "only MAME's software list pv1000.xml",
"vc4000": "only MAME's software list vc4000.xml",
"sega-dreamcast-arcade": "NAOMI, NAOMI 2 and Atomiswave sets, three boards",
"spectravideo": "the SVI ROMs are filed with the MSX",
"vgmplay": "sound chip sets, no board",
"vvvvvv": "SDL's controller database",
@@ -139,9 +138,11 @@ class Boards(unittest.TestCase):
slug = siterender.board_slug(board)
self.assertTrue(slug)
self.assertEqual(slug, toc_slug(name))
# The board's page is its section: no heading repeats its
# title (round 5, 6.8).
self.assertEqual(
siterender.console_href(*siterender.system_section(board)),
f"systems/arcade-{slug}.md#{slug}")
f"systems/arcade-{slug}.md")
def test_aliases_share_a_board(self) -> None:
"""Every id of one board's name leads to one section."""
@@ -171,7 +172,7 @@ class Boards(unittest.TestCase):
def test_parents_named_by_the_plan(self) -> None:
expect = {
"dos": ("dos", "DOSBox"),
"scummvm": ("other", "ScummVM"),
"scummvm": ("scummvm", "ScummVM"),
"tyrian": ("other", "opentyrian"),
"bbc-master-128": ("other", "beebem"),
}
+7 -2
View File
@@ -161,10 +161,12 @@ class EachArcadeBoardHasASection(unittest.TestCase):
"""6.4: the Arcade page was cut by storage folder."""
def test_each_board_heads_its_page(self) -> None:
# The page's title names the board, no h2 says it again (round 5, 6.8).
for name in BOARDS:
slug = toc_slug(name)
html = _page(DIST / "systems" / f"arcade-{slug}" / "index.html")
self.assertRegex(html, rf'<h2[^>]*id="{re.escape(slug)}"', name)
self.assertRegex(html, rf"<h1[^>]*>Arcade: {re.escape(name)}</h1>", name)
self.assertNotRegex(html, rf"<h2[^>]*>{re.escape(name)}<", name)
def test_every_board_on_an_emulator_systems_row_is_a_link(self) -> None:
if not (DIST / "emulators").is_dir():
@@ -223,7 +225,10 @@ class PartPagesKnowWhereTheyAre(unittest.TestCase):
orphans, numbered = [], []
for page in sorted((CONTENT / "systems").glob("*.md*")):
text = page.read_text(encoding="utf-8")
if "Part of " in text and "\nparent:" not in text.split("\n---\n", 1)[0]:
# A part is titled "<maker>: <console>" or "<name> files a to b".
title = re.search(r"^title: (.*)$", text, re.M)
part = title and (": " in title[1] or re.search(r" files .+ to ", title[1]))
if part and "\nparent:" not in text.split("\n---\n", 1)[0]:
orphans.append(page.name)
if re.search(r"^title: .*part \d+ of \d+", text, re.M | re.I):
numbered.append(page.name)