mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-20 18:59:07 -05:00
fix: reach the Windows side from WSL
Windows rules ran under WSL with C:\ paths read as relative and no Windows variables, so nothing was found and a forced RetroBat install went to ~/bios inside the distribution.
This commit is contained in:
1 parent
16f8b87ef4
commit
7e71f06c57
5 files changed
+100
-7
No files matched your search
+1
-1
@@ -8,7 +8,7 @@ param(
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "d86244b95c49d37d3950e0547fe13fa6df589dc21ba9868d46da4ab305522b3f"
|
||||
$defaultInstallSha256 = "142edea98e646ed11e27052d3dd02125a27d4cdb7ee04392e6af8fcd28f9762f"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+51
-5
@@ -26,6 +26,7 @@ import platform
|
||||
import re
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
@@ -181,9 +182,16 @@ def _os_default_dests(os_type: str) -> dict[str, Path]:
|
||||
return {
|
||||
# RetroArch's system directory defaults to <exe folder>\system
|
||||
# (platform_win32.c), and its installer to C:\RetroArch-Win64.
|
||||
"retroarch": Path("C:/RetroArch-Win64/system"),
|
||||
"retroarch": _host_path("C:/RetroArch-Win64/system"),
|
||||
# RetroBat's installer defaults to C:\RetroBat (installer.iss).
|
||||
"retrobat": Path("C:/RetroBat/bios"),
|
||||
"retrobat": _host_path("C:/RetroBat/bios"),
|
||||
}
|
||||
if os_type == "wsl":
|
||||
# RetroArch may be the Linux one inside the distribution; RetroBat
|
||||
# only exists on the Windows side, reached through /mnt/c.
|
||||
return {
|
||||
"retroarch": home / ".config" / "retroarch" / "system",
|
||||
"retrobat": _host_path("C:/RetroBat/bios"),
|
||||
}
|
||||
if os_type == "darwin":
|
||||
return {"retroarch": _macos_retroarch_base() / "system"}
|
||||
@@ -435,6 +443,42 @@ def _parse_os_release() -> dict[str, str]:
|
||||
return result
|
||||
|
||||
|
||||
# Set under WSL: a Windows path read from a config or a rule names a drive
|
||||
# that Linux sees under /mnt (drvfs). C:\\RetroBat\\bios was used as a relative
|
||||
# path and nothing Windows-side was ever found from WSL.
|
||||
_WSL = {"active": False, "root": "/mnt"}
|
||||
_WINDOWS_VARIABLES = ("USERPROFILE", "APPDATA", "LOCALAPPDATA", "ProgramFiles", "ProgramFiles(x86)")
|
||||
|
||||
|
||||
def _host_path(text: str) -> Path:
|
||||
"""A path as this machine opens it: under WSL, C:\\X is /mnt/c/X."""
|
||||
match = re.match(r"^([A-Za-z]):(?:[\\/]+(.*))?$", text) if _WSL["active"] else None
|
||||
if match:
|
||||
rest = [part for part in re.split(r"[\\/]", match.group(2) or "") if part]
|
||||
return Path(_WSL["root"], match.group(1).lower(), *rest)
|
||||
return Path(text)
|
||||
|
||||
|
||||
def _enter_wsl() -> None:
|
||||
"""Read Windows paths through drvfs, and the Windows variables detection
|
||||
needs, which WSL does not pass to Linux (only those named in WSLENV)."""
|
||||
_WSL["active"] = True
|
||||
for variable in _WINDOWS_VARIABLES:
|
||||
if os.environ.get(variable):
|
||||
continue
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["cmd.exe", "/c", f"echo %{variable}%"],
|
||||
capture_output=True, text=True, timeout=10,
|
||||
cwd="/mnt/c" if Path("/mnt/c").is_dir() else None,
|
||||
)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
return
|
||||
value = result.stdout.strip()
|
||||
if value and not value.startswith("%"):
|
||||
os.environ[variable] = str(_host_path(value))
|
||||
|
||||
|
||||
def _expand_retroarch_path(value: str, app_dir: Path) -> Path:
|
||||
"""Expand the notations RetroArch writes into its config values.
|
||||
|
||||
@@ -446,7 +490,7 @@ def _expand_retroarch_path(value: str, app_dir: Path) -> Path:
|
||||
return Path(str(Path.home())) / value[2:]
|
||||
if value[:1] == ":":
|
||||
return app_dir / value[2:]
|
||||
return Path(os.path.expandvars(os.path.expanduser(value)))
|
||||
return _host_path(os.path.expandvars(os.path.expanduser(value)))
|
||||
|
||||
|
||||
def _retroarch_cfg_dir(
|
||||
@@ -506,7 +550,7 @@ def _windows_retroarch_dirs() -> list[Path]:
|
||||
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")]
|
||||
candidates = [_host_path("C:/RetroArch-Win64"), _host_path("C:/RetroArch")]
|
||||
for var in ("ProgramFiles", "ProgramFiles(x86)"):
|
||||
root = os.environ.get(var, "")
|
||||
if root:
|
||||
@@ -960,7 +1004,7 @@ def _rule_path(template: str) -> Path:
|
||||
if template.startswith(variable):
|
||||
rest = [part for part in re.split(r"[\\/]", template[len(variable):]) if part]
|
||||
return base.joinpath(*rest)
|
||||
return Path(template)
|
||||
return _host_path(template)
|
||||
|
||||
|
||||
# The registry's executable rules: (os, platform, glob under $HOME or
|
||||
@@ -3501,6 +3545,8 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
print(f"{term.bold('RetroBIOS')} {term.dim(installer_id())}\n")
|
||||
|
||||
os_type = detect_os()
|
||||
if os_type == "wsl":
|
||||
_enter_wsl()
|
||||
|
||||
# Early exit for listing
|
||||
if args.list_platforms:
|
||||
|
||||
+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="d86244b95c49d37d3950e0547fe13fa6df589dc21ba9868d46da4ab305522b3f"
|
||||
DEFAULT_INSTALL_SHA256="142edea98e646ed11e27052d3dd02125a27d4cdb7ee04392e6af8fcd28f9762f"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -2786,5 +2786,45 @@ class APartialIsClosedBeforeItIsDeleted(unittest.TestCase):
|
||||
self.assertLess(branch.index("partial.close()"), branch.index("tmp_path.unlink()"))
|
||||
|
||||
|
||||
class WindowsSeenFromWsl(unittest.TestCase):
|
||||
"""Under WSL, C:\\RetroBat\\bios was a relative path, %APPDATA% and
|
||||
%USERPROFILE% were unset, and --platform retrobat wrote 7 753 files into
|
||||
~/bios inside the distribution, where RetroBat reads nothing."""
|
||||
|
||||
def setUp(self):
|
||||
self.root = Path(_tempdir(self))
|
||||
patcher = unittest.mock.patch.dict(install._WSL, {"active": True, "root": str(self.root)})
|
||||
patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
def test_a_drive_path_is_its_mount(self):
|
||||
self.assertEqual(install._host_path("C:\\RetroBat\\bios"), self.root / "c" / "RetroBat" / "bios")
|
||||
self.assertEqual(install._rule_path("C:\\RetroBat\\bios"), self.root / "c" / "RetroBat" / "bios")
|
||||
self.assertEqual(install._default_dest("wsl", "retrobat"), self.root / "c" / "RetroBat" / "bios")
|
||||
self.assertEqual(install._host_path("relative/path"), Path("relative/path"))
|
||||
|
||||
def test_retrobat_on_the_windows_side_is_detected(self):
|
||||
(self.root / "c" / "RetroBat" / "bios").mkdir(parents=True)
|
||||
found: list = []
|
||||
install._detect_by_path("wsl", found)
|
||||
self.assertIn(("retrobat", self.root / "c" / "RetroBat" / "bios"), found)
|
||||
|
||||
def test_the_windows_variables_are_read_through_cmd(self):
|
||||
answers = {"USERPROFILE": "C:\\Users\\me", "APPDATA": "C:\\Users\\me\\AppData\\Roaming"}
|
||||
|
||||
def cmd(argv, **_kwargs):
|
||||
name = argv[-1].split("%")[1]
|
||||
return subprocess.CompletedProcess(argv, 0, answers.get(name, f"%{name}%") + "\r\n", "")
|
||||
|
||||
cleared = {name: "" for name in install._WINDOWS_VARIABLES}
|
||||
with unittest.mock.patch.dict(os.environ, cleared), \
|
||||
unittest.mock.patch.object(install.subprocess, "run", cmd):
|
||||
install._enter_wsl()
|
||||
self.assertEqual(os.environ["USERPROFILE"], str(self.root / "c" / "Users" / "me"))
|
||||
self.assertEqual(os.environ["APPDATA"],
|
||||
str(self.root / "c" / "Users" / "me" / "AppData" / "Roaming"))
|
||||
self.assertEqual(os.environ["ProgramFiles"], "")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -291,6 +291,13 @@ not already found that way.
|
||||
Desktop installs are read from their own configuration, and several can be
|
||||
found on one machine.
|
||||
|
||||
Under WSL both sides are searched. The Windows one is reached through its
|
||||
`/mnt/<drive>` mount: a `C:\` path from a rule or a config becomes
|
||||
`/mnt/c/...`, and the Windows variables the rules use (`USERPROFILE`,
|
||||
`APPDATA`, `LOCALAPPDATA`, `ProgramFiles`) are read through `cmd.exe` when
|
||||
WSL does not pass them. A forced `--platform retrobat` falls back to
|
||||
`/mnt/c/RetroBat/bios`.
|
||||
|
||||
| Evidence | Platform | BIOS directory |
|
||||
|----------|----------|----------------|
|
||||
| `~/.config/EmuDeck/settings.sh` | EmuDeck | `emulationPath` + `/bios` |
|
||||
|
||||
Reference in new issue
Block a user