mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-11 12:33:53 -06:00
feat: install the fewest files for a card's games
--for-games --required-only on a dArkOS card from a computer kept every file of the list: --dest skipped the card's detection, so its rom folders were never found. The games part beside the BIOS folder now names them. The manifest marks a data tree every core runs without (optional), and --required-only leaves it out: one GBA and one SNES game took FBNeo's cheats and samples, 3,472 files no game opened.
This commit is contained in:
1 parent
adce8dd0d4
commit
072380c268
24 files changed
+184
-78
No files matched your search
@@ -51,10 +51,12 @@ data_directories:
|
||||
- ref: fbneo-cheats
|
||||
unread_on: [romm]
|
||||
destination: fbneo/cheats
|
||||
required: false
|
||||
source_ref: "source src/burner/conc.cpp:167"
|
||||
- ref: fbneo-samples
|
||||
unread_on: [romm]
|
||||
destination: fbneo
|
||||
required: false
|
||||
source_ref: "source src/burn/snd/samples.cpp:21-35"
|
||||
|
||||
notes: |
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
# and Invoke-WebRequest throws on a cut transfer before the hash is read:
|
||||
# the site's build rewrites this line there (scripts/sitebootstrap.py).
|
||||
$mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
|
||||
$defaultInstallSha256 = "57e3cb6739a701181908773e603f17d2b10e1b0e2a5cde5cc4d5c97426da5dd4"
|
||||
$defaultInstallSha256 = "3a78bf2e5a910d0f5c21bc2dc490aa600fc3273c56ae01e9ce5061d9b3578f07"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+25
-8
@@ -3724,6 +3724,8 @@ def _check_data_directory(entry: object, where: str) -> None:
|
||||
values = entry.get(field, [])
|
||||
if not isinstance(values, list) or not all(isinstance(v, str) for v in values):
|
||||
raise ValueError(f"{where}.{field} is invalid")
|
||||
if entry.get("optional", True) is not True:
|
||||
raise ValueError(f"{where}.optional is invalid")
|
||||
files = entry.get("files")
|
||||
if not isinstance(files, dict) or not files or len(files) > MAX_MANIFEST_FILES:
|
||||
raise ValueError(f"{where}.files is invalid")
|
||||
@@ -7393,11 +7395,16 @@ def _install_data_member(
|
||||
scratch.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def select_data_directories(manifest: dict, files: list[dict], narrowed: bool) -> list[dict]:
|
||||
"""The data trees this install keeps: all, or those of a kept system."""
|
||||
entries = manifest.get("data_directories") or []
|
||||
def select_data_directories(manifest: dict, files: list[dict], narrowed: bool,
|
||||
required_only: bool = False) -> list[dict]:
|
||||
"""The data trees this install keeps: all, or those of a kept system.
|
||||
--required-only leaves out a tree every core reading it runs without
|
||||
(`optional`): a GBA and a SNES game took FBNeo's cheats and samples,
|
||||
3,472 files no game opened."""
|
||||
entries = [e for e in manifest.get("data_directories") or []
|
||||
if not (required_only and e.get("optional"))]
|
||||
if not narrowed:
|
||||
return list(entries)
|
||||
return entries
|
||||
kept = {system for f in files for system in entry_systems(f)}
|
||||
return [e for e in entries if kept & set(e.get("systems") or [])]
|
||||
|
||||
@@ -8824,7 +8831,8 @@ def _prompt_custom_selection(
|
||||
if bios_path is not None and not dry_run and current != INSTALLED_ONLY:
|
||||
kept = menu_choice(files, omitted, installed, current, False)[0]
|
||||
kept_trees = select_data_directories({"data_directories": trees}, kept,
|
||||
narrowed or current is not None)
|
||||
narrowed or current is not None,
|
||||
isinstance(current, GamesChoice) and current.required)
|
||||
if kept and all_in_place(kept, kept_trees, bios_path):
|
||||
# Read before the menu, as the screen reads before it asks: a
|
||||
# rerun was offered an install that installs nothing, then told
|
||||
@@ -8953,7 +8961,8 @@ def _print_menu_head(
|
||||
# The trees of the systems kept: 2636 data files of blueMSX, Dolphin
|
||||
# and PPSSPP were counted for every --system tried.
|
||||
kept_trees = select_data_directories({"data_directories": trees}, shown,
|
||||
narrowed or current is not None)
|
||||
narrowed or current is not None,
|
||||
isinstance(current, GamesChoice) and current.required)
|
||||
data = sum(len(entry.get("files") or {}) for entry in kept_trees)
|
||||
data_size = sum(meta.get("size", 0) for entry in kept_trees
|
||||
for meta in (entry.get("files") or {}).values())
|
||||
@@ -9764,6 +9773,12 @@ def games_setups(index: dict, plat: str, bios_path: Path, os_type: str = "") ->
|
||||
if not named:
|
||||
above = card_root_above(bios_path)
|
||||
named = above[0] if above else ""
|
||||
if not named:
|
||||
# --dest on a handheld's games part from a computer (ArkOS's
|
||||
# EASYROMS/bios): detection never ran there, and the card's own rom
|
||||
# folders sit beside the BIOS folder.
|
||||
part = games_part(bios_path.parent)
|
||||
named = part.name if part else ""
|
||||
key = _setup_key(named) if named else ""
|
||||
found = [name for name in sorted(setups) if key and (name == key or name.startswith(key + "-"))]
|
||||
if not found and plat in setups:
|
||||
@@ -15671,7 +15686,8 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
!= len(manifest.get("files", [])) + len(variants if case_kept else [])
|
||||
or games_applied
|
||||
)
|
||||
data_dirs = select_data_directories(manifest, files, narrowed)
|
||||
data_dirs = select_data_directories(manifest, files, narrowed,
|
||||
bool(args.required_only))
|
||||
# The kinds as the plan and the menu head say them (parts_words),
|
||||
# the data files of the folders kept among them: this head said
|
||||
# BIOS files and game data beside a plan of three kinds, neither
|
||||
@@ -21812,7 +21828,8 @@ def _plan_data(state: TuiState, check: dict) -> tuple[int, int | None]:
|
||||
if not _tui_estimating(state):
|
||||
data = check.get("data_missing", 0)
|
||||
return data, check.get("data_bytes") if data else None
|
||||
trees = select_data_directories(state.manifest or {}, _choice_entries(state), True)
|
||||
required = any(flag == "--required-only" for flag, _value in tui_flags(state))
|
||||
trees = select_data_directories(state.manifest or {}, _choice_entries(state), True, required)
|
||||
sizes = [meta.get("size", 0) for entry in trees for meta in (entry.get("files") or {}).values()]
|
||||
return len(sizes), sum(sizes)
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins
|
||||
# curl or wget stop on a cut transfer before the hash is read: the site's
|
||||
# build rewrites this line there (scripts/sitebootstrap.py).
|
||||
MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
|
||||
DEFAULT_INSTALL_SHA256="57e3cb6739a701181908773e603f17d2b10e1b0e2a5cde5cc4d5c97426da5dd4"
|
||||
DEFAULT_INSTALL_SHA256="3a78bf2e5a910d0f5c21bc2dc490aa600fc3273c56ae01e9ce5061d9b3578f07"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "amberelec",
|
||||
"display_name": "AmberELEC",
|
||||
"version": "prerelease-20261019_1835",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
@@ -77381,7 +77381,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -77615,7 +77616,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -77988,7 +77990,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "batocera",
|
||||
"display_name": "Batocera",
|
||||
"version": "43.1",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
{
|
||||
@@ -225291,7 +225291,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -225525,7 +225526,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"save_directory": {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "emudeck",
|
||||
"display_name": "EmuDeck",
|
||||
"version": "2.7EA",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
{
|
||||
@@ -123400,7 +123400,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -123634,7 +123635,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -124007,7 +124009,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "lrps2",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "emuelec",
|
||||
"display_name": "EmuELEC",
|
||||
"version": "4.8",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
@@ -83639,7 +83639,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -83873,7 +83874,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -84246,7 +84248,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+5
-3
@@ -6,7 +6,7 @@
|
||||
"platform": "knulli",
|
||||
"display_name": "KNULLI",
|
||||
"version": "20260511",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
{
|
||||
@@ -157933,7 +157933,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -158167,7 +158168,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "lrps2",
|
||||
|
||||
+7
-4
@@ -6,7 +6,7 @@
|
||||
"platform": "lakka",
|
||||
"display_name": "Lakka",
|
||||
"version": "v6.1",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "system",
|
||||
"detect": [
|
||||
{
|
||||
@@ -130677,7 +130677,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -130911,7 +130912,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -131284,7 +131286,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "yaps2-resources",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "myminui",
|
||||
"display_name": "MyMinUI",
|
||||
"version": "2026-08-09",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
@@ -18958,7 +18958,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-cheats",
|
||||
@@ -32688,7 +32689,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -32922,7 +32924,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -33156,7 +33159,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+5
-3
@@ -6,7 +6,7 @@
|
||||
"platform": "nextui",
|
||||
"display_name": "NextUI",
|
||||
"version": "2026-10-20",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
@@ -19366,7 +19366,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -19600,7 +19601,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "recalbox",
|
||||
"display_name": "Recalbox",
|
||||
"version": "10.1.1",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
{
|
||||
@@ -62834,7 +62834,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -63068,7 +63069,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"save_directory": {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "retroarch",
|
||||
"display_name": "RetroArch",
|
||||
"version": "v1.22.2",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "system",
|
||||
"detect": [
|
||||
{
|
||||
@@ -140789,7 +140789,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -141023,7 +141024,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -141396,7 +141398,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "ppsspp-assets",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "retrobat",
|
||||
"display_name": "RetroBat",
|
||||
"version": "8.3.1",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
{
|
||||
@@ -89076,7 +89076,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -89310,7 +89311,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -89683,7 +89685,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"save_directory": {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "retrodeck",
|
||||
"display_name": "RetroDECK",
|
||||
"version": "0.10.10b",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "",
|
||||
"detect": [
|
||||
{
|
||||
@@ -153141,7 +153141,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -153375,7 +153376,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -153748,7 +153750,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "yaps2-resources",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "retropie",
|
||||
"display_name": "RetroPie",
|
||||
"version": "4.8.12",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "BIOS",
|
||||
"detect": [
|
||||
{
|
||||
@@ -146474,7 +146474,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -146708,7 +146709,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -147081,7 +147083,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "yaps2-resources",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"platform": "rocknix",
|
||||
"display_name": "ROCKNIX",
|
||||
"version": "20261001",
|
||||
"generated": "2026-11-05T23:59:37Z",
|
||||
"generated": "2026-11-06T07:21:27Z",
|
||||
"base_destination": "bios",
|
||||
"detect": [
|
||||
{
|
||||
@@ -109453,7 +109453,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 5083767
|
||||
"archive_size": 5083767,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "fbneo-samples",
|
||||
@@ -109687,7 +109688,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 0,
|
||||
"archive_size": 53006540
|
||||
"archive_size": 53006540,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "freeintv-overlays",
|
||||
@@ -110060,7 +110062,8 @@
|
||||
}
|
||||
},
|
||||
"strip_components": 1,
|
||||
"archive_size": 21311170
|
||||
"archive_size": 21311170,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"ref": "lrps2",
|
||||
|
||||
@@ -452,6 +452,11 @@
|
||||
},
|
||||
"description": "Platform systems whose cores read the tree."
|
||||
},
|
||||
"optional": {
|
||||
"type": "boolean",
|
||||
"const": true,
|
||||
"description": "Every core reading the tree runs without it (required: false in its profile): --required-only leaves it out."
|
||||
},
|
||||
"files": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
|
||||
@@ -518,7 +518,8 @@ def _data_directory_members(
|
||||
gets it from the tree's archive.
|
||||
|
||||
``refs_out``, when given, maps each yielded destination to
|
||||
(registry key, system ids, directory destination), for the manifest.
|
||||
(registry key, system ids, directory destination, whether the core
|
||||
needs the tree), for the manifest.
|
||||
|
||||
These are not BIOS and carry no hash of their own: they are whole
|
||||
trees an emulator reads, refreshed from upstream, so what ships is
|
||||
@@ -532,7 +533,8 @@ def _data_directory_members(
|
||||
ref_key = dd.get("ref", "")
|
||||
if not ref_key or not data_registry or ref_key not in data_registry:
|
||||
continue
|
||||
if required_only and dd.get("required") is False:
|
||||
needed = dd.get("required") is not False
|
||||
if required_only and not needed:
|
||||
continue
|
||||
if ref_key in installed_data_refs(platform_name):
|
||||
continue
|
||||
@@ -567,7 +569,7 @@ def _data_directory_members(
|
||||
):
|
||||
del reclaim[full]
|
||||
if refs_out is not None:
|
||||
refs_out[full] = (ref_key, systems, dd_prefix)
|
||||
refs_out[full] = (ref_key, systems, dd_prefix, needed)
|
||||
yield src, full
|
||||
continue
|
||||
if full in seen_destinations or (
|
||||
@@ -581,7 +583,7 @@ def _data_directory_members(
|
||||
if case_insensitive:
|
||||
seen_lower.add(full.lower())
|
||||
if refs_out is not None:
|
||||
refs_out[full] = (ref_key, systems, dd_prefix)
|
||||
refs_out[full] = (ref_key, systems, dd_prefix, needed)
|
||||
yield src, full
|
||||
|
||||
|
||||
@@ -4910,7 +4912,7 @@ def generate_manifest(
|
||||
# Phase 3: data directories. They are not files of the collection: the
|
||||
# installer fetches each from its source archive and keeps the members
|
||||
# whose hash the list below records, the same tree the pack carries.
|
||||
data_refs: dict[str, tuple[str, tuple[str, ...], str]] = {}
|
||||
data_refs: dict[str, tuple[str, tuple[str, ...], str, bool]] = {}
|
||||
reclaim = {full: path for full, (path, _size) in cache_held.items()}
|
||||
data_members = list(_data_directory_members(
|
||||
pack_systems, data_registry, platform_name, base_dest,
|
||||
@@ -5021,7 +5023,7 @@ def generate_manifest(
|
||||
|
||||
def _manifest_data_directories(
|
||||
members: list[tuple[str, str]],
|
||||
refs: dict[str, tuple[str, tuple[str, ...], str]],
|
||||
refs: dict[str, tuple[str, tuple[str, ...], str, bool]],
|
||||
registry: dict,
|
||||
base_dest: str,
|
||||
) -> list[dict]:
|
||||
@@ -5034,11 +5036,14 @@ def _manifest_data_directories(
|
||||
changed since is refused rather than installed. archive_size is the
|
||||
size of the archive refresh_data_dirs last downloaded, what fetching
|
||||
the tree costs: a tarball whose tree is 10 KB is a download of 21 MB.
|
||||
``optional`` marks a tree every core reading it runs without
|
||||
(``required: false``): install.py --required-only leaves it out, as the
|
||||
pack built with --required-only does.
|
||||
"""
|
||||
grouped: dict[tuple[str, str], dict] = {}
|
||||
versions: dict[str, dict[str, dict]] = {}
|
||||
for src, full in members:
|
||||
ref, systems, prefix = refs[full]
|
||||
ref, systems, prefix, needed = refs[full]
|
||||
entry = registry.get(ref, {})
|
||||
key = (ref, prefix)
|
||||
group = grouped.get(key)
|
||||
@@ -5072,11 +5077,19 @@ def _manifest_data_directories(
|
||||
size = versions[str(recorded)].get(ref, {}).get("archive_size")
|
||||
if isinstance(size, int) and size > 0:
|
||||
group["archive_size"] = size
|
||||
if needed:
|
||||
group["needed"] = True
|
||||
group["systems"].extend(s for s in systems if s not in group["systems"])
|
||||
rel = full[len(prefix):].lstrip("/") if prefix else full
|
||||
hashes = compute_hashes(src, frozenset({"sha1"}))
|
||||
group["files"][rel] = {"sha1": hashes["sha1"], "size": os.path.getsize(src)}
|
||||
return [grouped[key] for key in sorted(grouped)]
|
||||
trees = []
|
||||
for key in sorted(grouped):
|
||||
group = grouped[key]
|
||||
if not group.pop("needed", False):
|
||||
group["optional"] = True
|
||||
trees.append(group)
|
||||
return trees
|
||||
|
||||
|
||||
def _manifest_core_index(
|
||||
|
||||
@@ -6923,9 +6923,11 @@ class RequiredOnlyReachesDataDirectories(unittest.TestCase):
|
||||
|
||||
def test_every_tree_walk_reads_the_flag(self):
|
||||
source = (ROOT / "scripts" / "generate_pack.py").read_text(encoding="utf-8")
|
||||
self.assertEqual(
|
||||
source.count('if required_only and dd.get("required") is False:'), 2
|
||||
)
|
||||
# The pack's walk and the manifest's, which records the flag for
|
||||
# install.py --required-only.
|
||||
self.assertEqual(source.count('if required_only and dd.get("required") is False:'), 1)
|
||||
self.assertIn('needed = dd.get("required") is not False\n if required_only and not needed:',
|
||||
source)
|
||||
self.assertIn("seen_parents, required_only=required_only,", source)
|
||||
self.assertIn("data_refs, required_only=required_only,", source)
|
||||
|
||||
|
||||
@@ -3880,6 +3880,20 @@ class DataDirectoriesAreInstalled(unittest.TestCase):
|
||||
},
|
||||
}
|
||||
|
||||
def test_required_only_leaves_out_an_optional_tree(self):
|
||||
"""A GBA and a SNES game with --for-games --required-only took
|
||||
FBNeo's cheats and samples, 3,472 files no game opened."""
|
||||
cheats = {**self._entry(), "ref": "fbneo-cheats", "systems": ["snes"], "optional": True}
|
||||
sys_tree = {**self._entry(), "systems": ["snes"]}
|
||||
manifest = {"data_directories": [cheats, sys_tree]}
|
||||
files = [{"dest": "a.rom", "systems": ["snes"]}]
|
||||
self.assertEqual(install.select_data_directories(manifest, files, True), [cheats, sys_tree])
|
||||
self.assertEqual(install.select_data_directories(manifest, files, True, True), [sys_tree])
|
||||
self.assertEqual(install.select_data_directories(manifest, files, False, True), [sys_tree])
|
||||
install._check_data_directory(cheats, "data_directories[0]")
|
||||
with self.assertRaises(ValueError):
|
||||
install._check_data_directory({**cheats, "optional": False}, "data_directories[0]")
|
||||
|
||||
def test_the_archive_is_drawn_and_counted(self):
|
||||
"""82 MB of archives came with no progress line, and the run ended
|
||||
on "310.5 KB downloaded", the BIOS files alone."""
|
||||
|
||||
@@ -12912,6 +12912,18 @@ class DriveIsACardByItsFiles(unittest.TestCase):
|
||||
self.assertEqual([install.card_system(mount) for mount in mounts],
|
||||
[None, None, None])
|
||||
|
||||
def test_a_dest_on_a_games_part_reads_its_rom_folders(self):
|
||||
"""--dest EASYROMS/bios --for-games from a computer: detection never
|
||||
ran on the card, the generic RetroArch folders were tried, and the
|
||||
run kept every file of the list."""
|
||||
arkos = games_part(self.root / "media" / "EASYROMS")
|
||||
index = {"setups": {"arkos": {}, "retroarch": {}}}
|
||||
with mock.patch.object(install, "_mount_points", return_value=frozenset()), \
|
||||
mock.patch.object(install, "_drive_not_removable", return_value=False):
|
||||
self.assertEqual(install.games_setups(index, "retroarch", arkos / "bios"), ["arkos"])
|
||||
self.assertEqual(install.games_setups(index, "retroarch", self.root / "bios"),
|
||||
["retroarch"])
|
||||
|
||||
def test_a_card_beside_a_data_drive_comes_first(self):
|
||||
"""The ArkOS card and the data drive mounted,
|
||||
the data drive sorted first and took Enter. The card comes first in
|
||||
|
||||
+6
-4
@@ -405,7 +405,7 @@ lists record these files as omitted.
|
||||
|
||||
<!-- generated: dry-run -->
|
||||
|
||||
A RetroArch dry run into an empty folder, with the list of 2026-11-05, printed this:
|
||||
A RetroArch dry run into an empty folder, with the list of 2026-11-06, printed this:
|
||||
|
||||
```
|
||||
Fetching file index for retroarch...
|
||||
@@ -435,7 +435,7 @@ the installer can fetch them.
|
||||
<!-- generated: run-date -->
|
||||
|
||||
Each line a first install prints, and what it means. The run below is a
|
||||
Batocera install into an empty folder, from the list of 2026-11-05.
|
||||
Batocera install into an empty folder, from the list of 2026-11-06.
|
||||
The figures change with each release.
|
||||
<!-- /generated: run-date -->
|
||||
|
||||
@@ -531,7 +531,7 @@ would save, once that saving is over half.
|
||||
|
||||
<!-- generated: bulk-hint -->
|
||||
|
||||
RetroArch with `--system sony-playstation`, from the list of 2026-11-05:
|
||||
RetroArch with `--system sony-playstation`, from the list of 2026-11-06:
|
||||
|
||||
```
|
||||
duckstation pulls 316.5 MB of this 329.0 MB download for sony-playstation. --core pcsx1 keeps 11.0 MB of it and saves 318.0 MB (96%).
|
||||
@@ -876,7 +876,9 @@ BIOS sets of its parent chain (`neogeo.zip` for `mslug.zip`).
|
||||
|
||||
A game that is not recognised gets every BIOS of its system, and the run names
|
||||
it. So does an arcade set the core does not know. **Only what starts**
|
||||
(`--required-only`) leaves out the files the cores mark optional.
|
||||
(`--required-only`) leaves out the files the cores mark optional, and the data
|
||||
folders every core reading them runs without (FinalBurn Neo's cheats and
|
||||
samples).
|
||||
|
||||
The games are read without hashing whole discs, and a cache keeps what was
|
||||
read, so a second run over the same card reads only new files. It is a
|
||||
|
||||
Reference in new issue
Block a user