From c5ceb71af65ebb033c571b62663527e5a63a6e99 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:19:26 -0700 Subject: [PATCH 01/26] umu_consts: add XDG_DATA_HOME --- umu/umu_consts.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/umu/umu_consts.py b/umu/umu_consts.py index 9f5919508..8940672c7 100644 --- a/umu/umu_consts.py +++ b/umu/umu_consts.py @@ -35,6 +35,8 @@ class Color(Enum): "getnativepath", } +XDG_DATA_HOME = environ.get("XDG_DATA_HOME") + FLATPAK_ID = environ.get("FLATPAK_ID") or "" FLATPAK_PATH: Path = ( From 89ef820c9c8fb1ea9d697b73da19a9721f898976 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:21:20 -0700 Subject: [PATCH 02/26] umu_consts: fix type --- umu/umu_consts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/umu/umu_consts.py b/umu/umu_consts.py index 8940672c7..d3756e066 100644 --- a/umu/umu_consts.py +++ b/umu/umu_consts.py @@ -39,8 +39,8 @@ class Color(Enum): FLATPAK_ID = environ.get("FLATPAK_ID") or "" -FLATPAK_PATH: Path = ( - Path(environ.get("XDG_DATA_HOME"), "umu") if FLATPAK_ID else None +FLATPAK_PATH: Path | None = ( + Path(XDG_DATA_HOME, "umu") if FLATPAK_ID and XDG_DATA_HOME else None ) UMU_LOCAL: Path = FLATPAK_PATH or Path.home().joinpath( From 2b6fbcc04012e2c48efc5593d656300c34326d0e Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:21:30 -0700 Subject: [PATCH 03/26] umu_plugins: fix type --- umu/umu_plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umu/umu_plugins.py b/umu/umu_plugins.py index 600fbe259..0b608ae8f 100644 --- a/umu/umu_plugins.py +++ b/umu/umu_plugins.py @@ -5,7 +5,7 @@ def set_env_toml( env: dict[str, str], args: Namespace -) -> tuple[dict[str, str], list[str, tuple[str, Path]]]: +) -> tuple[dict[str, str], list[str]]: """Read key/values in a TOML file and map them to umu env. variables. In the TOML file, certain keys map to environment variables: From 277abf146fb31a51612f6b52c8cec68032f40337 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:33:44 -0700 Subject: [PATCH 04/26] umu_plugins: fix types --- umu/umu_plugins.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/umu/umu_plugins.py b/umu/umu_plugins.py index 0b608ae8f..0b61575f8 100644 --- a/umu/umu_plugins.py +++ b/umu/umu_plugins.py @@ -27,32 +27,40 @@ def set_env_toml( raise ModuleNotFoundError(err) # User configuration containing required key/value pairs - toml: dict[str, Any] = None + toml: dict[str, Any] + # Configuration file path + config_path: Path # Name of the configuration file - config: Path = Path(getattr(args, "config", None)).expanduser() + config: str = getattr(args, "config", "") # Executable options, if any opts: list[str] = [] - if not config.is_file(): + if not config: + err: str = f"Property 'config' does not exist in type '{type(args)}'" + raise AttributeError(err) + + config_path = Path(config).expanduser() + + if not config_path.is_file(): err: str = f"Path to configuration is not a file: '{config}'" raise FileNotFoundError(err) - with config.open(mode="rb") as file: + with config_path.open(mode="rb") as file: toml = tomllib.load(file) _check_env_toml(toml) # Required environment variables - env["WINEPREFIX"] = toml.get("umu").get("prefix") - env["PROTONPATH"] = toml.get("umu").get("proton") - env["EXE"] = toml.get("umu").get("exe") + env["WINEPREFIX"] = toml["umu"]["prefix"] + env["PROTONPATH"] = toml["umu"]["proton"] + env["EXE"] = toml["umu"]["exe"] # Optional - env["GAMEID"] = toml.get("umu").get("game_id", "") - env["STORE"] = toml.get("umu").get("store", "") + env["GAMEID"] = toml["umu"].get("game_id", "") + env["STORE"] = toml["umu"].get("store", "") - if isinstance(toml.get("umu").get("launch_args"), list): + if isinstance(toml["umu"].get("launch_args"), list): opts = toml["umu"]["launch_args"] - elif isinstance(toml.get("umu").get("launch_args"), str): + elif isinstance(toml["umu"].get("launch_args"), str): opts = toml["umu"]["launch_args"].split(" ") return env, opts @@ -73,7 +81,7 @@ def _check_env_toml(toml: dict[str, Any]) -> dict[str, Any]: raise ValueError(err) for key in required_keys: - path: Path = None + path: Path if key not in toml[table]: err: str = ( @@ -102,7 +110,7 @@ def _check_env_toml(toml: dict[str, Any]) -> dict[str, Any]: raise NotADirectoryError(err) # Raise an error for empty values - for key, val in toml.get(table).items(): + for key, val in toml[table].items(): if not val and isinstance(val, str): err: str = ( f"Value is empty for '{key}'.\n" From bc5cb7cdb75694683da9842c6408a05171090852 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:39:31 -0700 Subject: [PATCH 05/26] umu_log: fix type --- umu/umu_log.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/umu/umu_log.py b/umu/umu_log.py index 86c41195a..8dc3b1b76 100644 --- a/umu/umu_log.py +++ b/umu/umu_log.py @@ -10,6 +10,7 @@ getLogger, ) from sys import stderr +from typing import TextIO from umu_consts import SIMPLE_FORMAT, Color @@ -46,6 +47,6 @@ def format(self, record: LogRecord) -> str: # noqa: D102 log: CustomLogger = CustomLogger(getLogger(__name__)) -console_handler: StreamHandler = StreamHandler(stream=stderr) +console_handler: StreamHandler[TextIO] = StreamHandler(stream=stderr) console_handler.setFormatter(CustomFormatter()) log.addHandler(console_handler) From d61a4c536d2536be244c6f6b8ce038c847aa4d01 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:43:36 -0700 Subject: [PATCH 06/26] umu_util: fix types --- umu/umu_util.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/umu/umu_util.py b/umu/umu_util.py index 01493c575..0361b857d 100644 --- a/umu/umu_util.py +++ b/umu/umu_util.py @@ -19,8 +19,8 @@ def run_zenity(command: str, opts: list[str], msg: str) -> int: Intended to be used for long running operations (e.g. large file downloads) """ - bin: str = which("zenity") - cmd: str = which(command) + bin: str = which("zenity") or "" + cmd: str = which(command) or "" ret: int = 0 # Exit code returned from zenity if not bin: @@ -56,7 +56,10 @@ def run_zenity(command: str, opts: list[str], msg: str) -> int: zenity_proc.terminate() log.warning("%s timed out after 5 min.", cmd) raise TimeoutError - zenity_proc.stdin.close() + + if zenity_proc.stdin: + zenity_proc.stdin.close() + ret = zenity_proc.wait() if ret: @@ -70,9 +73,9 @@ def is_installed_verb(verb: list[str], pfx: Path) -> bool: Determines the installation of verbs by reading winetricks.log file. """ - wt_log: Path = None + wt_log: Path + verbs: set[str] is_installed: bool = False - verbs: set[str] = {} if not pfx: err: str = f"Value is '{pfx}' for WINE prefix" @@ -106,7 +109,7 @@ def is_winetricks_verb( verbs: list[str], pattern: str = r"^[a-zA-Z_0-9]+(=[a-zA-Z0-9]*)?$" ) -> bool: """Check if a string is a winetricks verb.""" - regex: Pattern = None + regex: Pattern if not verbs: return False From bcc393855a98f0f7280ef484f4df6a5b0de4a568 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:54:32 -0700 Subject: [PATCH 07/26] umu_runtime: fix types --- umu/umu_runtime.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py index 719881e9e..b6d36fb5b 100644 --- a/umu/umu_runtime.py +++ b/umu/umu_runtime.py @@ -9,7 +9,6 @@ from ssl import create_default_context from subprocess import run from sys import version -from tarfile import TarInfo from tarfile import open as taropen from tempfile import mkdtemp from typing import Any @@ -25,8 +24,10 @@ try: from tarfile import tar_filter + + has_data_filter: bool = True except ImportError: - tar_filter: Callable[[str, str], TarInfo] = None + has_data_filter: bool = False def _install_umu( @@ -42,6 +43,7 @@ def _install_umu( f"https://repo.steampowered.com/steamrt-images-{codename}" "/snapshots/latest-container-runtime-public-beta" ) + resp: HTTPResponse log.debug("Codename: %s", codename) log.debug("URL: %s", base_url) @@ -71,7 +73,6 @@ def _install_umu( f"/steamrt-images-{codename}" "/snapshots/latest-container-runtime-public-beta" ) - resp: HTTPResponse = None hash = sha256() # Get the digest for the runtime archive @@ -126,7 +127,7 @@ def _install_umu( ): futures: list[Future] = [] - if tar_filter: + if has_data_filter: log.debug("Using filter for archive") tar.extraction_filter = tar_filter else: @@ -198,13 +199,13 @@ def _update_umu( The runtime platform will be updated to the latest public beta by comparing the local VERSIONS.txt against the remote one. """ + runtime: Path + resp: HTTPResponse codename: str = json["umu"]["versions"]["runtime_platform"] endpoint: str = ( f"/steamrt-images-{codename}" "/snapshots/latest-container-runtime-public-beta" ) - runtime: Path = None - resp: HTTPResponse = None log.debug("Existing install detected") # Find the runtime directory (e.g., sniper_platform_0.20240530.90143) @@ -262,7 +263,7 @@ def _update_umu( # Handle the redirect if resp.status == 301: - location: str = resp.getheader("Location") + location: str = resp.getheader("Location", "") log.debug("Location: %s", resp.getheader("Location")) # The stdlib requires reading the entire response body before # making another request @@ -314,7 +315,7 @@ def _get_json(path: Path, config: str) -> dict[str, Any]: the tools currently used by launcher. The key/value pairs umu and versions must exist. """ - json: dict[str, Any] = None + json: dict[str, Any] # Steam Runtime platform values # See https://gitlab.steamos.cloud/steamrt/steamrt/-/wikis/home steamrts: set[str] = { @@ -336,7 +337,7 @@ def _get_json(path: Path, config: str) -> dict[str, Any]: json = load(file) # Raise an error if "umu" and "versions" doesn't exist - if not json or not json.get("umu") or not json.get("umu").get("versions"): + if not json or "umu" not in json or "versions" not in json["umu"]: err: str = ( f"Failed to load {config} or 'umu' or 'versions' not in: {config}" ) @@ -344,7 +345,7 @@ def _get_json(path: Path, config: str) -> dict[str, Any]: # The launcher will use the value runtime_platform to glob files. Attempt # to guard against directory removal attacks for non-system wide installs - if json.get("umu").get("versions").get("runtime_platform") not in steamrts: + if json["umu"]["versions"]["runtime_platform"] not in steamrts: err: str = "Value for 'runtime_platform' is not a steamrt" raise ValueError(err) @@ -377,10 +378,10 @@ def check_runtime(src: Path, json: dict[str, Any]) -> int: validate the integrity of the runtime's metadata after its moved to the home directory and used to run games. """ + runtime: Path codename: str = json["umu"]["versions"]["runtime_platform"] pv_verify: Path = src.joinpath("pressure-vessel", "bin", "pv-verify") ret: int = 1 - runtime: Path = None # Find the runtime directory try: From 1a68f7bdc4d76169f6da7f5b1473a598fccb6f41 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:56:01 -0700 Subject: [PATCH 08/26] umu_proton: fix types --- umu/umu_proton.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/umu/umu_proton.py b/umu/umu_proton.py index d494bb458..ef6859f8f 100644 --- a/umu/umu_proton.py +++ b/umu/umu_proton.py @@ -1,4 +1,3 @@ -from collections.abc import Callable from concurrent.futures import Future, ThreadPoolExecutor from hashlib import sha512 from http.client import HTTPException @@ -8,10 +7,10 @@ from shutil import rmtree from ssl import SSLContext, create_default_context from sys import version -from tarfile import TarInfo from tarfile import open as tar_open from tempfile import mkdtemp -from urllib.request import Request, URLError, urlopen +from urllib.error import URLError +from urllib.request import Request, urlopen from umu_consts import STEAM_COMPAT from umu_log import log @@ -21,8 +20,10 @@ try: from tarfile import tar_filter + + has_data_filter: bool = True except ImportError: - tar_filter: Callable[[str, str], TarInfo] = None + has_data_filter: bool = False def get_umu_proton( @@ -191,7 +192,7 @@ def _fetch_proton( tar_url, context=SSL_DEFAULT_CONTEXT ) as resp, ): - hash = sha512() + hashsum = sha512() # Crash here because without Proton, the launcher will not work if resp.status != 200: @@ -207,9 +208,9 @@ def _fetch_proton( view: memoryview = memoryview(buffer) while size := resp.readinto(buffer): file.write(view[:size]) - hash.update(view[:size]) + hashsum.update(view[:size]) - if hash.hexdigest() != digest: + if hashsum.hexdigest() != digest: err: str = f"Digest mismatched: {tarball}" raise ValueError(err) @@ -221,7 +222,7 @@ def _fetch_proton( def _extract_dir(file: Path, steam_compat: Path) -> None: """Extract from a path to another location.""" with tar_open(file, "r:gz") as tar: - if tar_filter: + if has_data_filter: log.debug("Using filter for archive") tar.extraction_filter = tar_filter else: @@ -389,11 +390,11 @@ def _update_proton( if not protons: return - for proton in protons: - if proton.is_dir(): + for stable in protons: + if stable.is_dir(): log.debug("Previous stable build found") - log.debug("Removing: %s", proton) - futures.append(thread_pool.submit(rmtree, str(proton))) + log.debug("Removing: %s", stable) + futures.append(thread_pool.submit(rmtree, str(stable))) for _ in futures: _.result() From 96e4af2aa5494e950564b8ffdb4fe70f4ec7451d Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:14:11 -0700 Subject: [PATCH 09/26] umu_run: fix types --- umu/umu_run.py | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index a3d127f0d..1ad4ab0d1 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -2,8 +2,8 @@ import os import sys +from _ctypes import CFuncPtr from argparse import ArgumentParser, Namespace, RawTextHelpFormatter -from collections.abc import Callable from concurrent.futures import Future, ThreadPoolExecutor from ctypes import CDLL, c_int, c_ulong from errno import ENETUNREACH @@ -142,7 +142,7 @@ def setup_pfx(path: str) -> None: log.debug("User home directory is link: %s", wineuser.is_symlink()) -def check_env(env: set[str, str]) -> dict[str, str] | dict[str, Any]: +def check_env(env: dict[str, str]) -> dict[str, str] | dict[str, Any]: """Before executing a game, check for environment variables and set them. GAMEID is strictly required and the client is responsible for setting this. @@ -171,7 +171,7 @@ def check_env(env: set[str, str]) -> dict[str, str] | dict[str, Any]: # Proton Version if ( os.environ.get("PROTONPATH") - and Path(STEAM_COMPAT, os.environ.get("PROTONPATH")).is_dir() + and Path(STEAM_COMPAT, os.environ["PROTONPATH"]).is_dir() ): log.debug("Proton version selected") os.environ["PROTONPATH"] = str( @@ -215,10 +215,10 @@ def set_env( # Command execution usage, but client wants to create a prefix. When an # empty string is the executable, Proton is expected to create the prefix # but will fail because the executable is not found - is_createpfx: bool = is_cmd and isinstance(args[0], str) and not args[0] + is_createpfx: bool = is_cmd and not args[0] # type: ignore # Command execution usage, but client wants to run winetricks verbs - is_winetricks: bool = is_cmd and args[0] == "winetricks" + is_winetricks: bool = is_cmd and args[0] == "winetricks" # type: ignore # PROTON_VERB # For invalid Proton verbs, just assign the waitforexitandrun @@ -240,19 +240,19 @@ def set_env( strict=True ) env["EXE"] = str(exe) - args = (env["EXE"], args[1]) + args = (env["EXE"], args[1]) # type: ignore env["STEAM_COMPAT_INSTALL_PATH"] = str(exe.parent) elif is_cmd: try: # Ensure executable path is absolute, otherwise Proton will fail # when creating the subprocess. # e.g., Games/umu/umu-0 -> $HOME/Games/umu/umu-0 - exe: Path = Path(args[0]).expanduser().resolve(strict=True) + exe: Path = Path(args[0]).expanduser().resolve(strict=True) # type: ignore env["EXE"] = str(exe) env["STEAM_COMPAT_INSTALL_PATH"] = str(exe.parent) except FileNotFoundError: # Assume that the executable will be inside prefix or container - env["EXE"] = args[0] + env["EXE"] = args[0] # type: ignore env["STEAM_COMPAT_INSTALL_PATH"] = "" log.warning("Executable not found: %s", env["EXE"]) else: # Configuration file usage @@ -291,7 +291,7 @@ def set_env( enable_steam_game_drive(env) # Winetricks - if env.get("EXE").endswith("winetricks"): + if env.get("EXE", "").endswith("winetricks"): # Proton directory with the last segment being subdirectory containing # the Proton libraries and binaries. In upstream Proton 9 the subdir # is 'files', while in other versions it may be 'dist'. @@ -378,9 +378,9 @@ def enable_steam_game_drive(env: dict[str, str]) -> dict[str, str]: # Set the shared library paths of the system after finding libc.so # See https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/-/blob/main/docs/distro-assumptions.md#filesystem-layout - for path in steamrt_paths: - if not Path(path).is_symlink() and Path(path, libc).is_file(): - paths.add(path) + for rtpath in steamrt_paths: + if not Path(rtpath).is_symlink() and Path(rtpath, libc).is_file(): + paths.add(rtpath) env["STEAM_RUNTIME_LIBRARY_PATH"] = ":".join(list(paths)) return env @@ -391,9 +391,9 @@ def build_command( local: Path, command: list[AnyPath], opts: list[str] = [], -) -> list[str]: +) -> list[AnyPath]: """Build the command to be executed.""" - proton: Path = Path(env.get("PROTONPATH"), "proton") + proton: Path = Path(env["PROTONPATH"], "proton") entry_point: Path = local.joinpath("umu") # Will run the game w/o Proton, effectively running the game as is. This @@ -439,7 +439,7 @@ def build_command( raise FileNotFoundError(err) # Configure winetricks to not be prompted for any windows - if env.get("EXE").endswith("winetricks") and opts: + if env.get("EXE", "").endswith("winetricks") and opts: # The position of arguments matter for winetricks # Usage: ./winetricks [options] [command|verb|path-to-verb] ... opts = ["-q", *opts] @@ -464,14 +464,11 @@ def run_command(command: list[AnyPath]) -> int: """Run the executable using Proton within the Steam Runtime.""" # Configure a process via libc prctl() # See prctl(2) for more details - prctl: Callable[ - [c_int, c_ulong, c_ulong, c_ulong, c_ulong], - c_int, - ] = None - proc: Popen = None + prctl: CFuncPtr + cwd: AnyPath + proc: Popen ret: int = 0 libc: str = get_libc() - cwd: AnyPath = "" if not command: err: str = f"Command list is empty or None: {command}" @@ -481,7 +478,7 @@ def run_command(command: list[AnyPath]) -> int: log.warning("Will not set subprocess as subreaper") # For winetricks, change directory to $PROTONPATH/protonfixes - if os.environ.get("EXE").endswith("winetricks"): + if os.environ.get("EXE", "").endswith("winetricks"): cwd = f"{os.environ['PROTONPATH']}/protonfixes" else: cwd = Path.cwd() @@ -519,6 +516,7 @@ def run_command(command: list[AnyPath]) -> int: def main() -> int: # noqa: D103 + future: Future | None = None env: dict[str, str] = { "WINEPREFIX": "", "GAMEID": "", @@ -547,7 +545,6 @@ def main() -> int: # noqa: D103 command: list[AnyPath] = [] opts: list[str] = [] root: Path = Path(__file__).resolve(strict=True).parent - future: Future = None args: Namespace | tuple[str, list[str]] = parse_args() if os.geteuid() == 0: @@ -601,7 +598,7 @@ def main() -> int: # noqa: D103 log.debug("Network is unreachable") # Check environment - if isinstance(args, Namespace) and getattr(args, "config", None): + if isinstance(args, Namespace): env, opts = set_env_toml(env, args) else: opts = args[1] # Reference the executable options From 8bcb2a00ac7e8fcadba10b454a7e9a30174a92ad Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:15:58 -0700 Subject: [PATCH 10/26] Add pyproject.toml - Configuration file for mypy --- umu/pyproject.toml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 umu/pyproject.toml diff --git a/umu/pyproject.toml b/umu/pyproject.toml new file mode 100644 index 000000000..c549b5f85 --- /dev/null +++ b/umu/pyproject.toml @@ -0,0 +1,15 @@ +[tool.mypy] +python_version = "3.10" +warn_return_any = true +ignore_missing_imports = true +# strict = true + +disable_error_code = [ + # Allow redefinitions since we redefine an error variable before raising exceptions + "no-redef" +] + +exclude = [ + '^umu_test\.py$', + '^umu_test_plugins\.py$', +] From 3a948cc6a588dece6858705b1b92e06f23b6f140 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:29:01 -0700 Subject: [PATCH 11/26] workflows: add mypy workflow --- .github/workflows/static.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/static.yml diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml new file mode 100644 index 000000000..b4b1d0b1f --- /dev/null +++ b/.github/workflows/static.yml @@ -0,0 +1,32 @@ +name: mypy + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + build: + strategy: + matrix: + version: ["3.10", "3.11", "3.12"] + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.version }} + - name: Install dependencies + run: | + python3 -m pip install --upgrade pip + - name: Check types with mypy + run: | + pip install mypy + cd umu && mypy . From 793768f108374c761ce7993f2522bcd15b5654f0 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:33:48 -0700 Subject: [PATCH 12/26] Revert "umu_consts: add XDG_DATA_HOME" This reverts commit c5ceb71af65ebb033c571b62663527e5a63a6e99. --- umu/umu_consts.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/umu/umu_consts.py b/umu/umu_consts.py index d3756e066..116febf6c 100644 --- a/umu/umu_consts.py +++ b/umu/umu_consts.py @@ -35,8 +35,6 @@ class Color(Enum): "getnativepath", } -XDG_DATA_HOME = environ.get("XDG_DATA_HOME") - FLATPAK_ID = environ.get("FLATPAK_ID") or "" FLATPAK_PATH: Path | None = ( From 3c4615c48dcffa47712f6e6606abfc5e3c1f0a05 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:35:20 -0700 Subject: [PATCH 13/26] umu_consts: update FLATPAK_PATH - Flatpak guarantees the existence of XDG_DATA_HOME and other XDG environment variables --- umu/umu_consts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umu/umu_consts.py b/umu/umu_consts.py index 116febf6c..16a6fba7f 100644 --- a/umu/umu_consts.py +++ b/umu/umu_consts.py @@ -38,7 +38,7 @@ class Color(Enum): FLATPAK_ID = environ.get("FLATPAK_ID") or "" FLATPAK_PATH: Path | None = ( - Path(XDG_DATA_HOME, "umu") if FLATPAK_ID and XDG_DATA_HOME else None + Path(environ["XDG_DATA_HOME"], "umu") if FLATPAK_ID else None ) UMU_LOCAL: Path = FLATPAK_PATH or Path.home().joinpath( From 09fa7aa0cb0a288ff7ffc8b14df6abbc44e89c9d Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:43:07 -0700 Subject: [PATCH 14/26] Ruff lint --- umu/umu_runtime.py | 1 - 1 file changed, 1 deletion(-) diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py index b6d36fb5b..9b45146f8 100644 --- a/umu/umu_runtime.py +++ b/umu/umu_runtime.py @@ -1,4 +1,3 @@ -from collections.abc import Callable from concurrent.futures import Future, ThreadPoolExecutor from hashlib import sha256 from http.client import HTTPException, HTTPResponse, HTTPSConnection From 4f2039db3550efd0f2906d63af2d99f542ddb947 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:44:28 -0700 Subject: [PATCH 15/26] workflows: update static.yml --- .github/workflows/static.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index b4b1d0b1f..f1365019f 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -13,7 +13,7 @@ jobs: build: strategy: matrix: - version: ["3.10", "3.11", "3.12"] + version: ["3.10"] runs-on: ubuntu-latest From ab7409db20778d170a7811bdc9720a8a5edc6864 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:53:31 -0700 Subject: [PATCH 16/26] umu_log: fix type --- umu/umu_log.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/umu/umu_log.py b/umu/umu_log.py index 8dc3b1b76..86c41195a 100644 --- a/umu/umu_log.py +++ b/umu/umu_log.py @@ -10,7 +10,6 @@ getLogger, ) from sys import stderr -from typing import TextIO from umu_consts import SIMPLE_FORMAT, Color @@ -47,6 +46,6 @@ def format(self, record: LogRecord) -> str: # noqa: D102 log: CustomLogger = CustomLogger(getLogger(__name__)) -console_handler: StreamHandler[TextIO] = StreamHandler(stream=stderr) +console_handler: StreamHandler = StreamHandler(stream=stderr) console_handler.setFormatter(CustomFormatter()) log.addHandler(console_handler) From 7df99c965a747b81769cb0ff5ed6d9a5495c18a6 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:30:30 -0700 Subject: [PATCH 17/26] Update pyproject.toml --- umu/pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/umu/pyproject.toml b/umu/pyproject.toml index c549b5f85..cca86c34c 100644 --- a/umu/pyproject.toml +++ b/umu/pyproject.toml @@ -2,7 +2,6 @@ python_version = "3.10" warn_return_any = true ignore_missing_imports = true -# strict = true disable_error_code = [ # Allow redefinitions since we redefine an error variable before raising exceptions From 71205fe9f668d2bd55b2937a7e4e37de658d1e91 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:30:49 -0700 Subject: [PATCH 18/26] umu_run: update format --- umu/umu_run.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/umu/umu_run.py b/umu/umu_run.py index 1ad4ab0d1..bc080564d 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -158,14 +158,17 @@ def check_env(env: dict[str, str]) -> dict[str, str] | dict[str, Any]: if os.environ.get("WINEPREFIX") == "": err: str = "Environment variable is empty: WINEPREFIX" raise ValueError(err) + if "WINEPREFIX" not in os.environ: pfx: Path = Path.home().joinpath("Games", "umu", env["GAMEID"]) pfx.mkdir(parents=True, exist_ok=True) os.environ["WINEPREFIX"] = str(pfx) + if not Path(os.environ["WINEPREFIX"]).expanduser().is_dir(): pfx: Path = Path(os.environ["WINEPREFIX"]) pfx.mkdir(parents=True, exist_ok=True) os.environ["WINEPREFIX"] = str(pfx) + env["WINEPREFIX"] = os.environ["WINEPREFIX"] # Proton Version @@ -209,6 +212,7 @@ def set_env( protonpath: Path = ( Path(env["PROTONPATH"]).expanduser().resolve(strict=True) ) + # Command execution usage is_cmd: bool = isinstance(args, tuple) @@ -381,6 +385,7 @@ def enable_steam_game_drive(env: dict[str, str]) -> dict[str, str]: for rtpath in steamrt_paths: if not Path(rtpath).is_symlink() and Path(rtpath, libc).is_file(): paths.add(rtpath) + env["STEAM_RUNTIME_LIBRARY_PATH"] = ":".join(list(paths)) return env From 2922f44447cdef92f003bfb930d2c0c81b7ecd71 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:51:27 -0700 Subject: [PATCH 19/26] Fix module imports - Since we've already imported the os and sys modules in our entry point, no need to selectively import functions from them --- umu/umu_consts.py | 6 +++--- umu/umu_log.py | 6 +++--- umu/umu_proton.py | 38 +++++++++++++++++++------------------- umu/umu_runtime.py | 44 ++++++++++++++++++++++---------------------- 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/umu/umu_consts.py b/umu/umu_consts.py index 16a6fba7f..ef3ef7d6e 100644 --- a/umu/umu_consts.py +++ b/umu/umu_consts.py @@ -1,5 +1,5 @@ +import os from enum import Enum -from os import environ from pathlib import Path @@ -35,10 +35,10 @@ class Color(Enum): "getnativepath", } -FLATPAK_ID = environ.get("FLATPAK_ID") or "" +FLATPAK_ID = os.environ.get("FLATPAK_ID") or "" FLATPAK_PATH: Path | None = ( - Path(environ["XDG_DATA_HOME"], "umu") if FLATPAK_ID else None + Path(os.environ["XDG_DATA_HOME"], "umu") if FLATPAK_ID else None ) UMU_LOCAL: Path = FLATPAK_PATH or Path.home().joinpath( diff --git a/umu/umu_log.py b/umu/umu_log.py index 86c41195a..7a1d42c23 100644 --- a/umu/umu_log.py +++ b/umu/umu_log.py @@ -1,3 +1,4 @@ +import sys from logging import ( DEBUG, ERROR, @@ -9,7 +10,6 @@ StreamHandler, getLogger, ) -from sys import stderr from umu_consts import SIMPLE_FORMAT, Color @@ -24,7 +24,7 @@ def console(self, msg: str) -> None: Intended to be used to notify umu setup progress state for command line usage """ - print(f"{Color.BOLD.value}{msg}{Color.RESET.value}", file=stderr) + print(f"{Color.BOLD.value}{msg}{Color.RESET.value}", file=sys.stderr) class CustomFormatter(Formatter): # noqa: D101 @@ -46,6 +46,6 @@ def format(self, record: LogRecord) -> str: # noqa: D102 log: CustomLogger = CustomLogger(getLogger(__name__)) -console_handler: StreamHandler = StreamHandler(stream=stderr) +console_handler: StreamHandler = StreamHandler(stream=sys.stderr) console_handler.setFormatter(CustomFormatter()) log.addHandler(console_handler) diff --git a/umu/umu_proton.py b/umu/umu_proton.py index ef6859f8f..063ab636c 100644 --- a/umu/umu_proton.py +++ b/umu/umu_proton.py @@ -1,12 +1,12 @@ +import os +import sys from concurrent.futures import Future, ThreadPoolExecutor from hashlib import sha512 from http.client import HTTPException from json import loads -from os import environ from pathlib import Path from shutil import rmtree from ssl import SSLContext, create_default_context -from sys import version from tarfile import open as tar_open from tempfile import mkdtemp from urllib.error import URLError @@ -16,7 +16,7 @@ from umu_log import log from umu_util import run_zenity -SSL_DEFAULT_CONTEXT: SSLContext = create_default_context() +ssl_default_context: SSLContext = create_default_context() try: from tarfile import tar_filter @@ -60,7 +60,7 @@ def get_umu_proton( if _get_from_steamcompat(env, STEAM_COMPAT) is env: return env - environ["PROTONPATH"] = "" + os.environ["PROTONPATH"] = "" return env @@ -77,12 +77,12 @@ def _fetch_releases() -> list[tuple[str, str]]: "User-Agent": "", } - if environ.get("PROTONPATH") == "GE-Proton": + if os.environ.get("PROTONPATH") == "GE-Proton": repo = "/repos/GloriousEggroll/proton-ge-custom/releases" with urlopen( # noqa: S310 Request(f"{url}{repo}", headers=headers), # noqa: S310 - context=SSL_DEFAULT_CONTEXT, + context=ssl_default_context, ) as resp: if resp.status != 200: return assets @@ -153,7 +153,7 @@ def _fetch_proton( # See https://github.com/astral-sh/ruff/issues/7918 log.console(f"Downloading {hash}...") with ( - urlopen(hash_url, context=SSL_DEFAULT_CONTEXT) as resp, # noqa: S310 + urlopen(hash_url, context=ssl_default_context) as resp, # noqa: S310 ): if resp.status != 200: err: str = ( @@ -168,7 +168,7 @@ def _fetch_proton( # Proton # Create a popup with zenity when the env var is set - if environ.get("UMU_ZENITY") == "1": + if os.environ.get("UMU_ZENITY") == "1": bin: str = "curl" opts: list[str] = [ "-LJO", @@ -185,11 +185,11 @@ def _fetch_proton( log.warning("zenity exited with the status code: %s", ret) log.console("Retrying from Python...") - if not environ.get("UMU_ZENITY") or ret: + if not os.environ.get("UMU_ZENITY") or ret: log.console(f"Downloading {tarball}...") with ( urlopen( # noqa: S310 - tar_url, context=SSL_DEFAULT_CONTEXT + tar_url, context=ssl_default_context ) as resp, ): hashsum = sha512() @@ -226,7 +226,7 @@ def _extract_dir(file: Path, steam_compat: Path) -> None: log.debug("Using filter for archive") tar.extraction_filter = tar_filter else: - log.warning("Python: %s", version) + log.warning("Python: %s", sys.version) log.warning("Using no data filter for archive") log.warning("Archive will be extracted insecurely") @@ -263,7 +263,7 @@ def _get_from_steamcompat( """ version: str = ( "GE-Proton" - if environ.get("PROTONPATH") == "GE-Proton" + if os.environ.get("PROTONPATH") == "GE-Proton" else "UMU-Proton" ) @@ -275,8 +275,8 @@ def _get_from_steamcompat( ) log.console(f"{latest.name} found in: '{steam_compat}'") log.console(f"Using {latest.name}") - environ["PROTONPATH"] = str(latest) - env["PROTONPATH"] = environ["PROTONPATH"] + os.environ["PROTONPATH"] = str(latest) + env["PROTONPATH"] = os.environ["PROTONPATH"] except ValueError: return None @@ -314,7 +314,7 @@ def _get_latest( proton = tarball.removesuffix(".tar.gz") version = ( "GE-Proton" - if environ.get("PROTONPATH") == "GE-Proton" + if os.environ.get("PROTONPATH") == "GE-Proton" else "UMU-Proton" ) @@ -323,8 +323,8 @@ def _get_latest( log.console(f"{version} is up to date") steam_compat.joinpath("UMU-Latest").unlink(missing_ok=True) steam_compat.joinpath("UMU-Latest").symlink_to(proton) - environ["PROTONPATH"] = str(steam_compat.joinpath(proton)) - env["PROTONPATH"] = environ["PROTONPATH"] + os.environ["PROTONPATH"] = str(steam_compat.joinpath(proton)) + env["PROTONPATH"] = os.environ["PROTONPATH"] return env # Use the latest UMU/GE-Proton @@ -344,8 +344,8 @@ def _get_latest( future.result() else: _extract_dir(tmp.joinpath(tarball), steam_compat) - environ["PROTONPATH"] = str(steam_compat.joinpath(proton)) - env["PROTONPATH"] = environ["PROTONPATH"] + os.environ["PROTONPATH"] = str(steam_compat.joinpath(proton)) + env["PROTONPATH"] = os.environ["PROTONPATH"] log.debug("Removing: %s", tarball) thread_pool.submit(tmp.joinpath(tarball).unlink, True) log.console(f"Using {version} ({proton})") diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py index 9b45146f8..adf164560 100644 --- a/umu/umu_runtime.py +++ b/umu/umu_runtime.py @@ -1,13 +1,13 @@ +import os +import sys from concurrent.futures import Future, ThreadPoolExecutor from hashlib import sha256 from http.client import HTTPException, HTTPResponse, HTTPSConnection from json import load -from os import environ from pathlib import Path from shutil import move, rmtree from ssl import create_default_context from subprocess import run -from sys import version from tarfile import open as taropen from tempfile import mkdtemp from typing import Any @@ -16,7 +16,7 @@ from umu_log import log from umu_util import run_zenity -CLIENT_SESSION: HTTPSConnection = HTTPSConnection( +client_session: HTTPSConnection = HTTPSConnection( "repo.steampowered.com", context=create_default_context(), ) @@ -48,7 +48,7 @@ def _install_umu( log.debug("URL: %s", base_url) # Download the runtime and optionally create a popup with zenity - if environ.get("UMU_ZENITY") == "1": + if os.environ.get("UMU_ZENITY") == "1": bin: str = "curl" opts: list[str] = [ "-LJ", @@ -66,7 +66,7 @@ def _install_umu( tmp.joinpath(archive).unlink(missing_ok=True) log.console("Retrying from Python...") - if not environ.get("UMU_ZENITY") or ret: + if not os.environ.get("UMU_ZENITY") or ret: digest: str = "" endpoint: str = ( f"/steamrt-images-{codename}" @@ -75,14 +75,14 @@ def _install_umu( hash = sha256() # Get the digest for the runtime archive - CLIENT_SESSION.request("GET", f"{endpoint}/SHA256SUMS") - resp = CLIENT_SESSION.getresponse() + client_session.request("GET", f"{endpoint}/SHA256SUMS") + resp = client_session.getresponse() if resp.status != 200: err: str = ( f"repo.steampowered.com returned the status: {resp.status}" ) - CLIENT_SESSION.close() + client_session.close() raise HTTPException(err) for line in resp.read().decode("utf-8").splitlines(): @@ -91,14 +91,14 @@ def _install_umu( break # Download the runtime - CLIENT_SESSION.request("GET", f"{endpoint}/{archive}") - resp = CLIENT_SESSION.getresponse() + client_session.request("GET", f"{endpoint}/{archive}") + resp = client_session.getresponse() if resp.status != 200: err: str = ( f"repo.steampowered.com returned the status: {resp.status}" ) - CLIENT_SESSION.close() + client_session.close() raise HTTPException(err) log.console(f"Downloading latest steamrt {codename}, please wait...") @@ -113,11 +113,11 @@ def _install_umu( # Verify the runtime digest if hash.hexdigest() != digest: err: str = f"Digest mismatched: {archive}" - CLIENT_SESSION.close() + client_session.close() raise ValueError(err) log.console(f"{archive}: SHA256 is OK") - CLIENT_SESSION.close() + client_session.close() # Open the tar file and move the files log.debug("Opening: %s", tmp.joinpath(archive)) @@ -130,7 +130,7 @@ def _install_umu( log.debug("Using filter for archive") tar.extraction_filter = tar_filter else: - log.warning("Python: %s", version) + log.warning("Python: %s", sys.version) log.warning("Using no data filter for archive") log.warning("Archive will be extracted insecurely") @@ -257,8 +257,8 @@ def _update_umu( ) break - CLIENT_SESSION.request("GET", url) - resp = CLIENT_SESSION.getresponse() + client_session.request("GET", url) + resp = client_session.getresponse() # Handle the redirect if resp.status == 301: @@ -267,8 +267,8 @@ def _update_umu( # The stdlib requires reading the entire response body before # making another request resp.read() - CLIENT_SESSION.request("GET", f"{location}/{versions}") - resp = CLIENT_SESSION.getresponse() + client_session.request("GET", f"{location}/{versions}") + resp = client_session.getresponse() if resp.status != 200: log.warning( @@ -281,16 +281,16 @@ def _update_umu( ) # Update the runtime if necessary by comparing VERSIONS.txt to the remote - CLIENT_SESSION.request( + client_session.request( "GET", f"{endpoint}/SteamLinuxRuntime_{codename}.VERSIONS.txt" ) - resp = CLIENT_SESSION.getresponse() + resp = client_session.getresponse() if resp.status != 200: log.warning( "repo.steampowered.com returned the status: %s", resp.status ) - CLIENT_SESSION.close() + client_session.close() return if ( @@ -304,7 +304,7 @@ def _update_umu( return log.console("steamrt is up to date") - CLIENT_SESSION.close() + client_session.close() def _get_json(path: Path, config: str) -> dict[str, Any]: From 16f80b7fe74ff01d3fb7c717b5490c43b3d9286d Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:51:50 -0700 Subject: [PATCH 20/26] umu_util: update format --- umu/umu_util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/umu/umu_util.py b/umu/umu_util.py index 0361b857d..6349acca5 100644 --- a/umu/umu_util.py +++ b/umu/umu_util.py @@ -26,6 +26,7 @@ def run_zenity(command: str, opts: list[str], msg: str) -> int: if not bin: log.warning("zenity was not found in system") return -1 + if not cmd: log.warning("%s was not found in system", command) return -1 From 8ded674279d941e19eb443b8f8262df27d106383 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:58:01 -0700 Subject: [PATCH 21/26] umu_proton: don't initialize vars --- umu/umu_proton.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/umu/umu_proton.py b/umu/umu_proton.py index 063ab636c..330e55749 100644 --- a/umu/umu_proton.py +++ b/umu/umu_proton.py @@ -301,11 +301,11 @@ def _get_latest( $HOME/.local/share/Steam/compatibilitytool.d will be used. """ # Name of the Proton archive (e.g., GE-Proton9-7.tar.gz) - tarball: str = "" + tarball: str # Name of the Proton directory (e.g., GE-Proton9-7) - proton: str = "" + proton: str # Name of the Proton version, which is either UMU-Proton or GE-Proton - version: str = "" + version: str if not assets: return None From f66ac1f177b6dafe85f14acdd1b0096bbde34c69 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Sat, 29 Jun 2024 13:20:52 -0700 Subject: [PATCH 22/26] umu_run: add fixme tag to runtime workaround --- umu/umu_run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index bc080564d..3574b2de1 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -318,7 +318,7 @@ def set_env( if FLATPAK_PATH: env["UMU_NO_RUNTIME"] = os.environ.get("UMU_NO_RUNTIME") or "" - # Currently, running games when using the Steam Runtime in a Flatpak + # FIXME: Currently, running games when using the Steam Runtime in a Flatpak # environment will cause the game window to not display within the SteamOS # gamescope session. Note, this is a workaround until the runtime is built # or the issue is fixed upstream. From 9d9d54711a1b71301508bbecebaabc5f9b016969 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Sat, 29 Jun 2024 13:22:01 -0700 Subject: [PATCH 23/26] umu_runtime: move uninitialized var to top level scope --- umu/umu_runtime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py index adf164560..eccda348a 100644 --- a/umu/umu_runtime.py +++ b/umu/umu_runtime.py @@ -32,6 +32,7 @@ def _install_umu( json: dict[str, Any], thread_pool: ThreadPoolExecutor ) -> None: + resp: HTTPResponse tmp: Path = Path(mkdtemp()) ret: int = 0 # Exit code from zenity # Codename for the runtime (e.g., 'sniper') @@ -42,7 +43,6 @@ def _install_umu( f"https://repo.steampowered.com/steamrt-images-{codename}" "/snapshots/latest-container-runtime-public-beta" ) - resp: HTTPResponse log.debug("Codename: %s", codename) log.debug("URL: %s", base_url) From d1bd57350171ed34a7a61fa8a363eca94faf2d39 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Sat, 29 Jun 2024 13:22:18 -0700 Subject: [PATCH 24/26] umu_runtime: remove return statement --- umu/umu_runtime.py | 1 - 1 file changed, 1 deletion(-) diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py index eccda348a..df106adda 100644 --- a/umu/umu_runtime.py +++ b/umu/umu_runtime.py @@ -187,7 +187,6 @@ def setup_umu( return _update_umu(local, json, thread_pool) - return def _update_umu( From 69f67712cace32b9dcb46ebb72bbabb180248917 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Sat, 29 Jun 2024 13:23:08 -0700 Subject: [PATCH 25/26] umu_runtime: update string slicing logic --- umu/umu_runtime.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py index df106adda..05c0d20b4 100644 --- a/umu/umu_runtime.py +++ b/umu/umu_runtime.py @@ -231,10 +231,9 @@ def _update_umu( # When the file is missing, the request for the image will need to be made # to the endpoint of the specific snapshot if not local.joinpath("VERSIONS.txt").is_file(): + url: str release: Path = runtime.joinpath("files", "lib", "os-release") versions: str = f"SteamLinuxRuntime_{codename}.VERSIONS.txt" - url: str = "" - build_id: str = "" # Restore the runtime if os-release is missing, otherwise pressure # vessel will crash when creating the variable directory @@ -248,9 +247,10 @@ def _update_umu( with release.open(mode="r", encoding="utf-8") as file: for line in file: if line.startswith("BUILD_ID"): - _: str = line.strip() - # Get the value after '=' and strip the quotes - build_id = _[_.find("=") + 1 :].strip('"') + # Get the value after 'BUILD_ID=' and strip the quotes + build_id: str = ( + line.removeprefix("BUILD_ID=").strip('"').rstrip() + ) url = ( f"/steamrt-images-{codename}" f"/snapshots/{build_id}" ) From a2ca96ede06d549942597b181c0a8fe2543292a1 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Sat, 29 Jun 2024 13:38:18 -0700 Subject: [PATCH 26/26] umu_runtime: fix string logic --- umu/umu_runtime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py index 05c0d20b4..1d18992a7 100644 --- a/umu/umu_runtime.py +++ b/umu/umu_runtime.py @@ -249,7 +249,7 @@ def _update_umu( if line.startswith("BUILD_ID"): # Get the value after 'BUILD_ID=' and strip the quotes build_id: str = ( - line.removeprefix("BUILD_ID=").strip('"').rstrip() + line.removeprefix("BUILD_ID=").rstrip().strip('"') ) url = ( f"/steamrt-images-{codename}" f"/snapshots/{build_id}"