mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-06 01:53:56 -06:00
feat: let --emulator take an alias name
--emulator mednafen_psx refused with 'use --emulator beetle_psx' although the profile names its target. The alias now selects that profile and says so on stderr, in verify, generate_pack and cross_reference alike. Launchers are still refused, and pipeline step 5 skips aliases since they compare under the profile they name.
This commit is contained in:
1 parent
640331b159
commit
fb9b5592a5
5 files changed
+66
-28
No files matched your search
+16
-10
@@ -1870,12 +1870,12 @@ def select_emulator_profiles(
|
||||
all_profiles: dict,
|
||||
standalone: bool = False,
|
||||
) -> list[tuple[str, dict]]:
|
||||
"""Resolve named profiles, refusing the ones that answer for others.
|
||||
"""Resolve named profiles, refusing the ones that answer for no core.
|
||||
|
||||
An alias is the same binary under another name and a launcher only
|
||||
starts an emulator, so neither has requirements of its own: naming one
|
||||
is a question about the wrong profile, and the error says which one to
|
||||
ask instead. Raising rather than exiting lets the verifier stop and the
|
||||
An alias is the same binary under another name, so naming one selects
|
||||
the profile it is an alias of, said on stderr. A launcher only starts an
|
||||
emulator and has no requirements of its own: naming one is a question
|
||||
about the wrong profile, and the error says so. Raising rather than exiting lets the verifier stop and the
|
||||
builder return empty-handed from one rule.
|
||||
"""
|
||||
selected: list[tuple[str, dict]] = []
|
||||
@@ -1916,11 +1916,17 @@ def select_emulator_profiles(
|
||||
),
|
||||
None,
|
||||
)
|
||||
raise ProfileSelectionError(
|
||||
f"{name} is an alias of {target}: use --emulator {target}"
|
||||
if target
|
||||
else f"{name} is an alias with no profile of its own to name"
|
||||
)
|
||||
if not target or target not in all_profiles:
|
||||
raise ProfileSelectionError(
|
||||
f"{name} is an alias with no profile of its own to name"
|
||||
)
|
||||
# The name a user reads in RetroArch or on the buildbot: the tool
|
||||
# knows the profile, so it says which and carries on.
|
||||
print(f"{name} is {target}: using its profile", file=sys.stderr)
|
||||
name, profile = target, all_profiles[target]
|
||||
kind = profile.get("type", "libretro")
|
||||
if any(key == name for key, _ in selected):
|
||||
continue
|
||||
if kind == "launcher":
|
||||
raise ProfileSelectionError(
|
||||
f"{name} is a launcher: use the emulator it launches"
|
||||
|
||||
@@ -541,6 +541,8 @@ def check_emulator_packs(
|
||||
all_ok = True
|
||||
compared = 0
|
||||
for name in sorted(profiles):
|
||||
if profiles[name].get("type") == "alias":
|
||||
continue # selects the profile it names, compared under that name
|
||||
for standalone in (False, True):
|
||||
try:
|
||||
select_emulator_profiles([name], profiles, standalone)
|
||||
|
||||
@@ -5610,12 +5610,17 @@ class ANamedPackThatIsAbsentFails(unittest.TestCase):
|
||||
|
||||
|
||||
|
||||
class AnAliasNamesItsProfile(unittest.TestCase):
|
||||
""""flycast_gles2 is an alias of flycast -use --emulator flycast": the
|
||||
dash read as an option, and an alias without alias_of advised
|
||||
"--emulator ?"."""
|
||||
class AnAliasSelectsItsProfile(unittest.TestCase):
|
||||
"""`--emulator mednafen_psx` refused with "use --emulator beetle_psx",
|
||||
a step the tool could take itself: the name a user reads in RetroArch
|
||||
now selects the profile it is an alias of, and says so on stderr. An
|
||||
alias without alias_of is found through the profile whose cores: names
|
||||
it."""
|
||||
|
||||
def test_the_alias_selects_its_profile(self):
|
||||
import contextlib as _contextlib
|
||||
import io as _io
|
||||
|
||||
def test_the_message(self):
|
||||
from scripts.common import ProfileSelectionError, select_emulator_profiles
|
||||
|
||||
profiles = {
|
||||
@@ -5623,12 +5628,28 @@ class AnAliasNamesItsProfile(unittest.TestCase):
|
||||
"flycast_gles2": {"type": "alias", "alias_of": "flycast"},
|
||||
"orphan": {"type": "alias"},
|
||||
"core": {"type": "libretro", "cores": ["orphan"]},
|
||||
"lost": {"type": "alias"},
|
||||
}
|
||||
for name, expected in (("flycast_gles2", "alias of flycast: use --emulator flycast"),
|
||||
("orphan", "alias of core: use --emulator core")):
|
||||
with self.subTest(name=name), self.assertRaises(ProfileSelectionError) as caught:
|
||||
select_emulator_profiles([name], profiles)
|
||||
self.assertIn(expected, str(caught.exception))
|
||||
for name, expected in (("flycast_gles2", "flycast"), ("orphan", "core")):
|
||||
err = _io.StringIO()
|
||||
with self.subTest(name=name), _contextlib.redirect_stderr(err):
|
||||
selected = select_emulator_profiles([name], profiles)
|
||||
self.assertEqual([key for key, _ in selected], [expected])
|
||||
self.assertIn(f"{name} is {expected}", err.getvalue())
|
||||
with _contextlib.redirect_stderr(_io.StringIO()):
|
||||
both = select_emulator_profiles(["flycast", "flycast_gles2"], profiles)
|
||||
self.assertEqual([key for key, _ in both], ["flycast"])
|
||||
with self.assertRaises(ProfileSelectionError):
|
||||
select_emulator_profiles(["lost"], profiles)
|
||||
|
||||
def test_verify_runs_the_alias(self):
|
||||
result = subprocess.run(
|
||||
[sys.executable, "scripts/verify.py", "--emulator", "mednafen_psx"],
|
||||
cwd=ROOT, capture_output=True, text=True, timeout=300, check=False,
|
||||
)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertIn("beetle_psx", result.stdout)
|
||||
self.assertIn("mednafen_psx is beetle_psx", result.stderr)
|
||||
|
||||
|
||||
|
||||
|
||||
+9
-4
@@ -17,7 +17,9 @@ Covers:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import hashlib
|
||||
import io
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
@@ -1444,10 +1446,13 @@ class TestE2E(unittest.TestCase):
|
||||
with self.assertRaises(SystemExit):
|
||||
verify_emulator(["test_game"], self.emulators_dir, self.db, standalone=True)
|
||||
|
||||
def test_93_verify_emulator_alias_rejected(self):
|
||||
"""Alias profile produces error with redirect message."""
|
||||
with self.assertRaises(SystemExit):
|
||||
verify_emulator(["test_alias"], self.emulators_dir, self.db)
|
||||
def test_93_verify_emulator_alias_selects_its_profile(self):
|
||||
"""An alias verifies the profile it is an alias of."""
|
||||
with contextlib.redirect_stderr(io.StringIO()):
|
||||
via_alias = verify_emulator(["test_alias"], self.emulators_dir, self.db)
|
||||
direct = verify_emulator(["test_emu"], self.emulators_dir, self.db)
|
||||
self.assertEqual(via_alias["emulators"], direct["emulators"])
|
||||
self.assertEqual(via_alias["details"], direct["details"])
|
||||
|
||||
def test_94_verify_emulator_launcher_rejected(self):
|
||||
"""Launcher profile produces error."""
|
||||
|
||||
@@ -10,6 +10,8 @@ it, and these tests make the agreement checkable instead of reviewable.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
import unittest
|
||||
@@ -446,10 +448,12 @@ class OneProfileSelector(unittest.TestCase):
|
||||
self.assertIsNone(error)
|
||||
self.assertEqual([n for n, _p in selected], ["real"])
|
||||
|
||||
def test_an_alias_names_the_profile_to_ask_instead(self):
|
||||
_selected, error = self._select(["ghost"])
|
||||
self.assertIn("alias of real", error)
|
||||
self.assertIn("--emulator real", error)
|
||||
def test_an_alias_selects_the_profile_it_names(self):
|
||||
with contextlib.redirect_stderr(io.StringIO()) as err:
|
||||
selected, error = self._select(["ghost"])
|
||||
self.assertIsNone(error)
|
||||
self.assertEqual([n for n, _p in selected], ["real"])
|
||||
self.assertIn("ghost is real", err.getvalue())
|
||||
|
||||
def test_a_launcher_is_refused(self):
|
||||
_selected, error = self._select(["starter"])
|
||||
|
||||
Reference in new issue
Block a user