fix: read RetroArch's config under XDG_CONFIG_HOME

Native RetroArch on Linux keeps retroarch.cfg under $XDG_CONFIG_HOME/retroarch when the variable is set, and falls back to ~/.retroarch.cfg (file_path_special.c fill_pathname_application_data, configuration.c open_default_config_file at e98e1da0). Detection read ~/.config/retroarch only.
This commit is contained in:
Abdessamad Derraz committed 2026-11-06 08:18:59 +01:00
1 parent 19898cb6ea
commit 97d0a478d2
7 files changed
+104 -18

No files matched your search

+1 -1
View File
@@ -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 = "34fd006cc0456c61b9a621e52f35cee6d3fd55ff14bbc6cea207ddc7bc57d858"
$defaultInstallSha256 = "f48287847612b616bcaf607bd50207353bef5648e650a732c2d9595a64726ab0"
$maximumInstallerBytes = 2MB
$installerExit = 0
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
+23 -8
View File
@@ -291,7 +291,6 @@ def _os_default_dests(os_type: str) -> dict[str, Path]:
the command line but not found must not land in ~/bios, which none of
them reads.
"""
home = Path.home()
if os_type == "windows":
return {
# RetroArch's system directory defaults to <exe folder>\system
@@ -307,13 +306,13 @@ def _os_default_dests(os_type: str) -> dict[str, Path]:
# RetroArch may be the Linux one inside the distribution, while RetroBat
# only exists on the Windows side, reached through /mnt/c.
return {
"retroarch": home / ".config" / "retroarch" / "system",
"retroarch": _unix_retroarch_base() / "system",
"retrobat": _host_path("C:/RetroBat/bios"),
}
if os_type == "darwin":
return {"retroarch": _macos_retroarch_base() / "system"}
return {
"retroarch": home / ".config" / "retroarch" / "system",
"retroarch": _unix_retroarch_base() / "system",
}
@@ -1385,6 +1384,17 @@ def _macos_retroarch_base() -> Path:
return Path.home() / "Documents" / "RetroArch"
def _unix_retroarch_base() -> Path:
"""RetroArch's base folder on Linux: $XDG_CONFIG_HOME/retroarch when the
variable is set, else ~/.config/retroarch (fill_pathname_application_data
in file_path_special.c, frontend_unix_get_env in platform_unix.c). The
code tests only that the variable exists, so an empty one counts."""
xdg = os.environ.get("XDG_CONFIG_HOME")
if xdg is not None:
return Path(xdg) / "retroarch"
return Path.home() / ".config" / "retroarch"
# System directory -> the retroarch.cfg it was read from and the directory
# ':' expands to there, for finding the cores of the same installation.
_RETROARCH_CONFIGS: dict[Path, tuple[Path, Path]] = {}
@@ -2773,11 +2783,16 @@ def detect_platforms(os_type: str) -> list[tuple[str, Path]]:
if ra_dir:
found.append(("retroarch", ra_dir))
# RetroArch native
native_cfg = home / ".config" / "retroarch" / "retroarch.cfg"
ra_dir = _parse_retroarch_system_dir(native_cfg)
if ra_dir:
found.append(("retroarch", ra_dir))
# RetroArch native: the config under its base folder, then
# ~/.retroarch.cfg when that one is missing (open_default_config_file
# in configuration.c). Either way the system folder defaults to the
# base folder's.
native_base = _unix_retroarch_base()
for native_cfg in (native_base / "retroarch.cfg", home / ".retroarch.cfg"):
ra_dir = _parse_retroarch_system_dir(native_cfg, native_base)
if ra_dir:
found.append(("retroarch", ra_dir))
break
if os_type == "darwin":
# open_default_config_file reads <Application Support>/RetroArch/config
+1 -1
View File
@@ -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="34fd006cc0456c61b9a621e52f35cee6d3fd55ff14bbc6cea207ddc7bc57d858"
DEFAULT_INSTALL_SHA256="f48287847612b616bcaf607bd50207353bef5648e650a732c2d9595a64726ab0"
MAX_INSTALLER_BYTES=2097152
cleanup() {
+8 -8
View File
@@ -27,8 +27,8 @@
{
"dest": "roms/ports/retrobios/install.py",
"repo_path": "install.py",
"size": 1103111,
"sha256": "34fd006cc0456c61b9a621e52f35cee6d3fd55ff14bbc6cea207ddc7bc57d858",
"size": 1103894,
"sha256": "f48287847612b616bcaf607bd50207353bef5648e650a732c2d9595a64726ab0",
"executable": false
},
{
@@ -71,8 +71,8 @@
"muos": {
"archive": {
"dest": "ARCHIVE/RetroBIOS.muxapp",
"size": 1156738,
"sha256": "35c0920008baadca997d0f778e99ce46d702bbe3d3f0d33104d7158422b292aa"
"size": 1157521,
"sha256": "0f9b070334a530a0ed5a6b6b773928d92f5a08aa0d0af18fde7b6cb4a16e731d"
},
"members": [
{
@@ -92,8 +92,8 @@
{
"name": "RetroBIOS/install.py",
"repo_path": "install.py",
"size": 1103111,
"sha256": "34fd006cc0456c61b9a621e52f35cee6d3fd55ff14bbc6cea207ddc7bc57d858",
"size": 1103894,
"sha256": "f48287847612b616bcaf607bd50207353bef5648e650a732c2d9595a64726ab0",
"executable": false
},
{
@@ -166,8 +166,8 @@
{
"dest": ".config/modules/retrobios/install.py",
"repo_path": "install.py",
"size": 1103111,
"sha256": "34fd006cc0456c61b9a621e52f35cee6d3fd55ff14bbc6cea207ddc7bc57d858",
"size": 1103894,
"sha256": "f48287847612b616bcaf607bd50207353bef5648e650a732c2d9595a64726ab0",
"executable": false
},
{
+12
View File
@@ -21,12 +21,24 @@
"config": "$HOME/snap/retroarch/current/.config/retroarch/retroarch.cfg",
"parse_key": "system_directory"
},
{
"os": "linux",
"method": "config_file",
"config": "$XDG_CONFIG_HOME/retroarch/retroarch.cfg",
"parse_key": "system_directory"
},
{
"os": "linux",
"method": "config_file",
"config": "$HOME/.config/retroarch/retroarch.cfg",
"parse_key": "system_directory"
},
{
"os": "linux",
"method": "config_file",
"config": "$HOME/.retroarch.cfg",
"parse_key": "system_directory"
},
{
"os": "darwin",
"method": "config_file",
+13
View File
@@ -219,10 +219,23 @@ platforms:
method: config_file
config: $HOME/snap/retroarch/current/.config/retroarch/retroarch.cfg
parse_key: system_directory
# Native: $XDG_CONFIG_HOME/retroarch when the variable is set, else
# $HOME/.config/retroarch, then $HOME/.retroarch.cfg when that file is
# missing (file_path_special.c fill_pathname_application_data,
# configuration.c open_default_config_file). A value left at default
# is the system folder of the first of the two folders.
- os: linux
method: config_file
config: $XDG_CONFIG_HOME/retroarch/retroarch.cfg
parse_key: system_directory
- os: linux
method: config_file
config: $HOME/.config/retroarch/retroarch.cfg
parse_key: system_directory
- os: linux
method: config_file
config: $HOME/.retroarch.cfg
parse_key: system_directory
# configuration.c reads <Application Support>/RetroArch/config, and a value
# left at default is ~/Documents/RetroArch/system (platform_darwin.m).
# Older builds kept the file one level up.
+46
View File
@@ -2646,6 +2646,52 @@ class RetroArchWhereItReallyLives(unittest.TestCase):
self.assertIn(("retroarch", support / "system"), found)
class LinuxRetroArchFollowsXdgConfigHome(unittest.TestCase):
"""RetroArch on Linux keeps its config under $XDG_CONFIG_HOME/retroarch
when the variable is set, then falls back to ~/.retroarch.cfg
(file_path_special.c fill_pathname_application_data, configuration.c
open_default_config_file). Only ~/.config/retroarch was read: a home
with its own XDG layout detected nothing."""
def _env(self) -> tuple[Path, Path]:
home = Path(_tempdir(self))
xdg = Path(_tempdir(self))
patcher = unittest.mock.patch.dict(os.environ, {"HOME": str(home)}, clear=True)
patcher.start()
self.addCleanup(patcher.stop)
return home, xdg
def test_the_config_under_xdg_config_home_is_read(self):
home, xdg = self._env()
(xdg / "retroarch").mkdir()
(xdg / "retroarch" / "retroarch.cfg").write_text('system_directory = "/srv/bios"\n')
# A config under ~/.config is not the one this RetroArch opens.
(home / ".config" / "retroarch").mkdir(parents=True)
(home / ".config" / "retroarch" / "retroarch.cfg").write_text(
'system_directory = "/elsewhere"\n')
os.environ["XDG_CONFIG_HOME"] = str(xdg)
found = install.detect_platforms("linux")
self.assertIn(("retroarch", Path("/srv/bios")), found)
self.assertNotIn(("retroarch", Path("/elsewhere")), found)
self.assertEqual(install._os_default_dests("linux")["retroarch"],
xdg / "retroarch" / "system")
def test_home_retroarch_cfg_is_the_fallback(self):
home, xdg = self._env()
os.environ["XDG_CONFIG_HOME"] = str(xdg)
(home / ".retroarch.cfg").write_text('system_directory = "default"\n')
found = install.detect_platforms("linux")
self.assertIn(("retroarch", xdg / "retroarch" / "system"), found)
def test_without_the_variable_the_folder_is_under_dot_config(self):
home, _ = self._env()
(home / ".config" / "retroarch").mkdir(parents=True)
(home / ".config" / "retroarch" / "retroarch.cfg").write_text(
'system_directory = "default"\n')
found = install.detect_platforms("linux")
self.assertIn(("retroarch", home / ".config" / "retroarch" / "system"), found)
class NoPythonNamesThisSystemsCommand(unittest.TestCase):
"""Without Python the bootstrap said `sudo apt install python3` on every
system: Termux has no sudo and installs with `pkg install python`, and