mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-12 04:53:52 -06:00
refactor: read the roms root from romfolders
platforms/romfolders/<platform>.yml records the roms root from the OS's own source (roms_root path and from_bios), the same fact the registry's roms_directory restated for ROCKNIX alone. The manifest's roms_directory now carries from_bios, which the installer follows from a BIOS folder of the platform's name, and the registry key is gone. A list that installs above its BIOS folder (AmberELEC) holds its roms root in the install tree: a file a launcher runs from there is a plain dest. emulators_directory stays in the registry: no rom folders file names emulator folders.
This commit is contained in:
1 parent
8633db0a22
commit
3db2819150
12 files changed
+180
-52
No files matched your search
+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 = "b9586fece4058b670a4fe83b8c2825b7882024eba816a36353b07a7496af7f1b"
|
||||
$defaultInstallSha256 = "67c84f81ad5a452a73ae6b6f36bbdf593a48728754dbb0f77296c381012f2fd2"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+14
-6
@@ -3687,10 +3687,17 @@ def _check_roms_directory(data: dict) -> None:
|
||||
return
|
||||
if (
|
||||
not isinstance(layout, dict)
|
||||
or set(layout) != {"bios_folder"}
|
||||
or set(layout) != {"bios_folder", "from_bios"}
|
||||
or len(_safe_relative_path(layout["bios_folder"], "roms_directory.bios_folder").parts) != 1
|
||||
or not isinstance(layout["from_bios"], str)
|
||||
):
|
||||
raise ValueError("invalid roms_directory")
|
||||
# The roms root relative to the BIOS folder: up some levels, then down
|
||||
# into named folders. Nothing climbs again once it went down.
|
||||
parts = PurePosixPath(layout["from_bios"]).parts
|
||||
ups = next((i for i, part in enumerate(parts) if part != ".."), len(parts))
|
||||
if not ups or any(part in ("..", ".", "/") or _CONTROLS.search(part) for part in parts[ups:]):
|
||||
raise ValueError("invalid roms_directory.from_bios")
|
||||
|
||||
|
||||
def _check_emulators_directory(data: dict) -> None:
|
||||
@@ -5294,17 +5301,18 @@ def place_roms_entries(
|
||||
) -> tuple[list[dict], list[dict]]:
|
||||
"""Find the roms folder for the entries a launcher reads below it.
|
||||
|
||||
The platform keeps its BIOS folder in its roms folder under the name the
|
||||
list gives (ROCKNIX's /storage/roms/bios): a BIOS folder of that name
|
||||
puts the roms folder above it. Any other is a folder this run cannot
|
||||
relate to the roms, and the entries are left out with the reason.
|
||||
The list gives the roms root relative to the BIOS folder, as the OS's
|
||||
own source places them (ROCKNIX's /storage/roms holds bios/): a BIOS
|
||||
folder of the platform's name puts the roms root there. Any other is a
|
||||
folder this run cannot relate to the roms, and the entries are left out
|
||||
with the reason.
|
||||
"""
|
||||
below = [entry for entry in files if entry.get("root") == "roms"]
|
||||
if not below:
|
||||
return files, []
|
||||
layout = manifest.get("roms_directory") or {}
|
||||
if layout and bios_path.name == layout.get("bios_folder"):
|
||||
_ROMS_DIRS[bios_path] = bios_path.parent
|
||||
_ROMS_DIRS[bios_path] = Path(os.path.normpath(bios_path / layout["from_bios"]))
|
||||
return files, []
|
||||
if say:
|
||||
print(f" {_plural(len(below), 'file')} read from {display}'s roms folder left out: "
|
||||
|
||||
+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="b9586fece4058b670a4fe83b8c2825b7882024eba816a36353b07a7496af7f1b"
|
||||
DEFAULT_INSTALL_SHA256="67c84f81ad5a452a73ae6b6f36bbdf593a48728754dbb0f77296c381012f2fd2"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
{
|
||||
"dest": "roms/ports/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1138424,
|
||||
"sha256": "b9586fece4058b670a4fe83b8c2825b7882024eba816a36353b07a7496af7f1b",
|
||||
"size": 1138987,
|
||||
"sha256": "67c84f81ad5a452a73ae6b6f36bbdf593a48728754dbb0f77296c381012f2fd2",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -71,8 +71,8 @@
|
||||
"muos": {
|
||||
"archive": {
|
||||
"dest": "ARCHIVE/RetroBIOS.muxapp",
|
||||
"size": 1192049,
|
||||
"sha256": "9da63b607a6ae2a734f4437c224b484229c514b08bbab6341b529ce102de464f"
|
||||
"size": 1192612,
|
||||
"sha256": "90e6c3ec8b3eae2d9f8f1b07874c083e4d555fb325590999ef4690fb67125426"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
@@ -92,8 +92,8 @@
|
||||
{
|
||||
"name": "RetroBIOS/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1138424,
|
||||
"sha256": "b9586fece4058b670a4fe83b8c2825b7882024eba816a36353b07a7496af7f1b",
|
||||
"size": 1138987,
|
||||
"sha256": "67c84f81ad5a452a73ae6b6f36bbdf593a48728754dbb0f77296c381012f2fd2",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -166,8 +166,8 @@
|
||||
{
|
||||
"dest": ".config/modules/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1138424,
|
||||
"sha256": "b9586fece4058b670a4fe83b8c2825b7882024eba816a36353b07a7496af7f1b",
|
||||
"size": 1138987,
|
||||
"sha256": "67c84f81ad5a452a73ae6b6f36bbdf593a48728754dbb0f77296c381012f2fd2",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -860,13 +860,6 @@ platforms:
|
||||
# sources/RK3566/retroarch.cfg:664-665 at 20261001) and setsettings.sh
|
||||
# leaves it: saves sit beside each game, no single place.
|
||||
save_directory: null
|
||||
# The BIOS folder sits in the roms directory (/storage/roms/bios, the
|
||||
# detect entry below), where start_pico8.sh also runs PICO-8 from
|
||||
# /storage/roms/pico-8. A launcher path below path is placed there, and
|
||||
# the installer finds that directory as the folder holding bios_folder.
|
||||
roms_directory:
|
||||
path: /storage/roms
|
||||
bios_folder: bios
|
||||
schedule: weekly
|
||||
target_scraper: rocknix_targets
|
||||
target_source: https://github.com/ROCKNIX/distribution/blob/next/projects/ROCKNIX/packages/virtual/emulators/package.mk
|
||||
|
||||
@@ -528,17 +528,22 @@
|
||||
}
|
||||
},
|
||||
"roms_directory": {
|
||||
"description": "Where the platform keeps its roms folder, present when an entry carries root: roms. bios_folder is the name of the BIOS folder inside it: a BIOS folder of that name has the roms folder as its parent, any other leaves root: roms entries out (no_roms_directory).",
|
||||
"description": "Where the platform keeps its roms root, present when an entry carries root: roms. from_bios is that root relative to the BIOS folder, as platforms/romfolders/<platform>.yml records it from the OS's own source (roms_root.from_bios). It is followed only from a BIOS folder named bios_folder (the platform's base_destination); any other leaves root: roms entries out (no_roms_directory).",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"bios_folder"
|
||||
"bios_folder",
|
||||
"from_bios"
|
||||
],
|
||||
"properties": {
|
||||
"bios_folder": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^[^/\\\\]+$"
|
||||
},
|
||||
"from_bios": {
|
||||
"type": "string",
|
||||
"pattern": "^\\.\\.(/\\.\\.)*(/[^/.][^/]*)*$"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+50
-2
@@ -509,6 +509,14 @@ def load_platform_config(platform_name: str, platforms_dir: str = "platforms") -
|
||||
# The registry key, which per-platform profile fields (installed_on,
|
||||
# not_bundled_on) name: the display name differs (MiSTer FPGA).
|
||||
config["_key"] = platform_name
|
||||
# Where the platform's games live, as its rom folders file records it
|
||||
# from the OS's own source (platforms/romfolders/<key>.yml, roms_root).
|
||||
romfolders = os.path.join(platforms_dir, "romfolders", f"{platform_name}.yml")
|
||||
if os.path.exists(romfolders):
|
||||
with open(romfolders) as f:
|
||||
roms_root = (source_yaml(f) or {}).get("roms_root")
|
||||
if isinstance(roms_root, dict):
|
||||
config["_roms_root"] = roms_root
|
||||
_platform_config_cache[cache_key] = config
|
||||
return config
|
||||
|
||||
@@ -2755,7 +2763,7 @@ def standalone_set(config: dict) -> set[str]:
|
||||
names |= {
|
||||
HANDED_PREFIX + json.dumps(
|
||||
[h.emulator, h.folder, h.directory, sorted(h.handles), h.source_ref,
|
||||
h.roms_folder]
|
||||
h.roms_place]
|
||||
)
|
||||
for h in handed_directories(config)
|
||||
}
|
||||
@@ -2791,7 +2799,9 @@ def _handed(standalone_cores: Iterable[str]) -> list:
|
||||
if not tag.startswith(HANDED_PREFIX):
|
||||
continue
|
||||
emulator, folder, directory, handles, ref, roms = json.loads(tag[len(HANDED_PREFIX):])
|
||||
found.append(HandedDirectory(emulator, folder, directory, frozenset(handles), ref, roms))
|
||||
found.append(HandedDirectory(
|
||||
emulator, folder, directory, frozenset(handles), ref, tuple(roms) if roms else None
|
||||
))
|
||||
return found
|
||||
|
||||
|
||||
@@ -2818,6 +2828,39 @@ EMULATORS_ROOT = "emulators"
|
||||
OUTER_ROOTS = (ROMS_ROOT, EMULATORS_ROOT)
|
||||
|
||||
|
||||
def outer_layout(config: dict, root: str) -> dict | None:
|
||||
"""Where a platform keeps the folder an outer root names, or None.
|
||||
|
||||
roms: the roms root its rom folders file records (``path``, the OS's
|
||||
spelling, and ``from_bios``, relative to the BIOS folder), with the
|
||||
BIOS folder's own name, base_destination, that a run's folder must
|
||||
carry before ``from_bios`` is followed from it. emulators: the
|
||||
registry's ``emulators_directory``, the folders a launcher searches
|
||||
for an emulator by key, which no rom folders file describes.
|
||||
"""
|
||||
if root == ROMS_ROOT:
|
||||
found = config.get("_roms_root") or {}
|
||||
base = str(config.get("base_destination") or "")
|
||||
path, relation = found.get("path"), found.get("from_bios")
|
||||
if not (path and relation) or "<" in str(path):
|
||||
return None
|
||||
if base:
|
||||
return {"path": str(path), "from_bios": str(relation), "bios_folder": base}
|
||||
# A list whose dests start above the BIOS folder (AmberELEC's
|
||||
# bios/...) installs into the folder holding it: a roms root there
|
||||
# or below is part of the install tree, written as a plain dest.
|
||||
declared = declared_root(config)
|
||||
if not declared:
|
||||
return None
|
||||
inside = os.path.normpath(f"{declared}/{relation}")
|
||||
if inside == ".." or inside.startswith("../"):
|
||||
return None
|
||||
return {"path": str(path), "install_prefix": "" if inside == "." else inside}
|
||||
if root == EMULATORS_ROOT:
|
||||
return config.get("emulators_directory") or None
|
||||
return None
|
||||
|
||||
|
||||
def standalone_layout_path(entry: dict, profile: dict) -> str | None:
|
||||
"""The path of an entry relative to the directories its standalone build declares.
|
||||
|
||||
@@ -2908,6 +2951,11 @@ def platform_layouts(
|
||||
tree, path = placed
|
||||
moved = {**f, "standalone_path": path,
|
||||
"layout_path": standalone_layout_path(f, profile)}
|
||||
if tree == "install":
|
||||
# Below the roms root inside the install tree (AmberELEC's
|
||||
# /storage/roms): a plain dest the platform prefix skips.
|
||||
files.append({**moved, "unprefixed": True})
|
||||
continue
|
||||
# A file the launcher runs from the roms directory (ROCKNIX's
|
||||
# roms/pico-8) or an emulator folder (RetroBat's emulators/pico8)
|
||||
# is relative to it, and says so.
|
||||
|
||||
@@ -40,6 +40,7 @@ from alternatives import core_file_spares, settle_sets, slot_set_keys
|
||||
from common import resolve_platform_cores as _platform_cores
|
||||
from common import (
|
||||
OUTER_ROOTS,
|
||||
outer_layout,
|
||||
installed_data_refs,
|
||||
platform_arg,
|
||||
require_directory,
|
||||
@@ -4686,11 +4687,12 @@ def _record_absent(
|
||||
)
|
||||
|
||||
|
||||
# What a manifest's roms_directory and emulators_directory carry from the
|
||||
# registry: the BIOS folder's name, and for emulator folders the places the
|
||||
# What a manifest's roms_directory and emulators_directory carry: the BIOS
|
||||
# folder's name, for the roms root its place relative to the BIOS folder
|
||||
# (romfolders roms_root.from_bios), and for emulator folders the places the
|
||||
# launcher searches, the one a missing folder is created at, and the config
|
||||
# file whose key moves a folder.
|
||||
MANIFEST_OUTER_FIELDS = ("bios_folder", "searched", "default", "config")
|
||||
MANIFEST_OUTER_FIELDS = ("bios_folder", "from_bios", "searched", "default", "config")
|
||||
|
||||
|
||||
def _record_unplaceable(unplaceable: list[dict], record_omission: Callable[..., None]) -> None:
|
||||
@@ -5259,7 +5261,7 @@ def generate_manifest(
|
||||
if data_directories:
|
||||
result["data_directories"] = data_directories
|
||||
for root in OUTER_ROOTS:
|
||||
layout = config.get(f"{root}_directory") or {}
|
||||
layout = outer_layout(config, root) or {}
|
||||
if layout and any(entry.get("root") == root
|
||||
for entry in [*manifest_files, *result["omitted_files"]]):
|
||||
# Where the installer finds the folder: relative to the folder
|
||||
|
||||
+30
-11
@@ -331,6 +331,9 @@ BIOS_TREE = ""
|
||||
ROMS_TREE = "roms"
|
||||
# The emulator folders of a platform whose registry describes them.
|
||||
EMULATORS_TREE = "emulators"
|
||||
# The tree a platform's list installs into when it starts above the BIOS
|
||||
# folder: a plain dest, with no prefix.
|
||||
INSTALL_TREE = "install"
|
||||
# A folder of neither tree, which no pack and no installer can fill.
|
||||
OUTSIDE_TREE = "outside"
|
||||
Place = tuple[str, str]
|
||||
@@ -382,15 +385,13 @@ class HandedDirectory:
|
||||
directory: str
|
||||
handles: frozenset[str]
|
||||
source_ref: str
|
||||
roms_folder: str | None = None
|
||||
roms_place: Place | None = None
|
||||
|
||||
def place(self) -> Place | None:
|
||||
"""The folder as a place, None when it lies outside both roots."""
|
||||
if self.folder is not None:
|
||||
return (BIOS_TREE, self.folder)
|
||||
if self.roms_folder is not None:
|
||||
return (ROMS_TREE, self.roms_folder)
|
||||
return None
|
||||
return self.roms_place
|
||||
|
||||
|
||||
def handed_directories(config: dict) -> list[HandedDirectory]:
|
||||
@@ -430,19 +431,37 @@ def handed_directories(config: dict) -> list[HandedDirectory]:
|
||||
directory=directory,
|
||||
handles=handles,
|
||||
source_ref=str(record.get("source_ref", "")),
|
||||
roms_folder=None if folder is not None else folder_in_roms(raw, config),
|
||||
roms_place=None if folder is not None else _roms_place(
|
||||
config, folder_in_roms(raw, config)
|
||||
),
|
||||
))
|
||||
return found
|
||||
|
||||
|
||||
def _roms_place(config: dict, path: str | None) -> Place | None:
|
||||
"""A path below the roms root as a place: in the install tree when the
|
||||
platform installs above its BIOS folder (AmberELEC), else the roms tree."""
|
||||
if path is None:
|
||||
return None
|
||||
from common import ROMS_ROOT, outer_layout # noqa: PLC0415
|
||||
|
||||
layout = outer_layout(config, ROMS_ROOT) or {}
|
||||
if "install_prefix" in layout:
|
||||
prefix = layout["install_prefix"]
|
||||
return (INSTALL_TREE, sanitize_pack_path(f"{prefix}/{path}" if prefix else path))
|
||||
return (ROMS_TREE, path)
|
||||
|
||||
|
||||
def folder_in_roms(directory: str, config: dict) -> str | None:
|
||||
"""A directory relative to the platform's roms directory, None outside it.
|
||||
|
||||
Only a platform whose registry names the roms directory has one
|
||||
(``roms_directory.path``): ROCKNIX's /storage/roms, which holds its BIOS
|
||||
Only a platform whose rom folders file records its roms root has one
|
||||
(``roms_root.path``): ROCKNIX's /storage/roms, which holds its BIOS
|
||||
folder and the folders its launchers run programs from.
|
||||
"""
|
||||
roms = str((config.get("roms_directory") or {}).get("path") or "").rstrip("/")
|
||||
from common import ROMS_ROOT, outer_layout # noqa: PLC0415
|
||||
|
||||
roms = str((outer_layout(config, ROMS_ROOT) or {}).get("path") or "").rstrip("/")
|
||||
directory = directory.strip().rstrip("/")
|
||||
if not roms or not directory.startswith(roms + "/"):
|
||||
return None
|
||||
@@ -503,7 +522,7 @@ def executed_files(config: dict) -> list[ExecutedFile]:
|
||||
f"{directories[0]}/{name}" if directories[0] else name
|
||||
))
|
||||
elif roms is not None:
|
||||
place = (ROMS_TREE, sanitize_pack_path(f"{roms}/{name}" if roms else name))
|
||||
place = _roms_place(config, sanitize_pack_path(f"{roms}/{name}" if roms else name))
|
||||
elif emulator_folder is not None:
|
||||
place = (EMULATORS_TREE, sanitize_pack_path(f"{emulator_folder}/{name}"))
|
||||
else:
|
||||
@@ -581,8 +600,8 @@ def standalone_bindings(
|
||||
key = "/".join(p for p in (sub, rest) if p)
|
||||
found.setdefault(key, set()).add(target)
|
||||
linked = True
|
||||
if not linked and record.roms_folder is not None:
|
||||
found.setdefault(sub, set()).add((ROMS_TREE, record.roms_folder))
|
||||
if not linked and record.roms_place is not None:
|
||||
found.setdefault(sub, set()).add(record.roms_place)
|
||||
if EXECUTABLE_DIRECTORY in wanted:
|
||||
paths = list(layout)
|
||||
for run in executed:
|
||||
|
||||
+13
-7
@@ -18,7 +18,7 @@ from common import resolve_local_file
|
||||
from common import resolve_platform_cores
|
||||
from common import core_system_dirs, platform_layouts, system_dir_path
|
||||
from common import standalone_set as platform_standalone_set
|
||||
from common import OUTER_ROOTS, sanitize_pack_path
|
||||
from common import OUTER_ROOTS, outer_layout, sanitize_pack_path
|
||||
from common import size_fits
|
||||
from validation import deliverable, read_from_save_dir, read_from_system_dir
|
||||
from packpaths import libretro_systems, save_destination, save_layout
|
||||
@@ -44,6 +44,10 @@ def extra_full_destination(fe: dict, prefix: str) -> str:
|
||||
"""
|
||||
if fe.get("root") == "save":
|
||||
return str(fe.get("pack_path") or "")
|
||||
if fe.get("unprefixed"):
|
||||
# A path of the install tree outside the BIOS folder (AmberELEC's
|
||||
# pico-8/ beside bios/): no platform prefix in front.
|
||||
return sanitize_pack_path(fe.get("destination", fe.get("name", "")))
|
||||
if fe.get("root") in OUTER_ROOTS:
|
||||
return outer_destination(
|
||||
fe["root"], sanitize_pack_path(fe.get("destination", fe.get("name", "")))
|
||||
@@ -573,7 +577,7 @@ def _agnostic_scan_extras(
|
||||
# The scan walks the BIOS tree: a file read below the save
|
||||
# directory is placed by the gap report's pass.
|
||||
if (read_from_save_dir(f, standalone) or f.get("unplaced")
|
||||
or f.get("root") in OUTER_ROOTS):
|
||||
or f.get("root") in OUTER_ROOTS or f.get("unprefixed")):
|
||||
continue
|
||||
# An agnostic BIOS mode says the BIOS filename is free, not that
|
||||
# every file the emulator loads is. A free filename still has a
|
||||
@@ -1024,12 +1028,10 @@ class ExtraPlacement:
|
||||
self.native_systems = native_slug_systems(config)
|
||||
self.flat = bool(config.get("firmware_folder_flat"))
|
||||
self.save = save_layout(config)
|
||||
# The roms directory and emulator folders the registry describes,
|
||||
# The roms root and emulator folders the platform's files describe,
|
||||
# for a file a launcher runs from them (ROCKNIX's roms/pico-8,
|
||||
# RetroBat's emulators/pico8).
|
||||
self.outer = {
|
||||
root for root in OUTER_ROOTS if config.get(f"{root}_directory")
|
||||
}
|
||||
self.outer = {root for root in OUTER_ROOTS if outer_layout(config, root)}
|
||||
self.config = config
|
||||
self.norm_map = (
|
||||
{_norm_system_id(sid): sid for sid in self.platform_systems}
|
||||
@@ -1050,6 +1052,8 @@ class ExtraPlacement:
|
||||
"""
|
||||
if entry.get("unplaced"):
|
||||
return None
|
||||
if entry.get("unprefixed"):
|
||||
return dest, dest
|
||||
if entry.get("root") in OUTER_ROOTS:
|
||||
root = entry["root"]
|
||||
return (dest, outer_destination(root, dest)) if root in self.outer else None
|
||||
@@ -1339,7 +1343,7 @@ def _collect_emulator_extras(
|
||||
# covered elsewhere belongs to another program's file.
|
||||
# Nor is one placed outside the BIOS tree by the layout.
|
||||
if (fname not in covered_names or f.get("unsourceable") or f.get("unplaced")
|
||||
or f.get("root") in OUTER_ROOTS):
|
||||
or f.get("root") in OUTER_ROOTS or f.get("unprefixed")):
|
||||
continue
|
||||
# Installed with the emulator or by the platform's package,
|
||||
# as the first pass already decided for the same entry.
|
||||
@@ -1586,6 +1590,8 @@ def _report_extra(u: dict, name: str, dest: str) -> dict:
|
||||
extra["system_dir"] = u["system_dir"]
|
||||
if u.get("layout_path"):
|
||||
extra["layout_path"] = u["layout_path"]
|
||||
if u.get("unprefixed"):
|
||||
extra["unprefixed"] = True
|
||||
# The archive layout the core opens ranks same-named copies by what
|
||||
# they hold. Without it the first copy indexed won.
|
||||
if u.get("contents"):
|
||||
|
||||
@@ -794,6 +794,8 @@ def find_undeclared_files(
|
||||
entry["members"] = members
|
||||
if f.get("layout_path"):
|
||||
entry["layout_path"] = f["layout_path"]
|
||||
if f.get("unprefixed"):
|
||||
entry["unprefixed"] = True
|
||||
if f.get("unplaced"):
|
||||
entry["unplaced"] = f["unplaced"]
|
||||
elif f.get("root") in OUTER_ROOTS:
|
||||
|
||||
@@ -274,13 +274,36 @@ class AProgramRunFromItsFolder(unittest.TestCase):
|
||||
}))
|
||||
(self.platforms / "_registry.yml").write_text(yaml.safe_dump({"platforms": {
|
||||
**{name: {"config": f"{name}.yml"} for name in launchers},
|
||||
"romsplat": {"config": "romsplat.yml",
|
||||
"roms_directory": {"path": "/storage/roms", "bios_folder": "bios"}},
|
||||
"emuplat": {"config": "emuplat.yml", "emulators_directory": {
|
||||
"launcher_spelling": '<GetPath("{key}")>', "bios_folder": "bios",
|
||||
"searched": ["frontend/{key}", "emulators/{key}"],
|
||||
"default": "emulators/{key}", "config": "frontend/launcher.cfg"}},
|
||||
}}))
|
||||
# The roms root as the OS's own source records it (romfolders).
|
||||
(self.platforms / "romfolders").mkdir()
|
||||
(self.platforms / "romfolders" / "romsplat.yml").write_text(yaml.safe_dump({
|
||||
"setup": "romsplat", "platform": "romsplat",
|
||||
"roms_root": {"path": "/storage/roms", "from_bios": "..", "source_ref": "os x.mk:1"},
|
||||
"folders": [],
|
||||
}))
|
||||
# A list that installs into the roms root itself, its BIOS folder
|
||||
# one of the folders there (AmberELEC's /storage/roms).
|
||||
(self.platforms / "rootplat.yml").write_text(yaml.safe_dump({
|
||||
"platform": "rootplat", "version": "1", "verification_mode": "existence",
|
||||
"base_destination": "", "cores": ["prog"], "standalone_cores": ["prog"],
|
||||
"launchers": [{**run, "names": ["prog"], "search_dir": "/storage/roms/prog"}],
|
||||
"systems": {"prog-system": {"files": [
|
||||
{"name": "own.bin", "destination": "bios/own.bin", "required": False},
|
||||
]}},
|
||||
}))
|
||||
registry = yaml.safe_load((self.platforms / "_registry.yml").read_text())
|
||||
registry["platforms"]["rootplat"] = {"config": "rootplat.yml"}
|
||||
(self.platforms / "_registry.yml").write_text(yaml.safe_dump(registry))
|
||||
(self.platforms / "romfolders" / "rootplat.yml").write_text(yaml.safe_dump({
|
||||
"setup": "rootplat", "platform": "rootplat",
|
||||
"roms_root": {"path": "/storage/roms", "from_bios": "..", "source_ref": "os x.mk:1"},
|
||||
"folders": [],
|
||||
}))
|
||||
(self.emulators / "prog.yml").write_text(yaml.safe_dump({
|
||||
"emulator": "Prog", "type": "standalone", "cores": ["prog"],
|
||||
"systems": ["prog-system"],
|
||||
@@ -332,11 +355,20 @@ class AProgramRunFromItsFolder(unittest.TestCase):
|
||||
sorted((f["dest"], f.get("root")) for f in manifest["files"]),
|
||||
[("prog/prog", "roms"), ("prog/prog.dat", "roms")],
|
||||
)
|
||||
self.assertEqual(manifest["roms_directory"], {"bios_folder": "bios"})
|
||||
self.assertEqual(manifest["roms_directory"], {"bios_folder": "bios", "from_bios": ".."})
|
||||
entries = self.verify("romsplat")
|
||||
self.assertEqual(sorted(u["path"] for u in entries), ["prog/prog", "prog/prog.dat"])
|
||||
self.assertTrue(all(u["in_pack"] is False for u in entries))
|
||||
|
||||
def test_a_roms_root_inside_the_install_tree_is_a_plain_dest(self) -> None:
|
||||
self.assertEqual(self.pack("rootplat"), ["prog/prog", "prog/prog.dat"])
|
||||
manifest = self.manifest("rootplat")
|
||||
self.assertEqual(
|
||||
sorted((f["dest"], f.get("root")) for f in manifest["files"] if "prog" in f["dest"]),
|
||||
[("prog/prog", None), ("prog/prog.dat", None)],
|
||||
)
|
||||
self.assertNotIn("roms_directory", manifest)
|
||||
|
||||
def test_run_from_an_emulator_folder_is_named(self) -> None:
|
||||
self.assertEqual(self.pack("exeplat"), [])
|
||||
manifest = self.manifest("exeplat")
|
||||
@@ -367,6 +399,19 @@ class AProgramRunFromItsFolder(unittest.TestCase):
|
||||
self.assertEqual({o["reason"] for o in left}, {"no_roms_directory"})
|
||||
with self.assertRaises(ValueError):
|
||||
install._check_roms_directory({"files": files})
|
||||
# A roms root beside the BIOS folder (Batocera's ../roms).
|
||||
beside = {**manifest, "roms_directory": {"bios_folder": "bios", "from_bios": "../roms"}}
|
||||
install._check_roms_directory(beside)
|
||||
disk = self.root / "userdata" / "bios"
|
||||
install.place_roms_entries(files, disk, beside, "romsplat", say=False)
|
||||
self.assertEqual(install._entry_place(disk, kept_entry := files[0])[0],
|
||||
self.root / "userdata" / "roms")
|
||||
self.assertEqual(kept_entry["root"], "roms")
|
||||
for climbing in ("roms", "../roms/..", "/storage/roms"):
|
||||
with self.subTest(from_bios=climbing), self.assertRaises(ValueError):
|
||||
install._check_roms_directory(
|
||||
{**manifest, "roms_directory": {"bios_folder": "bios", "from_bios": climbing}}
|
||||
)
|
||||
|
||||
def test_run_from_an_emulator_folder_the_registry_describes(self) -> None:
|
||||
self.assertEqual(self.pack("emuplat"), [])
|
||||
|
||||
Reference in new issue
Block a user