mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-19 23:32:36 -05:00
refactor: review fixes, DRY coverage, filter test nav
- Extract compute_coverage to common.py (was duplicated) - Filter test cores from nav and emulator index - Use absolute URL for README download links - Consistent page titles with site name suffix - Safer mkdocs.yml nav rewrite with regex - Build all_platform_names once in gap analysis
This commit is contained in:
@@ -217,6 +217,27 @@ def resolve_local_file(
|
|||||||
return None, "not_found"
|
return None, "not_found"
|
||||||
|
|
||||||
|
|
||||||
|
def compute_coverage(platform_name: str, platforms_dir: str, db: dict) -> dict:
|
||||||
|
"""Compute BIOS coverage for a platform using verify logic."""
|
||||||
|
from verify import verify_platform
|
||||||
|
config = load_platform_config(platform_name, platforms_dir)
|
||||||
|
result = verify_platform(config, db)
|
||||||
|
present = result["ok"] + result["untested"]
|
||||||
|
pct = (present / result["total"] * 100) if result["total"] > 0 else 0
|
||||||
|
return {
|
||||||
|
"platform": config.get("platform", platform_name),
|
||||||
|
"total": result["total"],
|
||||||
|
"verified": result["ok"],
|
||||||
|
"untested": result["untested"],
|
||||||
|
"missing": result["missing"],
|
||||||
|
"present": present,
|
||||||
|
"percentage": pct,
|
||||||
|
"mode": config.get("verification_mode", "existence"),
|
||||||
|
"details": result["details"],
|
||||||
|
"config": config,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def safe_extract_zip(zip_path: str, dest_dir: str) -> None:
|
def safe_extract_zip(zip_path: str, dest_dir: str) -> None:
|
||||||
"""Extract a ZIP file safely, preventing zip-slip path traversal."""
|
"""Extract a ZIP file safely, preventing zip-slip path traversal."""
|
||||||
dest = os.path.realpath(dest_dir)
|
dest = os.path.realpath(dest_dir)
|
||||||
|
|||||||
@@ -18,33 +18,10 @@ from datetime import datetime, timezone
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
from common import load_database, load_platform_config
|
from common import load_database, compute_coverage
|
||||||
|
|
||||||
try:
|
|
||||||
import yaml
|
|
||||||
except ImportError:
|
|
||||||
yaml = None
|
|
||||||
|
|
||||||
SITE_URL = "https://abdess.github.io/retrobios/"
|
SITE_URL = "https://abdess.github.io/retrobios/"
|
||||||
RELEASE_URL = "../../releases/latest"
|
RELEASE_URL = "https://github.com/Abdess/retrobios/releases/latest"
|
||||||
|
|
||||||
|
|
||||||
def _compute_coverage(platform_name: str, platforms_dir: str, db: dict) -> dict:
|
|
||||||
from verify import verify_platform
|
|
||||||
config = load_platform_config(platform_name, platforms_dir)
|
|
||||||
result = verify_platform(config, db)
|
|
||||||
present = result["ok"] + result["untested"]
|
|
||||||
pct = (present / result["total"] * 100) if result["total"] > 0 else 0
|
|
||||||
return {
|
|
||||||
"platform": config.get("platform", platform_name),
|
|
||||||
"total": result["total"],
|
|
||||||
"verified": result["ok"],
|
|
||||||
"untested": result["untested"],
|
|
||||||
"missing": result["missing"],
|
|
||||||
"present": present,
|
|
||||||
"percentage": pct,
|
|
||||||
"mode": config.get("verification_mode", "existence"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def generate_readme(db: dict, platforms_dir: str) -> str:
|
def generate_readme(db: dict, platforms_dir: str) -> str:
|
||||||
@@ -61,7 +38,7 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
|
|||||||
coverages = {}
|
coverages = {}
|
||||||
for name in platform_names:
|
for name in platform_names:
|
||||||
try:
|
try:
|
||||||
coverages[name] = _compute_coverage(name, platforms_dir, db)
|
coverages[name] = compute_coverage(name, platforms_dir, db)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
+16
-33
@@ -26,7 +26,7 @@ except ImportError:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
from common import load_database, load_platform_config
|
from common import load_database, load_platform_config, compute_coverage
|
||||||
|
|
||||||
DOCS_DIR = "docs"
|
DOCS_DIR = "docs"
|
||||||
SITE_NAME = "RetroBIOS"
|
SITE_NAME = "RetroBIOS"
|
||||||
@@ -67,25 +67,6 @@ def _status_icon(pct: float) -> str:
|
|||||||
# Coverage computation (reuses verify.py logic)
|
# Coverage computation (reuses verify.py logic)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _compute_coverage(platform_name: str, platforms_dir: str, db: dict) -> dict:
|
|
||||||
from verify import verify_platform
|
|
||||||
config = load_platform_config(platform_name, platforms_dir)
|
|
||||||
result = verify_platform(config, db)
|
|
||||||
present = result["ok"] + result["untested"]
|
|
||||||
pct = (present / result["total"] * 100) if result["total"] > 0 else 0
|
|
||||||
return {
|
|
||||||
"platform": config.get("platform", platform_name),
|
|
||||||
"total": result["total"],
|
|
||||||
"verified": result["ok"],
|
|
||||||
"untested": result["untested"],
|
|
||||||
"missing": result["missing"],
|
|
||||||
"present": present,
|
|
||||||
"percentage": pct,
|
|
||||||
"mode": config.get("verification_mode", "existence"),
|
|
||||||
"details": result["details"],
|
|
||||||
"config": config,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Load emulator profiles
|
# Load emulator profiles
|
||||||
@@ -169,7 +150,7 @@ def generate_home(db: dict, coverages: dict, emulator_count: int,
|
|||||||
|
|
||||||
def generate_platform_index(coverages: dict) -> str:
|
def generate_platform_index(coverages: dict) -> str:
|
||||||
lines = [
|
lines = [
|
||||||
"# Platforms",
|
f"# Platforms - {SITE_NAME}",
|
||||||
"",
|
"",
|
||||||
"| Platform | Coverage | Verification | Status |",
|
"| Platform | Coverage | Verification | Status |",
|
||||||
"|----------|----------|-------------|--------|",
|
"|----------|----------|-------------|--------|",
|
||||||
@@ -276,7 +257,7 @@ def _group_by_manufacturer(db: dict) -> dict[str, dict[str, list]]:
|
|||||||
|
|
||||||
def generate_systems_index(manufacturers: dict) -> str:
|
def generate_systems_index(manufacturers: dict) -> str:
|
||||||
lines = [
|
lines = [
|
||||||
"# Systems",
|
f"# Systems - {SITE_NAME}",
|
||||||
"",
|
"",
|
||||||
"| Manufacturer | Consoles | Files |",
|
"| Manufacturer | Consoles | Files |",
|
||||||
"|-------------|----------|-------|",
|
"|-------------|----------|-------|",
|
||||||
@@ -355,13 +336,14 @@ def generate_system_page(
|
|||||||
|
|
||||||
def generate_emulators_index(profiles: dict) -> str:
|
def generate_emulators_index(profiles: dict) -> str:
|
||||||
lines = [
|
lines = [
|
||||||
"# Emulators",
|
f"# Emulators - {SITE_NAME}",
|
||||||
"",
|
"",
|
||||||
"| Engine | Type | Systems | Files |",
|
"| Engine | Type | Systems | Files |",
|
||||||
"|--------|------|---------|-------|",
|
"|--------|------|---------|-------|",
|
||||||
]
|
]
|
||||||
|
|
||||||
unique = {k: v for k, v in profiles.items() if v.get("type") != "alias"}
|
unique = {k: v for k, v in profiles.items() if v.get("type") not in ("alias", "test")}
|
||||||
|
test_cores = {k: v for k, v in profiles.items() if v.get("type") == "test"}
|
||||||
aliases = {k: v for k, v in profiles.items() if v.get("type") == "alias"}
|
aliases = {k: v for k, v in profiles.items() if v.get("type") == "alias"}
|
||||||
|
|
||||||
for name in sorted(unique.keys()):
|
for name in sorted(unique.keys()):
|
||||||
@@ -494,6 +476,11 @@ def generate_gap_analysis(
|
|||||||
total_in_repo = 0
|
total_in_repo = 0
|
||||||
total_missing = 0
|
total_missing = 0
|
||||||
|
|
||||||
|
# Build global set of all platform-declared filenames (once)
|
||||||
|
all_platform_names = set()
|
||||||
|
for pfiles in platform_files.values():
|
||||||
|
all_platform_names.update(pfiles)
|
||||||
|
|
||||||
emulator_gaps = []
|
emulator_gaps = []
|
||||||
for emu_name, profile in sorted(profiles.items()):
|
for emu_name, profile in sorted(profiles.items()):
|
||||||
if profile.get("type") == "alias":
|
if profile.get("type") == "alias":
|
||||||
@@ -502,11 +489,6 @@ def generate_gap_analysis(
|
|||||||
if not files:
|
if not files:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Collect all files declared by any platform (global check)
|
|
||||||
all_platform_names = set()
|
|
||||||
for pfiles in platform_files.values():
|
|
||||||
all_platform_names.update(pfiles)
|
|
||||||
|
|
||||||
undeclared = []
|
undeclared = []
|
||||||
for f in files:
|
for f in files:
|
||||||
fname = f.get("name", "")
|
fname = f.get("name", "")
|
||||||
@@ -676,7 +658,7 @@ def generate_mkdocs_nav(
|
|||||||
slug = mfr.lower().replace(" ", "-")
|
slug = mfr.lower().replace(" ", "-")
|
||||||
system_nav.append({mfr: f"systems/{slug}.md"})
|
system_nav.append({mfr: f"systems/{slug}.md"})
|
||||||
|
|
||||||
unique_profiles = {k: v for k, v in profiles.items() if v.get("type") != "alias"}
|
unique_profiles = {k: v for k, v in profiles.items() if v.get("type") not in ("alias", "test")}
|
||||||
emu_nav = [{"Overview": "emulators/index.md"}]
|
emu_nav = [{"Overview": "emulators/index.md"}]
|
||||||
for name in sorted(unique_profiles.keys()):
|
for name in sorted(unique_profiles.keys()):
|
||||||
display = unique_profiles[name].get("emulator", name)
|
display = unique_profiles[name].get("emulator", name)
|
||||||
@@ -734,7 +716,7 @@ def main():
|
|||||||
coverages = {}
|
coverages = {}
|
||||||
for name in sorted(platform_names):
|
for name in sorted(platform_names):
|
||||||
try:
|
try:
|
||||||
cov = _compute_coverage(name, args.platforms_dir, db)
|
cov = compute_coverage(name, args.platforms_dir, db)
|
||||||
coverages[name] = cov
|
coverages[name] = cov
|
||||||
print(f" {cov['platform']}: {cov['present']}/{cov['total']} ({_pct(cov['present'], cov['total'])})")
|
print(f" {cov['platform']}: {cov['present']}/{cov['total']} ({_pct(cov['present'], cov['total'])})")
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
@@ -793,9 +775,10 @@ def main():
|
|||||||
|
|
||||||
with open("mkdocs.yml") as f:
|
with open("mkdocs.yml") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
# Replace or append nav section
|
# Replace nav section (everything from \nnav: to the next top-level key or EOF)
|
||||||
|
import re
|
||||||
if "\nnav:" in content:
|
if "\nnav:" in content:
|
||||||
content = content[:content.index("\nnav:") + 1] + nav_yaml
|
content = re.sub(r'\nnav:.*', '\n' + nav_yaml.rstrip(), content, count=1, flags=re.DOTALL)
|
||||||
else:
|
else:
|
||||||
content += "\n" + nav_yaml
|
content += "\n" + nav_yaml
|
||||||
with open("mkdocs.yml", "w") as f:
|
with open("mkdocs.yml", "w") as f:
|
||||||
|
|||||||
Reference in New Issue
Block a user