mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-26 21:57:24 -05:00
docs: point users to --check and exact pack files
Troubleshooting, the FAQ and the download page sent people who only ran the installer to verify.py, which reads the repository, not their BIOS folder. Download links now name the exact asset of the recorded release, the --dest example names the BIOS folder on the card, the slice layout left with the last release that used it, and the shown verify output is what the tool prints.
This commit is contained in:
1 parent
621f4fcdee
commit
6ee138a819
12 files changed
+486
-170
No files matched your search
+40
-18
@@ -124,6 +124,34 @@ def release_totals(platform_name: str, record: dict) -> tuple[int | None, int |
|
||||
return pack["files"], pack["extracted_size"]
|
||||
|
||||
|
||||
def download_links(
|
||||
platform_name: str, record: dict, repo: str, label: str, attrs: str = ""
|
||||
) -> str:
|
||||
"""Markdown links to the files of a platform's pack in the recorded release.
|
||||
|
||||
A pack published whole gets one link labelled *label*. A pack in parts
|
||||
gets one link per part, since every part is needed. *repo* is the
|
||||
repository URL, absolute or relative, and *attrs* a MkDocs attribute list
|
||||
put after each link. Without a pack in the record the link falls back to
|
||||
the latest release page.
|
||||
"""
|
||||
pack = release_record.pack_for(platform_name, record)
|
||||
tag = record.get("tag")
|
||||
assets = pack.get("assets") if pack else None
|
||||
if not tag or not assets:
|
||||
return f"[{label}]({repo}/releases/latest){attrs}"
|
||||
urls = [f"{repo}/releases/download/{tag}/{asset}" for asset in assets]
|
||||
if len(urls) == 1:
|
||||
return f"[{label}]({urls[0]}){attrs}"
|
||||
parts = [
|
||||
f"[{'P' if attrs else 'p'}art {number} of {len(urls)}]({url}){attrs}"
|
||||
for number, url in enumerate(urls, 1)
|
||||
]
|
||||
if attrs:
|
||||
return " ".join(parts)
|
||||
return f"{label}: " + ", ".join(parts)
|
||||
|
||||
|
||||
def extract_targets(platforms_dir: str) -> list[tuple[str, str]]:
|
||||
"""(display name, folder) per registered platform, where its pack extracts.
|
||||
|
||||
@@ -182,7 +210,7 @@ def download_table(
|
||||
f"| {display} | {f'{files:,}' if files else '-'} |"
|
||||
f" {format_size(size) if size else '-'} |"
|
||||
f" {extract_paths.get(cov['platform'], '')} |"
|
||||
f" [Download]({RELEASE_URL}) |"
|
||||
f" {download_links(name, record, REPO_PATH, 'Download')} |"
|
||||
)
|
||||
return lines
|
||||
|
||||
@@ -219,7 +247,7 @@ def format_size(size: int) -> str:
|
||||
|
||||
|
||||
SITE_URL = "https://abdess.github.io/retrobios/"
|
||||
RELEASE_URL = "../../releases/latest"
|
||||
REPO_PATH = "../.."
|
||||
REPO = "Abdess/retrobios"
|
||||
|
||||
|
||||
@@ -365,8 +393,9 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
|
||||
"# Android (Termux, after pkg install python and termux-setup-storage)",
|
||||
"curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh",
|
||||
"",
|
||||
"# Handheld (SD card mounted on PC)",
|
||||
"curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --platform retroarch --dest /path/to/sdcard",
|
||||
"# SD card mounted on a PC: --dest is the BIOS folder on the card",
|
||||
"# (RetroArch on Switch: retroarch/cores/system, on Android: RetroArch/system)",
|
||||
"curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --platform retroarch --dest /path/to/sdcard/retroarch/cores/system",
|
||||
"```",
|
||||
"",
|
||||
"The script auto-detects your platform, downloads only missing files, and verifies checksums.",
|
||||
@@ -381,16 +410,9 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
|
||||
" The size is what the files occupy once extracted, and the ZIP itself"
|
||||
" downloads smaller.",
|
||||
"",
|
||||
"A pack over 2 GB comes in several parts, and every part is needed."
|
||||
" How to open them depends on their name:",
|
||||
"",
|
||||
"- `Pack.part1of2.zip`, `Pack.part2of2.zip`: each part is an ordinary"
|
||||
" ZIP. Extract them all into the same folder.",
|
||||
"- `Pack.zip.001`, `Pack.zip.002` (releases up to v2026.09.04): slices"
|
||||
" of one ZIP, none of which opens on its own. Put them in one folder"
|
||||
" and open the `.001` with 7-Zip or PeaZip, or join them first with"
|
||||
" `cat Pack.zip.0* > Pack.zip` on Linux and macOS,"
|
||||
" `cmd /c copy /b Pack.zip.001+Pack.zip.002 Pack.zip` on Windows.",
|
||||
"A pack over 2 GB comes in several parts (`Pack.part1of2.zip`,"
|
||||
" `Pack.part2of2.zip`), and every part is needed. Each part is an"
|
||||
" ordinary ZIP: extract them all into the same folder.",
|
||||
"",
|
||||
"Every release ships `SHA256SUMS.txt` and a detached signature of it,"
|
||||
" checkable against `allowed_signers` in this repository:"
|
||||
@@ -575,7 +597,8 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
|
||||
"python scripts/generate_pack.py --list-emulators",
|
||||
"python scripts/generate_pack.py --list-systems",
|
||||
"",
|
||||
"# Verify your BIOS collection",
|
||||
"# Coverage of this repository's collection per platform, emulator or system",
|
||||
"# (it reads database.json and bios/: for your own BIOS folder, run the installer with --check)",
|
||||
"python scripts/verify.py --all",
|
||||
"python scripts/verify.py --platform batocera",
|
||||
"python scripts/verify.py --emulator flycast",
|
||||
@@ -734,13 +757,12 @@ pip install pyyaml "jsonschema[format-nongpl]" markdown
|
||||
python scripts/validate_pr.py --changed # the BIOS files the branch adds
|
||||
python scripts/validate_schemas.py --source-only # profiles and platform files
|
||||
python scripts/profile_sync.py --emulator NAME --strict # each profile the branch adds
|
||||
python scripts/refresh_data_dirs.py # data directories the pack-building tests read
|
||||
python -m unittest discover -s tests -t .
|
||||
```
|
||||
|
||||
The full pipeline is not needed for a contribution: it rebuilds every pack
|
||||
(about 35 GB in `dist/`) and needs the data directories fetched first
|
||||
(`python scripts/refresh_data_dirs.py`), which is why maintainers run it
|
||||
before a release.
|
||||
in `dist/`, which is why maintainers run it before a release.
|
||||
|
||||
## PR validation
|
||||
|
||||
|
||||
+49
-17
@@ -37,6 +37,7 @@ from common import (
|
||||
list_registered_platforms,
|
||||
load_database,
|
||||
load_emulator_profiles,
|
||||
load_platform_config,
|
||||
load_provenance_snapshots,
|
||||
native_layer,
|
||||
require_yaml,
|
||||
@@ -59,6 +60,7 @@ yaml = require_yaml()
|
||||
from generate_readme import (
|
||||
compute_coverage,
|
||||
contributing_text,
|
||||
download_links,
|
||||
extract_notes,
|
||||
extract_targets,
|
||||
release_totals,
|
||||
@@ -335,7 +337,7 @@ def generate_home(
|
||||
lines.append(
|
||||
f"| {logo_md} | [{display}](platforms/{name}.md) | "
|
||||
f"{_released_files(name)} | {mode_label} | "
|
||||
f"[Pack]({RELEASE_URL}){{ .md-button .md-button--primary }} |"
|
||||
f"{_pack_buttons(name)} |"
|
||||
)
|
||||
|
||||
lines.extend(
|
||||
@@ -448,6 +450,17 @@ def compute_stats(db: dict, coverages: dict, profiles: dict) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def _pack_buttons(platform_name: str, label: str = "Pack") -> str:
|
||||
"""Buttons to the files of the platform's pack in the recorded release."""
|
||||
return download_links(
|
||||
platform_name,
|
||||
release_record.load_record(),
|
||||
REPO_URL,
|
||||
label,
|
||||
"{ .md-button .md-button--primary }",
|
||||
)
|
||||
|
||||
|
||||
def _released_files(platform_name: str) -> str:
|
||||
"""File count of the pack the latest release serves, as a table cell."""
|
||||
files, _size = release_totals(platform_name, release_record.load_record())
|
||||
@@ -1673,7 +1686,7 @@ def generate_platform_index(coverages: dict, registry: dict | None = None) -> st
|
||||
f"| [{display}]({name}.md) | "
|
||||
f"{cov['present']:,} | {_released_files(name)} | "
|
||||
f"{mode_html} | {status_html} | "
|
||||
f"[Pack]({RELEASE_URL}){{ .md-button .md-button--primary }} |"
|
||||
f"{_pack_buttons(name)} |"
|
||||
)
|
||||
|
||||
lines.extend(
|
||||
@@ -1914,8 +1927,7 @@ def generate_platform_page(
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
f"[Download {display} Pack]({RELEASE_URL})"
|
||||
"{ .md-button .md-button--primary }",
|
||||
_pack_buttons(name, f"Download {display} Pack"),
|
||||
"",
|
||||
]
|
||||
)
|
||||
@@ -4439,7 +4451,7 @@ def _mkdocs_config(docs: Path, text: str) -> tuple[Path, str]:
|
||||
def generate_which_pack() -> str:
|
||||
"""Generate the 'Which pack?' decision page."""
|
||||
rel = RELEASE_URL
|
||||
return f"""\
|
||||
return _link_pack_cells(f"""\
|
||||
# Download
|
||||
|
||||
Some retro consoles need firmware files (commonly called BIOS) to run games.
|
||||
@@ -4473,7 +4485,12 @@ irm https://raw.githubusercontent.com/Abdess/retrobios/main/install.ps1 | iex
|
||||
That is the complete default flow. Extra copies into detected standalone
|
||||
emulator directories are deliberately opt-in with `--standalone-copies`, so
|
||||
automatic setup never writes outside the selected platform tree unexpectedly.
|
||||
Use `python install.py --check` from a checkout for a read-only verification.
|
||||
Adding `--check` reads the BIOS folder, hashes what is there and writes
|
||||
nothing:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --check
|
||||
```
|
||||
|
||||
Options, environment overrides, how each platform is detected and what the
|
||||
installer is allowed to write: [Installer](wiki/installer.md).
|
||||
@@ -4487,16 +4504,9 @@ download it, and extract the files into the BIOS folder listed below.
|
||||
The metadata and website can be newer than that release: pack publication is
|
||||
manual and only happens after the release gates pass.
|
||||
|
||||
A pack over 2 GB comes in several parts, and every part is needed. How to
|
||||
open them depends on their name:
|
||||
|
||||
- `PackName.part1of2.zip`, `PackName.part2of2.zip`: each part is an ordinary
|
||||
ZIP. Extract them all into the same folder.
|
||||
- `PackName.zip.001`, `PackName.zip.002` (releases up to v2026.09.04): slices
|
||||
of one ZIP, none of which opens on its own. Put them in one folder and open
|
||||
the `.001` with 7-Zip or PeaZip, or join them first:
|
||||
- Linux/macOS: `cat PackName.zip.0* > PackName.zip`
|
||||
- Windows: `cmd /c copy /b PackName.zip.001+PackName.zip.002 PackName.zip`
|
||||
A pack over 2 GB comes in several parts (`PackName.part1of2.zip`,
|
||||
`PackName.part2of2.zip`), and every part is needed. Each part is an ordinary
|
||||
ZIP: extract them all into the same folder.
|
||||
|
||||
### Steam Deck
|
||||
|
||||
@@ -4591,7 +4601,29 @@ but standalone emulators may still need their BIOS path configured.
|
||||
If a game still asks for a missing file, check the
|
||||
[platforms section](platforms/index.md) for the full file list, or the
|
||||
[emulators section](emulators/index.md) for what each core expects.
|
||||
"""
|
||||
""")
|
||||
|
||||
|
||||
def _link_pack_cells(page: str) -> str:
|
||||
"""Point each table cell naming a platform's pack at that pack's files.
|
||||
|
||||
The cell names the platform by its display name, resolved through the
|
||||
registry, and the links come from the release record.
|
||||
"""
|
||||
record = release_record.load_record()
|
||||
keys = {
|
||||
load_platform_config(key, "platforms").get("platform", key): key
|
||||
for key in list_registered_platforms("platforms", include_archived=True)
|
||||
}
|
||||
cell = re.compile(rf"\| \[([^\]]+)\]\({re.escape(RELEASE_URL)}\) \|")
|
||||
|
||||
def link(match: re.Match[str]) -> str:
|
||||
label = match.group(1)
|
||||
if label not in keys:
|
||||
raise KeyError(f"no registered platform is displayed as {label!r}")
|
||||
return f"| {download_links(keys[label], record, REPO_URL, label)} |"
|
||||
|
||||
return cell.sub(link, page)
|
||||
|
||||
|
||||
def generate_mkdocs_nav(
|
||||
|
||||
Reference in new issue
Block a user