From 8d0b6d5f9395e49c0ad062f4c4072f7e55c26617 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sun, 18 Oct 2026 05:26:39 +0200 Subject: [PATCH] fix: find RetroArch in Steam libraries and ES-DE The installer looked for retroarch.exe in C:\RetroArch-Win64 and Program Files\RetroArch only, so a RetroArch under Program Files\ RetroArch-Win64, in a Steam library on another drive, or in an installed ES-DE's Emulators folder went undetected. All three are searched; Steam libraries come from Steam's own library list. --- install.ps1 | 2 +- install.py | 43 ++++++++++++++++++++++++++++++++++++++++--- install.sh | 2 +- tests/test_install.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/install.ps1 b/install.ps1 index 7a980f89..bf3da60b 100644 --- a/install.ps1 +++ b/install.ps1 @@ -8,7 +8,7 @@ param( $ErrorActionPreference = "Stop" $defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" -$defaultInstallSha256 = "973e116ab59e233cd4fe5ebb77d4973bc06013b22b6388e80d12fa1d61fb0c73" +$defaultInstallSha256 = "bfc3a2127689147e8a5f729a9ed668608f06dbd3b14ca6e768cdf2a7f90d5d32" $maximumInstallerBytes = 2MB $installerExit = 0 $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } diff --git a/install.py b/install.py index 091af425..a4b2bfbe 100644 --- a/install.py +++ b/install.py @@ -457,14 +457,51 @@ def _retroarch_cfg_dir( return None +def _steam_libraries() -> list[Path]: + """Every Steam library, the default one first. + + Steam lists the others in steamapps/libraryfolders.vdf, each as a + "path" line; a RetroArch installed on D:/SteamLibrary was not found + when only Program Files was searched. + """ + roots: list[Path] = [] + for var in ("ProgramFiles(x86)", "ProgramFiles"): + base = os.environ.get(var, "") + if base and (Path(base) / "Steam").is_dir(): + roots.append(Path(base) / "Steam") + libraries = list(roots) + for root in roots: + vdf = root / "steamapps" / "libraryfolders.vdf" + try: + text = vdf.read_text(encoding="utf-8", errors="replace") + except OSError: + continue + for raw in re.findall(r'"path"\s+"([^"]+)"', text): + library = Path(raw.replace("\\\\", "\\")) + if library not in libraries: + libraries.append(library) + return libraries + + def _windows_retroarch_dirs() -> list[Path]: - """Folders holding retroarch.exe where the installer and the archive put - it: C:/RetroArch-Win64 by default, C:/RetroArch for 32-bit builds.""" + """Folders holding retroarch.exe where its installers put it. + + C:/RetroArch-Win64 by default, C:/RetroArch for 32-bit builds, the same + names under Program Files, every Steam library, and the Emulators folder + of an installed ES-DE (es_find_rules.xml lists all of them). + """ candidates = [Path("C:/RetroArch-Win64"), Path("C:/RetroArch")] for var in ("ProgramFiles", "ProgramFiles(x86)"): root = os.environ.get(var, "") if root: - candidates.append(Path(root) / "RetroArch") + candidates += [Path(root) / "RetroArch-Win64", Path(root) / "RetroArch"] + candidates += [ + Path(root) / "ES-DE" / "Emulators" / name + for name in ("RetroArch-Win64", "RetroArch") + ] + candidates += [ + library / "steamapps" / "common" / "RetroArch" for library in _steam_libraries() + ] return [folder for folder in candidates if (folder / "retroarch.exe").is_file()] diff --git a/install.sh b/install.sh index 18daa8a3..d2f5f161 100755 --- a/install.sh +++ b/install.sh @@ -18,7 +18,7 @@ esac TEMP_INSTALLER="" TEMP_DIRECTORY="" DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" -DEFAULT_INSTALL_SHA256="973e116ab59e233cd4fe5ebb77d4973bc06013b22b6388e80d12fa1d61fb0c73" +DEFAULT_INSTALL_SHA256="bfc3a2127689147e8a5f729a9ed668608f06dbd3b14ca6e768cdf2a7f90d5d32" MAX_INSTALLER_BYTES=2097152 cleanup() { diff --git a/tests/test_install.py b/tests/test_install.py index 0f272cba..101295d8 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -970,6 +970,49 @@ class DetectionFollowsTheRegistry(unittest.TestCase): self.assertEqual(found, [("emudeck", home / "elsewhere" / "bios")]) +class RetroArchIsFoundWhereWindowsInstallsPutIt(unittest.TestCase): + """Program Files\\RetroArch-Win64, a Steam library on another drive and + an installed ES-DE's Emulators folder all held a RetroArch the one-liner + reported as "no supported platform detected".""" + + def _env(self, program_files: Path) -> None: + patcher = unittest.mock.patch.dict( + os.environ, {"ProgramFiles": str(program_files), "ProgramFiles(x86)": ""} + ) + patcher.start() + self.addCleanup(patcher.stop) + + @staticmethod + def _exe(folder: Path) -> Path: + folder.mkdir(parents=True) + (folder / "retroarch.exe").write_bytes(b"MZ") + return folder + + def test_program_files_win64(self): + program_files = Path(_tempdir(self)) + self._env(program_files) + found = self._exe(program_files / "RetroArch-Win64") + self.assertIn(found, install._windows_retroarch_dirs()) + + def test_a_steam_library_on_another_drive(self): + program_files = Path(_tempdir(self)) + library = Path(_tempdir(self)) + steamapps = program_files / "Steam" / "steamapps" + steamapps.mkdir(parents=True) + (steamapps / "libraryfolders.vdf").write_text( + '"libraryfolders"\n{\n\t"1"\n\t{\n\t\t"path"\t\t"' + str(library) + '"\n\t}\n}\n' + ) + self._env(program_files) + found = self._exe(library / "steamapps" / "common" / "RetroArch") + self.assertIn(found, install._windows_retroarch_dirs()) + + def test_an_installed_es_de(self): + program_files = Path(_tempdir(self)) + self._env(program_files) + found = self._exe(program_files / "ES-DE" / "Emulators" / "RetroArch-Win64") + self.assertIn(found, install._windows_retroarch_dirs()) + + class InstallerStaysOnPython38AndTheStdlib(unittest.TestCase): """install.py runs where the bootstraps let it run: Python 3.8, stdlib only.