fix: keep display names out of pack file paths

This commit is contained in:
Abdessamad Derraz committed 2026-10-06 09:09:02 +02:00
1 parent d7e7ec13ae
commit dce43a1281
2 files changed
+71 -7

No files matched your search

+19 -7
View File
@@ -203,6 +203,18 @@ def _system_tag(system_filter: list[str] | None) -> str:
return "_" + "_".join(display_parts)
_UNSAFE_IN_NAME = re.compile(r'[/\\:*?"<>|]')
def _name_part(text: str, space: str = "") -> str:
"""A display name made safe to stand in a file name.
'FinalBurn Neo (CPS-1/CPS-2)' named a directory that did not exist; a
Windows user cannot write ':' or '?' either.
"""
return _UNSAFE_IN_NAME.sub("-", text.replace(" ", space))
def _platform_pack_stem(
group_platforms: list[str], representative: str, platforms_dir: str
) -> str:
@@ -213,14 +225,14 @@ def _platform_pack_stem(
"""
rep_cfg = load_platform_config(representative, platforms_dir)
version = rep_cfg.get("version", rep_cfg.get("dat_version", ""))
version_tag = f"_{version.replace(' ', '')}" if version else ""
version_tag = f"_{_name_part(str(version))}" if version else ""
if len(group_platforms) <= 1:
return rep_cfg.get("platform", representative).replace(" ", "_") + version_tag
return _name_part(rep_cfg.get("platform", representative), "_") + version_tag
names = [
load_platform_config(p, platforms_dir).get("platform", p)
for p in group_platforms
]
return "_".join(n.replace(" ", "") for n in names) + version_tag
return "_".join(_name_part(n) for n in names) + version_tag
@@ -1231,7 +1243,7 @@ def generate_emulator_pack(
return None
# ZIP naming
display_names = [p.get("emulator", n).replace(" ", "") for n, p in selected]
display_names = [_name_part(p.get("emulator", n)) for n, p in selected]
validation_index = _build_validation_index(dict(selected))
narrow_tags = "".join(
tag
@@ -1524,7 +1536,7 @@ def generate_system_pack(
# Use system-based ZIP name
sys_display = "_".join(
"_".join(w.title() for w in sid.split("-")) for sid in system_ids
_name_part("_".join(w.title() for w in sid.split("-"))) for sid in system_ids
)
result = generate_emulator_pack(
matching,
@@ -1697,7 +1709,7 @@ def generate_split_packs(
source, regions, target_name, one_per_slot, required_only
)
)
safe_group = group_name.replace(" ", "_")
safe_group = _name_part(group_name, "_")
new_name = f"{platform_display.replace(' ', '_')}{ver_tag}{narrow_tags}_{safe_group}_BIOS_Pack.zip"
new_path = os.path.join(split_dir, new_name)
if new_path != zip_path:
@@ -1777,7 +1789,7 @@ def generate_md5_pack(
)
)
zip_name = (
f"{context_name.replace(' ', '_')}_Custom{custom_tags}_BIOS_Pack.zip"
f"{_name_part(context_name, '_')}_Custom{custom_tags}_BIOS_Pack.zip"
)
zip_path = os.path.join(output_dir, zip_name)
os.makedirs(output_dir, exist_ok=True)
+52
View File
@@ -0,0 +1,52 @@
"""A display name never becomes a path inside the output directory.
fbneo_cps12 is called 'FinalBurn Neo (CPS-1/CPS-2)': the slash made the
emulator and system packs write into a directory that does not exist, while
verify reported the same scope OK.
"""
from __future__ import annotations
import hashlib
import sys
import tempfile
import unittest
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO_ROOT / "scripts"))
from generate_pack import _name_part, generate_emulator_pack # noqa: E402
class PackFileNames(unittest.TestCase):
def test_separators_and_reserved_characters_are_replaced(self):
self.assertEqual(_name_part("FinalBurn Neo (CPS-1/CPS-2)"), "FinalBurnNeo(CPS-1-CPS-2)")
self.assertEqual(_name_part('a\\b:c*d?"e<f>g|h', "_"), "a-b-c-d--e-f-g-h")
def test_an_emulator_named_with_a_slash_writes_its_pack(self):
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp:
emulators = Path(tmp) / "emulators"
out = Path(tmp) / "out"
emulators.mkdir()
out.mkdir()
rom = Path(tmp) / "demo.bin"
rom.write_bytes(b"demo")
sha1 = hashlib.sha1(b"demo").hexdigest()
(emulators / "demo.yml").write_text(
'emulator: "Demo (A/B)"\ntype: libretro\nsystems: [demo]\n'
f'files:\n - name: demo.bin\n sha1: "{sha1}"\n'
)
db = {
"files": {sha1: {"path": str(rom), "name": "demo.bin", "size": 4,
"md5": hashlib.md5(b"demo").hexdigest()}},
"indexes": {"by_name": {"demo.bin": [sha1]}, "by_md5": {}},
}
result = generate_emulator_pack(
["demo"], str(emulators), db, "bios", str(out), zip_contents={},
)
self.assertTrue(result and Path(result).parent == out, result)
if __name__ == "__main__":
unittest.main()