diff --git a/install.ps1 b/install.ps1 index 2a57af8b..7a980f89 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 = "dc6b428278a4352923c19ddcf055fd994aac1df77f35cb1d097e8f4c5d887ae1" +$defaultInstallSha256 = "973e116ab59e233cd4fe5ebb77d4973bc06013b22b6388e80d12fa1d61fb0c73" $maximumInstallerBytes = 2MB $installerExit = 0 $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } diff --git a/install.py b/install.py index 7dacd8aa..091af425 100644 --- a/install.py +++ b/install.py @@ -175,7 +175,6 @@ def _os_default_dests(os_type: str) -> dict[str, Path]: home = Path.home() if os_type == "windows": profile = Path(os.environ.get("USERPROFILE", str(home))) - appdata = Path(os.environ.get("APPDATA", str(home / "AppData" / "Roaming"))) return { # RetroArch's system directory defaults to \system # (platform_win32.c), and its installer to C:\RetroArch-Win64. @@ -904,11 +903,11 @@ def _rule_path(template: str) -> Path: 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,) - for rule_os, platform, path, bios in _PATH_RULES: - if rule_os not in systems or any(name == platform for name, _ in found): + for rule_os, platform_name, path, bios in _PATH_RULES: + if rule_os not in systems or any(name == platform_name for name, _ in found): continue if _rule_path(path).exists(): - found.append((platform, _rule_path(bios or path))) + found.append((platform_name, _rule_path(bios or path))) def detect_platforms(os_type: str) -> list[tuple[str, Path]]: diff --git a/install.sh b/install.sh index 097e4551..18daa8a3 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="dc6b428278a4352923c19ddcf055fd994aac1df77f35cb1d097e8f4c5d887ae1" +DEFAULT_INSTALL_SHA256="973e116ab59e233cd4fe5ebb77d4973bc06013b22b6388e80d12fa1d61fb0c73" MAX_INSTALLER_BYTES=2097152 cleanup() { diff --git a/tests/test_install.py b/tests/test_install.py index f5caf519..0f272cba 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -1151,6 +1151,52 @@ class InstallerStaysOnPython38AndTheStdlib(unittest.TestCase): self.assertEqual(used, []) + def test_no_local_is_assigned_and_never_read(self): + """ruff --select F in py38 mode is the installer's lint gate; an + unread `appdata` in _os_default_dests made it exit 1. The suite has + no ruff, so the rule is read from the syntax tree.""" + import ast # noqa: PLC0415 + + tree = ast.parse((Path(__file__).resolve().parents[1] / "install.py").read_text()) + unread = [] + for func in ast.walk(tree): + if not isinstance(func, (ast.FunctionDef, ast.AsyncFunctionDef)): + continue + stored, loaded = {}, set() + for node in ast.walk(func): + if isinstance(node, ast.Name): + if isinstance(node.ctx, ast.Store): + stored.setdefault(node.id, node.lineno) + else: + loaded.add(node.id) + nested = { + n.id for inner in ast.walk(func) if inner is not func + and isinstance(inner, (ast.FunctionDef, ast.Lambda)) + for n in ast.walk(inner) if isinstance(n, ast.Name) + } + unread += [ + f"{func.name}:{line} {name}" for name, line in stored.items() + if name not in loaded | nested and not name.startswith("_") + and not any( + isinstance(g, (ast.Global, ast.Nonlocal)) and name in g.names + for g in ast.walk(func) + ) + ] + self.assertEqual(unread, []) + # Nor a module rebound: a loop variable named `platform` shadowed the + # platform module in _detect_by_path (F402). + modules = { + alias.asname or alias.name.split(".")[0] + for node in tree.body if isinstance(node, ast.Import) + for alias in node.names + } + rebound = sorted( + f"{node.id}:{node.lineno}" for node in ast.walk(tree) + if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Store) + and node.id in modules + ) + self.assertEqual(rebound, []) + class ARefusedCopyIsAnError(unittest.TestCase): """A PermissionError on a standalone copy was counted as "dir not found" and the run ended on Done with exit code 0."""