mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
feat: find RetroBat through the folder it records
RetroBat.exe writes its folder to HKCU\SOFTWARE\RetroBat LatestKnownInstallPath on every start (retrobat-executable 702da66a, Program.cs:57 and 99, RegistryTools.cs:15-50). Only C:\RetroBat and the profile folder were looked at, so an install on D: was missed and a forced --platform retrobat wrote into C:\RetroBat\bios. The value is read through winreg, or reg.exe under WSL, before the fixed folders.
This commit is contained in:
1 parent
4f20b5daaf
commit
cdb2cfa6f0
6 files changed
+117
-2
No files matched your search
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "caec72e5ebd146509e3b1fabc7d8d4c5c921567592d6d1581df6e5cc50f3e96f"
|
||||
$defaultInstallSha256 = "f05f862fcebc16e99d692a20a09163665828ea0383643fcc96a41b11d77fcff7"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+59
@@ -1092,6 +1092,64 @@ def _detect_by_executable(os_type: str, found: list[tuple[str, Path]]) -> None:
|
||||
found.append((platform_name, newest.parent / subdir))
|
||||
|
||||
|
||||
# The registry's registry rules: (os, platform, key, value, BIOS folder under
|
||||
# the folder the value names). RetroBat.exe writes its own folder there on
|
||||
# every start (retrobat-executable 702da66a, RetroBat/RetroBat/Program.cs:57
|
||||
# and 99, RegistryTools.cs:15-50), wherever it was installed. The path rules
|
||||
# only knew C:\RetroBat and the profile folder.
|
||||
_REGISTRY_RULES: tuple[tuple[str, str, str, str, str], ...] = (
|
||||
("windows", "retrobat", "HKCU\\SOFTWARE\\RetroBat", "LatestKnownInstallPath", "bios"),
|
||||
)
|
||||
|
||||
|
||||
def _read_registry(key: str, value: str) -> str | None:
|
||||
"""A string value of the Windows registry, read natively or, under WSL,
|
||||
through reg.exe. None when the key, the value or the means is missing."""
|
||||
if os.name == "nt":
|
||||
import winreg # noqa: PLC0415
|
||||
|
||||
hive, _, subkey = key.partition("\\")
|
||||
roots = {"HKCU": winreg.HKEY_CURRENT_USER, "HKLM": winreg.HKEY_LOCAL_MACHINE}
|
||||
try:
|
||||
with winreg.OpenKey(roots[hive], subkey) as handle:
|
||||
data, _kind = winreg.QueryValueEx(handle, value)
|
||||
except (OSError, KeyError):
|
||||
return None
|
||||
return data.strip() if isinstance(data, str) and data.strip() else None
|
||||
if not _WSL["active"]:
|
||||
return None
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["reg.exe", "query", key, "/v", value],
|
||||
capture_output=True, text=True, errors="replace", timeout=10,
|
||||
stdin=subprocess.DEVNULL, cwd="/mnt/c" if Path("/mnt/c").is_dir() else None,
|
||||
)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
return None
|
||||
match = re.search(
|
||||
rf"^\s*{re.escape(value)}\s+REG_(?:EXPAND_)?SZ\s+(.+?)\s*$", result.stdout, re.M
|
||||
)
|
||||
return match.group(1) if match else None
|
||||
|
||||
|
||||
def _detect_by_registry(os_type: str, found: list[tuple[str, Path]]) -> None:
|
||||
"""Add a platform whose own program names its folder in the registry.
|
||||
|
||||
A folder since moved or removed is passed over, so the path rules still
|
||||
get their turn.
|
||||
"""
|
||||
systems = ("windows",) if os_type in ("windows", "wsl") else ()
|
||||
for rule_os, platform_name, key, value, subdir in _REGISTRY_RULES:
|
||||
if rule_os not in systems or any(name == platform_name for name, _ in found):
|
||||
continue
|
||||
folder = _read_registry(key, value)
|
||||
if not folder:
|
||||
continue
|
||||
base = _host_path(folder.rstrip("\\/") or folder)
|
||||
if base.is_dir():
|
||||
found.append((platform_name, base / subdir))
|
||||
|
||||
|
||||
def _detect_by_path(os_type: str, found: list[tuple[str, Path]]) -> None:
|
||||
"""Add what a registry path rule finds, for a platform not found yet."""
|
||||
systems = ("linux", "windows") if os_type == "wsl" else (os_type,)
|
||||
@@ -1239,6 +1297,7 @@ def detect_platforms(os_type: str) -> list[tuple[str, Path]]:
|
||||
found.append(("bizhawk", bizhawk))
|
||||
|
||||
_detect_by_executable(os_type, found)
|
||||
_detect_by_registry(os_type, found)
|
||||
_detect_by_path(os_type, found)
|
||||
return found
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ esac
|
||||
TEMP_INSTALLER=""
|
||||
TEMP_DIRECTORY=""
|
||||
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
DEFAULT_INSTALL_SHA256="caec72e5ebd146509e3b1fabc7d8d4c5c921567592d6d1581df6e5cc50f3e96f"
|
||||
DEFAULT_INSTALL_SHA256="f05f862fcebc16e99d692a20a09163665828ea0383643fcc96a41b11d77fcff7"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -351,6 +351,14 @@ platforms:
|
||||
target_source: null
|
||||
install:
|
||||
detect:
|
||||
# RetroBat.exe writes its own folder there on every start, wherever it
|
||||
# was installed (retrobat-executable 702da66a,
|
||||
# RetroBat/RetroBat/Program.cs:57 and 99, RegistryTools.cs:15-50).
|
||||
- os: windows
|
||||
method: registry
|
||||
key: 'HKCU\SOFTWARE\RetroBat'
|
||||
value: LatestKnownInstallPath
|
||||
bios_subdir: bios
|
||||
# installer.iss: DefaultDirName=C:\RetroBat, the first place to look.
|
||||
- os: windows
|
||||
method: path_exists
|
||||
|
||||
@@ -3800,5 +3800,52 @@ class ANetworkFailureNamesTheNetwork(unittest.TestCase):
|
||||
self.assertNotIn("being written to", text)
|
||||
|
||||
|
||||
class RetroBatIsFoundWhereItSaysItIs(unittest.TestCase):
|
||||
"""RetroBat on D:\\RetroBat was not detected, and --platform retrobat
|
||||
wrote 7.6 GB into C:\\RetroBat\\bios, a folder it does not read.
|
||||
RetroBat.exe writes its folder to the registry on every start."""
|
||||
|
||||
def test_the_table_is_the_registry(self):
|
||||
import yaml # noqa: PLC0415
|
||||
|
||||
registry = yaml.safe_load((REPO_ROOT / "platforms" / "_registry.yml").read_text())
|
||||
rules = {
|
||||
(rule["os"], name, rule["key"], rule["value"], rule["bios_subdir"])
|
||||
for name, entry in registry["platforms"].items()
|
||||
for rule in (entry.get("install") or {}).get("detect", [])
|
||||
if rule["method"] == "registry"
|
||||
}
|
||||
self.assertEqual(set(install._REGISTRY_RULES), rules)
|
||||
|
||||
def test_the_registry_folder_wins_over_the_default(self):
|
||||
folder = Path(_tempdir(self))
|
||||
with unittest.mock.patch.object(install, "_read_registry",
|
||||
return_value=str(folder) + "\\"):
|
||||
found: list = []
|
||||
install._detect_by_registry("windows", found)
|
||||
self.assertEqual(found, [("retrobat", folder / "bios")])
|
||||
|
||||
def test_a_folder_since_removed_is_passed_over(self):
|
||||
gone = Path(_tempdir(self)) / "moved"
|
||||
with unittest.mock.patch.object(install, "_read_registry", return_value=str(gone)):
|
||||
found: list = []
|
||||
install._detect_by_registry("windows", found)
|
||||
self.assertEqual(found, [])
|
||||
|
||||
def test_wsl_reads_it_through_reg_exe(self):
|
||||
output = ("\nHKEY_CURRENT_USER\\SOFTWARE\\RetroBat\n"
|
||||
" LatestKnownInstallPath REG_SZ D:\\Games\\RetroBat\\\n\n")
|
||||
with unittest.mock.patch.dict(install._WSL, {"active": True, "root": "/mnt"}), \
|
||||
unittest.mock.patch.object(install.os, "name", "posix"), \
|
||||
unittest.mock.patch.object(
|
||||
install.subprocess, "run",
|
||||
return_value=SimpleNamespace(stdout=output, returncode=0)) as run:
|
||||
value = install._read_registry("HKCU\\SOFTWARE\\RetroBat", "LatestKnownInstallPath")
|
||||
self.assertEqual(value, "D:\\Games\\RetroBat\\")
|
||||
self.assertEqual(install._host_path(value.rstrip("\\")),
|
||||
Path("/mnt/d/Games/RetroBat"))
|
||||
self.assertEqual(run.call_args[0][0][:2], ["reg.exe", "query"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -318,6 +318,7 @@ WSL does not pass them. A forced `--platform retrobat` falls back to
|
||||
|
||||
| Evidence | Platform | BIOS directory |
|
||||
|----------|----------|----------------|
|
||||
| `HKCU\SOFTWARE\RetroBat` `LatestKnownInstallPath`, which `RetroBat.exe` writes on every start (read through `reg.exe` under WSL) | RetroBat | that folder + `\bios`, before the fixed folders above |
|
||||
| `~/.config/EmuDeck/settings.sh` | EmuDeck | `emulationPath` + `/bios` |
|
||||
| `%APPDATA%\EmuDeck\settings.ps1` | EmuDeck | `$emulationPath` + `\bios` |
|
||||
| `~/.var/app/net.retrodeck.retrodeck/config/retrodeck/retrodeck.json` | RetroDECK | `paths.rd_home_path`, falling back to the pre-migration `retrodeck.cfg` and its `rdhome` |
|
||||
|
||||
Reference in new issue
Block a user