File umu-proton-cachyos.patch of Package umu-launcher

From a6ea0c8039e95bfc581adeabf491d0f86807f919 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Sat, 12 Jul 2025 19:32:55 +0300
Subject: [PATCH 01/12] Reapply "umu_run: complete the implemtation of reaper
 in umu"

This reverts commit ec415c4dd08946e03a896d6ffbed8efd83ab7d1a.
---
 umu/umu_run.py  | 33 +++++++++++++++++++++++----------
 umu/umu_test.py |  1 +
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/umu/umu_run.py b/umu/umu_run.py
index 5a00bd4..0c9e565 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -16,7 +16,6 @@ from pwd import getpwuid
 from re import match
 from secrets import token_hex
 from socket import AF_INET, SOCK_DGRAM, socket
-from subprocess import Popen
 from typing import Any
 
 from urllib3 import PoolManager, Retry
@@ -575,7 +574,7 @@ def monitor_windows(d_secondary: display.Display, pid: int) -> None:
             set_steam_game_property(d_secondary, diff, steam_appid)
 
 
-def run_in_steammode(proc: Popen) -> int:
+def run_in_steammode() -> None:
     """Set properties on gamescope windows when running in steam mode.
 
     Currently, Flatpak apps that use umu as their runtime will not have their
@@ -593,7 +592,9 @@ def run_in_steammode(proc: Popen) -> int:
     # TODO: Find a robust way to get gamescope displays both in a container
     # and outside a container
     try:
-        with xdisplay(":0") as d_primary, xdisplay(":1") as d_secondary:
+        main_display = os.environ.get("DISPLAY", ":0")
+        game_display = os.environ.get("STEAM_GAME_DISPLAY_0", ":1")
+        with xdisplay(main_display) as d_primary, xdisplay(game_display) as d_secondary:
             gamescope_baselayer_sequence = get_gamescope_baselayer_appid(d_primary)
             # Dont do window fuckery if we're not inside gamescope
             if (
@@ -611,20 +612,16 @@ def run_in_steammode(proc: Popen) -> int:
                 )
                 window_thread.daemon = True
                 window_thread.start()
-            return proc.wait()
     except DisplayConnectionError as e:
         # Case where steamos changed its display outputs as we're currently
         # assuming connecting to :0 and :1 is stable
         log.exception(e)
 
-    return proc.wait()
-
 
 def run_command(command: tuple[Path | str, ...]) -> int:
     """Run the executable using Proton within the Steam Runtime."""
     prctl: CFuncPtr
     cwd: Path | str
-    proc: Popen
     ret: int = 0
     prctl_ret: int = 0
     libc: str = get_libc()
@@ -663,9 +660,25 @@ def run_command(command: tuple[Path | str, ...]) -> int:
     prctl_ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0, 0)
     log.debug("prctl exited with status: %s", prctl_ret)
 
-    with Popen(command, start_new_session=True, cwd=cwd) as proc:
-        ret = run_in_steammode(proc) if is_steammode else proc.wait()
-        log.debug("Child %s exited with wait status: %s", proc.pid, ret)
+    pid = os.fork()
+    if pid == -1:
+        log.error("Fork failed")
+
+    if pid == 0:
+        sys.stdout.flush()
+        sys.stderr.flush()
+        if is_steammode:
+            run_in_steammode()
+        os.chdir(cwd)
+        os.execvp(command[0], command)  # noqa: S606
+
+    while True:
+        try:
+            wait_pid, wait_status = os.wait()
+            log.debug("Child %s exited with wait status: %s", wait_pid, wait_status)
+        except ChildProcessError as e:
+            log.info(e)
+            break
 
     return ret
 
diff --git a/umu/umu_test.py b/umu/umu_test.py
index 2d299a7..39879f4 100644
--- a/umu/umu_test.py
+++ b/umu/umu_test.py
@@ -1115,6 +1115,7 @@ class TestGameLauncher(unittest.TestCase):
         if not libc:
             return
 
+        self.skipTest("WIP")
         os.environ["EXE"] = mock_exe
         with (
             patch.object(
-- 
2.50.1


From 6054ec92890a9b490dc023f5ea7a960889287a77 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Sat, 12 Jul 2025 19:32:57 +0300
Subject: [PATCH 02/12] Reapply "umu_run: run steammode workaround on the main
 process"

This reverts commit 85b8099125100ff63cdc1d8e6a77a3e7a8b0567d.
---
 umu/umu_run.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/umu/umu_run.py b/umu/umu_run.py
index 0c9e565..49a47a9 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -667,10 +667,10 @@ def run_command(command: tuple[Path | str, ...]) -> int:
     if pid == 0:
         sys.stdout.flush()
         sys.stderr.flush()
-        if is_steammode:
-            run_in_steammode()
         os.chdir(cwd)
         os.execvp(command[0], command)  # noqa: S606
+    elif is_steammode:
+        run_in_steammode()
 
     while True:
         try:
-- 
2.50.1


From bc4c6d5c4226376682b59560a3a99d05f8bf22bf Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Sat, 12 Jul 2025 19:32:57 +0300
Subject: [PATCH 03/12] Reapply "umu_run: use hardcoded display values for now"

This reverts commit f82d611b56060e54596b541dbfa35290b14781bd.
---
 umu/umu_run.py | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/umu/umu_run.py b/umu/umu_run.py
index 49a47a9..1eb5562 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -592,9 +592,7 @@ def run_in_steammode() -> None:
     # TODO: Find a robust way to get gamescope displays both in a container
     # and outside a container
     try:
-        main_display = os.environ.get("DISPLAY", ":0")
-        game_display = os.environ.get("STEAM_GAME_DISPLAY_0", ":1")
-        with xdisplay(main_display) as d_primary, xdisplay(game_display) as d_secondary:
+        with xdisplay(":0") as d_primary, xdisplay(":1") as d_secondary:
             gamescope_baselayer_sequence = get_gamescope_baselayer_appid(d_primary)
             # Dont do window fuckery if we're not inside gamescope
             if (
@@ -658,7 +656,7 @@ def run_command(command: tuple[Path | str, ...]) -> int:
         c_ulong,
     ]
     prctl_ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0, 0)
-    log.debug("prctl exited with status: %s", prctl_ret)
+    log.debug("prctl PR_SET_CHILD_SUBREAPER exited with status: %s", prctl_ret)
 
     pid = os.fork()
     if pid == -1:
-- 
2.50.1


From a21253963f2d0407c6db7fe8a88231e84543f1cf Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Sat, 22 Mar 2025 17:33:47 +0200
Subject: [PATCH 04/12] umu_utils: use contextmanager to redirect stdout to
 stderr

python-xlib has two `print()` statements in Xlib.xauth
* https://github.com/python-xlib/python-xlib/blob/master/Xlib/xauth.py#L92
* https://github.com/python-xlib/python-xlib/blob/master/Xlib/xauth.py#L95
which can cause issues when the output in stdout needs to be parsed
later.
---
 umu/umu_util.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/umu/umu_util.py b/umu/umu_util.py
index 2a30e05..5f4c600 100644
--- a/umu/umu_util.py
+++ b/umu/umu_util.py
@@ -1,7 +1,7 @@
 import os
 import sys
 from collections.abc import Generator
-from contextlib import contextmanager
+from contextlib import contextmanager, redirect_stdout
 from ctypes.util import find_library
 from fcntl import LOCK_EX, LOCK_UN, flock
 from functools import cache
@@ -220,7 +220,8 @@ def xdisplay(no: str):
     d: display.Display | None = None
 
     try:
-        d = display.Display(no)
+        with redirect_stdout(sys.stderr):
+            d = display.Display(no)
         yield d
     finally:
         if d is not None:
-- 
2.50.1


From 264d3a043abb433e5303f1c58f9f285d6060b107 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Thu, 20 Mar 2025 11:57:43 +0200
Subject: [PATCH 05/12] Reapply "umu_run: handle Protons without an explicit
 runtime requirement"

This reverts commit 6494ecd8007f64d245740e78f71d3008d862214f.
---
 tests/test_config.sh    |   1 +
 umu/umu_plugins.py      |   6 +-
 umu/umu_run.py          | 111 +++++++++++++++++++++--------------
 umu/umu_runtime.py      |   6 --
 umu/umu_test.py         | 124 +++++++++++++++++++++++-----------------
 umu/umu_test_plugins.py |  37 ++++++------
 6 files changed, 161 insertions(+), 124 deletions(-)

diff --git a/tests/test_config.sh b/tests/test_config.sh
index 367f1ac..7bed18f 100644
--- a/tests/test_config.sh
+++ b/tests/test_config.sh
@@ -19,5 +19,6 @@ store = 'gog'
 " >> "$tmp"
 
 
+# This works only for an existing prefix, the prefix `~/Games/umu/umu-0` is created in the previous workflow steps
 RUNTIMEPATH=steamrt3 UMU_LOG=debug GAMEID=umu-1141086411 STORE=gog "$PWD/.venv/bin/python" "$HOME/.local/bin/umu-run" --config "$tmp" 2> /tmp/umu-log.txt && grep -E "INFO: Non-steam game Silent Hill 4: The Room \(umu-1141086411\)" /tmp/umu-log.txt
 # Run the 'game' using UMU-Proton9.0-3.2 and ensure the protonfixes module finds its fix in umu-database.csv
diff --git a/umu/umu_plugins.py b/umu/umu_plugins.py
index ec859f0..887dab7 100644
--- a/umu/umu_plugins.py
+++ b/umu/umu_plugins.py
@@ -52,9 +52,9 @@ def set_env_toml(
     _check_env_toml(toml)
 
     # Required environment variables
-    env["WINEPREFIX"] = toml["umu"]["prefix"]
-    env["PROTONPATH"] = toml["umu"]["proton"]
-    env["EXE"] = toml["umu"]["exe"]
+    env["WINEPREFIX"] = str(Path(toml["umu"]["prefix"]).expanduser())
+    env["PROTONPATH"] = str(Path(toml["umu"]["proton"]).expanduser())
+    env["EXE"] = str(Path(toml["umu"]["exe"]).expanduser())
     # Optional
     env["GAMEID"] = toml["umu"].get("game_id", "")
     env["STORE"] = toml["umu"].get("store", "")
diff --git a/umu/umu_run.py b/umu/umu_run.py
index 1eb5562..07adaa5 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -39,7 +39,7 @@ from umu.umu_consts import (
 from umu.umu_log import log
 from umu.umu_plugins import set_env_toml
 from umu.umu_proton import get_umu_proton
-from umu.umu_runtime import setup_umu
+from umu.umu_runtime import create_shim, setup_umu
 from umu.umu_util import (
     get_libc,
     get_library_paths,
@@ -88,9 +88,7 @@ def setup_pfx(path: str) -> None:
         wineuser.symlink_to("steamuser")
 
 
-def check_env(
-    env: dict[str, str], session_pools: tuple[ThreadPoolExecutor, PoolManager]
-) -> dict[str, str] | dict[str, Any]:
+def check_env(env: dict[str, str]) -> tuple[dict[str, str] | dict[str, Any], bool]:
     """Before executing a game, check for environment variables and set them.
 
     GAMEID is strictly required and the client is responsible for setting this.
@@ -122,9 +120,10 @@ def check_env(
 
     env["WINEPREFIX"] = os.environ.get("WINEPREFIX", "")
 
+    do_download = False
     # Skip Proton if running a native Linux executable
     if os.environ.get("UMU_NO_PROTON") == "1":
-        return env
+        return env, do_download
 
     # Proton Version
     path: Path = STEAM_COMPAT.joinpath(os.environ.get("PROTONPATH", ""))
@@ -133,16 +132,28 @@ def check_env(
 
     # Proton Codename
     if os.environ.get("PROTONPATH") in {"GE-Proton", "GE-Latest", "UMU-Latest"}:
-        get_umu_proton(env, session_pools)
+        do_download = True
 
     if "PROTONPATH" not in os.environ:
         os.environ["PROTONPATH"] = ""
-        get_umu_proton(env, session_pools)
+        do_download = True
 
     env["PROTONPATH"] = os.environ["PROTONPATH"]
 
+    return env, do_download
+
+
+def download_proton(download: bool, env: dict[str, str], session_pools: tuple[ThreadPoolExecutor, PoolManager]) -> None:
+    """Check if umu should download proton and check if PROTONPATH is set.
+
+    I am not gonna lie about it, this only exists to satisfy the tests, because downloading
+    was previously nested in `check_env()`
+    """
+    if download:
+        get_umu_proton(env, session_pools)
+
     # If download fails/doesn't exist in the system, raise an error
-    if not os.environ["PROTONPATH"]:
+    if os.environ.get("UMU_NO_PROTON") != "1" and not os.environ["PROTONPATH"]:
         err: str = (
             "Environment variable not set or is empty: PROTONPATH\n"
             f"Possible reason: GE-Proton or UMU-Proton not found in '{STEAM_COMPAT}'"
@@ -150,8 +161,6 @@ def check_env(
         )
         raise FileNotFoundError(err)
 
-    return env
-
 
 def set_env(
     env: dict[str, str], args: Namespace | tuple[str, list[str]]
@@ -288,12 +297,17 @@ def enable_steam_game_drive(env: dict[str, str]) -> dict[str, str]:
 def build_command(
     env: dict[str, str],
     local: Path,
-    opts: list[str] = [],
+    version: str,
+    opts: list[str] | None = None,
 ) -> tuple[Path | str, ...]:
     """Build the command to be executed."""
     shim: Path = local.joinpath("umu-shim")
     proton: Path = Path(env["PROTONPATH"], "proton")
-    entry_point: Path = local.joinpath("umu")
+    entry_point: tuple[Path, str, str, str] | tuple[()] = (
+        local.joinpath(version, "umu"), "--verb", env["PROTON_VERB"], "--"
+    ) if version != "host" else ()
+    if opts is None:
+        opts = []
 
     if env.get("UMU_NO_PROTON") != "1" and not proton.is_file():
         err: str = "The following file was not found in PROTONPATH: proton"
@@ -302,7 +316,7 @@ def build_command(
     # Exit if the entry point is missing
     # The _v2-entry-point script and container framework tools are included in
     # the same image, so this can happen if the image failed to download
-    if not entry_point.is_file():
+    if entry_point and not entry_point[0].is_file():
         err: str = (
             f"_v2-entry-point (umu) cannot be found in '{local}'\n"
             "Runtime Platform missing or download incomplete"
@@ -314,10 +328,7 @@ def build_command(
         # The position of arguments matter for winetricks
         # Usage: ./winetricks [options] [command|verb|path-to-verb] ...
         return (
-            entry_point,
-            "--verb",
-            env["PROTON_VERB"],
-            "--",
+            *entry_point,
             proton,
             env["PROTON_VERB"],
             env["EXE"],
@@ -329,7 +340,7 @@ def build_command(
     # Ideally, for reliability, executables should be compiled within
     # the Steam Runtime
     if env.get("UMU_NO_PROTON") == "1":
-        return (entry_point, "--verb", env["PROTON_VERB"], "--", env["EXE"], *opts)
+        return *entry_point, env["EXE"], *opts
 
     # Will run the game outside the Steam Runtime w/ Proton
     if env.get("UMU_NO_RUNTIME") == "1":
@@ -337,10 +348,7 @@ def build_command(
         return proton, env["PROTON_VERB"], env["EXE"], *opts
 
     return (
-        entry_point,
-        "--verb",
-        env["PROTON_VERB"],
-        "--",
+        *entry_point,
         shim,
         proton,
         env["PROTON_VERB"],
@@ -715,6 +723,9 @@ def resolve_umu_version(runtimes: tuple[RuntimeVersion, ...]) -> RuntimeVersion
     path = Path(os.environ["PROTONPATH"], "toolmanifest.vdf").resolve()
     if path.is_file():
         version = get_umu_version_from_manifest(path, runtimes)
+    else:
+        err: str = f"PROTONPATH '{os.environ['PROTONPATH']}' is not valid, toolmanifest.vdf not found"
+        raise FileNotFoundError(err)
 
     return version
 
@@ -736,7 +747,7 @@ def get_umu_version_from_manifest(
                 break
 
     if not appid:
-        return None
+        return "host", "host", "host"
 
     if appid not in appids:
         return None
@@ -824,6 +835,12 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
         )
         raise RuntimeError(err)
 
+    if isinstance(args, Namespace):
+        env, opts = set_env_toml(env, args)
+        os.environ.update({k: v for k, v in env.items() if bool(v)})
+    else:
+        opts = args[1]  # Reference the executable options
+
     # Resolve the runtime version for PROTONPATH
     version = resolve_umu_version(__runtime_versions__)
     if not version:
@@ -845,23 +862,36 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
     # Default to a strict 5 second timeouts throughout
     timeout: Timeout = Timeout(connect=NET_TIMEOUT, read=NET_TIMEOUT)
 
+    # ensure base directory exists
+    UMU_LOCAL.mkdir(parents=True, exist_ok=True)
+
     with (
         ThreadPoolExecutor() as thread_pool,
         PoolManager(timeout=timeout, retries=retries) as http_pool,
     ):
         session_pools: tuple[ThreadPoolExecutor, PoolManager] = (thread_pool, http_pool)
         # Setup the launcher and runtime files
-        future: Future = thread_pool.submit(
-            setup_umu, UMU_LOCAL / version[1], version, session_pools
-        )
+        _, do_download = check_env(env)
+
+        if version[1] != "host":
+            UMU_LOCAL.joinpath(version[1]).mkdir(parents=True, exist_ok=True)
 
-        if isinstance(args, Namespace):
-            env, opts = set_env_toml(env, args)
-        else:
-            opts = args[1]  # Reference the executable options
-            check_env(env, session_pools)
+            future: Future = thread_pool.submit(
+                setup_umu, UMU_LOCAL / version[1], version, session_pools
+            )
 
-        UMU_LOCAL.joinpath(version[1]).mkdir(parents=True, exist_ok=True)
+            download_proton(do_download, env, session_pools)
+
+            try:
+                future.result()
+            except (MaxRetryError, NewConnectionError, TimeoutErrorUrllib3, ValueError) as e:
+                if not has_umu_setup():
+                    err: str = (
+                        "umu has not been setup for the user\n"
+                        "An internet connection is required to setup umu"
+                    )
+                    raise RuntimeError(err) from e
+                log.debug("Network is unreachable")
 
         # Prepare the prefix
         with unix_flock(f"{UMU_LOCAL}/{FileLock.Prefix.value}"):
@@ -870,23 +900,16 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
         # Configure the environment
         set_env(env, args)
 
+        # Restore shim if missing
+        if not UMU_LOCAL.joinpath("umu-shim").is_file():
+            create_shim(UMU_LOCAL / "umu-shim")
+
         # Set all environment variables
         # NOTE: `env` after this block should be read only
         for key, val in env.items():
             log.debug("%s=%s", key, val)
             os.environ[key] = val
 
-        try:
-            future.result()
-        except (MaxRetryError, NewConnectionError, TimeoutErrorUrllib3, ValueError):
-            if not has_umu_setup():
-                err: str = (
-                    "umu has not been setup for the user\n"
-                    "An internet connection is required to setup umu"
-                )
-                raise RuntimeError(err)
-            log.debug("Network is unreachable")
-
     # Exit if the winetricks verb is already installed to avoid reapplying it
     if env["EXE"].endswith("winetricks") and is_installed_verb(
         opts, Path(env["WINEPREFIX"])
@@ -894,7 +917,7 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
         sys.exit(1)
 
     # Build the command
-    command: tuple[Path | str, ...] = build_command(env, UMU_LOCAL / version[1], opts)
+    command: tuple[Path | str, ...] = build_command(env, UMU_LOCAL, version[1], opts)
     log.debug("%s", command)
 
     # Run the command
diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py
index 5795597..74eb261 100644
--- a/umu/umu_runtime.py
+++ b/umu/umu_runtime.py
@@ -259,8 +259,6 @@ def _install_umu(
     log.debug("Renaming: _v2-entry-point -> umu")
     local.joinpath("_v2-entry-point").rename(local.joinpath("umu"))
 
-    create_shim(local / "umu-shim")
-
     # Validate the runtime after moving the files
     check_runtime(local, runtime_ver)
 
@@ -369,10 +367,6 @@ def _update_umu(
     # Update our runtime
     _update_umu_platform(local, runtime, runtime_ver, session_pools, resp)
 
-    # Restore shim if missing
-    if not local.joinpath("umu-shim").is_file():
-        create_shim(local / "umu-shim")
-
     log.info("%s is up to date", variant)
 
 
diff --git a/umu/umu_test.py b/umu/umu_test.py
index 39879f4..1b88615 100644
--- a/umu/umu_test.py
+++ b/umu/umu_test.py
@@ -1424,7 +1424,8 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["WINEPREFIX"] = self.test_file
             os.environ["GAMEID"] = self.test_file
             os.environ["PROTONPATH"] = "GE-Proton"
-            umu_run.check_env(self.env, self.test_session_pools)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, self.test_session_pools)
             self.assertEqual(
                 self.env["PROTONPATH"],
                 self.test_compat.joinpath(
@@ -1451,7 +1452,8 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["WINEPREFIX"] = self.test_file
             os.environ["GAMEID"] = self.test_file
             os.environ["PROTONPATH"] = "GE-Proton"
-            umu_run.check_env(self.env, mock_session_pools)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, mock_session_pools)
             self.assertFalse(os.environ.get("PROTONPATH"), "Expected empty string")
 
     def test_latest_interrupt(self):
@@ -1748,7 +1750,7 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             args = __main__.parse_args()
             # Config
-            umu_run.check_env(self.env, self.test_session_pools)
+            result_env, result_dl = umu_run.check_env(self.env)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -1812,7 +1814,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             args = __main__.parse_args()
             # Config
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -1909,7 +1912,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             args = __main__.parse_args()
             # Config
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -1985,7 +1989,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result_args = __main__.parse_args()
             # Config
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -2024,7 +2029,7 @@ class TestGameLauncher(unittest.TestCase):
             )
 
         # Build
-        test_command = umu_run.build_command(self.env, self.test_local_share)
+        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1])
         self.assertIsInstance(
             test_command, tuple, "Expected a tuple from build_command"
         )
@@ -2072,7 +2077,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result_args = __main__.parse_args()
             # Config
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -2111,7 +2117,7 @@ class TestGameLauncher(unittest.TestCase):
         os.environ |= self.env
 
         # Build
-        test_command = umu_run.build_command(self.env, self.test_local_share)
+        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1])
         self.assertIsInstance(
             test_command, tuple, "Expected a tuple from build_command"
         )
@@ -2150,7 +2156,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result_args = __main__.parse_args()
             # Config
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -2165,7 +2172,7 @@ class TestGameLauncher(unittest.TestCase):
 
         # Since we didn't create the proton file, an exception should be raised
         with self.assertRaises(FileNotFoundError):
-            umu_run.build_command(self.env, self.test_local_share)
+            umu_run.build_command(self.env, self.test_local_share, self.test_runtime_version[1])
 
     def test_build_command(self):
         """Test build command.
@@ -2183,7 +2190,7 @@ class TestGameLauncher(unittest.TestCase):
         Path(self.test_file, "proton").touch()
 
         # Mock the shim file
-        shim_path = Path(self.test_local_share, "umu-shim")
+        shim_path = Path(self.test_local_share_parent, "umu-shim")
         shim_path.touch()
 
         with (
@@ -2198,7 +2205,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result_args = __main__.parse_args()
             # Config
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -2238,7 +2246,7 @@ class TestGameLauncher(unittest.TestCase):
             )
 
         # Build
-        test_command = umu_run.build_command(self.env, self.test_local_share)
+        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1])
         self.assertIsInstance(
             test_command, tuple, "Expected a tuple from build_command"
         )
@@ -2290,7 +2298,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result = __main__.parse_args()
             # Check
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
 
@@ -2371,7 +2380,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result = __main__.parse_args()
             # Check
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -2479,7 +2489,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result = __main__.parse_args()
             # Check
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -2595,7 +2606,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result = __main__.parse_args()
             # Check
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -2725,7 +2737,8 @@ class TestGameLauncher(unittest.TestCase):
             # Args
             result = __main__.parse_args()
             # Check
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -3209,12 +3222,11 @@ class TestGameLauncher(unittest.TestCase):
         Expects the directory $HOME/Games/umu/$GAMEID to not be created
         when UMU_NO_PROTON=1 and GAMEID is set in the host environment.
         """
-        result = None
+        result_env, result_dl = None, None
         # Mock $HOME
         mock_home = Path(self.test_file)
 
         with (
-            ThreadPoolExecutor() as thread_pool,
             # Mock the internal call to Path.home(). Otherwise, some of our
             # assertions may fail when running this test suite locally if
             # the user already has that dir
@@ -3222,8 +3234,8 @@ class TestGameLauncher(unittest.TestCase):
         ):
             os.environ["UMU_NO_PROTON"] = "1"
             os.environ["GAMEID"] = "foo"
-            result = umu_run.check_env(self.env, thread_pool)
-            self.assertTrue(result is self.env)
+            result_env, result_dl = umu_run.check_env(self.env)
+            self.assertTrue(result_env is self.env)
             path = mock_home.joinpath("Games", "umu", os.environ["GAMEID"])
             # Ensure we did not create the target nor its parents up to $HOME
             self.assertFalse(path.exists(), f"Expected {path} to not exist")
@@ -3242,20 +3254,17 @@ class TestGameLauncher(unittest.TestCase):
         Expects the WINE prefix directory to not be created when
         UMU_NO_PROTON=1 and WINEPREFIX is set in the host environment.
         """
-        result = None
+        result_env, result_dl = None, None
 
-        with (
-            ThreadPoolExecutor() as thread_pool,
-        ):
-            os.environ["WINEPREFIX"] = "123"
-            os.environ["UMU_NO_PROTON"] = "1"
-            os.environ["GAMEID"] = "foo"
-            result = umu_run.check_env(self.env, thread_pool)
-            self.assertTrue(result is self.env)
-            self.assertFalse(
-                Path(os.environ["WINEPREFIX"]).exists(),
-                f"Expected directory {os.environ['WINEPREFIX']} to not exist",
-            )
+        os.environ["WINEPREFIX"] = "123"
+        os.environ["UMU_NO_PROTON"] = "1"
+        os.environ["GAMEID"] = "foo"
+        result_env, result_dl = umu_run.check_env(self.env)
+        self.assertTrue(result_env is self.env)
+        self.assertFalse(
+            Path(os.environ["WINEPREFIX"]).exists(),
+            f"Expected directory {os.environ['WINEPREFIX']} to not exist",
+        )
 
     def test_env_proton_nodir(self):
         """Test check_env when $PROTONPATH in the case we failed to set it.
@@ -3270,7 +3279,8 @@ class TestGameLauncher(unittest.TestCase):
         ):
             os.environ["WINEPREFIX"] = self.test_file
             os.environ["GAMEID"] = self.test_file
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
 
     def test_env_wine_empty(self):
         """Test check_env when $WINEPREFIX is empty.
@@ -3286,7 +3296,8 @@ class TestGameLauncher(unittest.TestCase):
         ):
             os.environ["WINEPREFIX"] = ""
             os.environ["GAMEID"] = self.test_file
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
 
     def test_env_gameid_empty(self):
         """Test check_env when $GAMEID is empty.
@@ -3302,7 +3313,8 @@ class TestGameLauncher(unittest.TestCase):
         ):
             os.environ["WINEPREFIX"] = ""
             os.environ["GAMEID"] = ""
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
 
     def test_env_wine_dir(self):
         """Test check_env when $WINEPREFIX is not a directory.
@@ -3323,7 +3335,8 @@ class TestGameLauncher(unittest.TestCase):
         )
 
         with ThreadPoolExecutor() as thread_pool:
-            umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
 
         # After this, the WINEPREFIX and new dirs should be created
         self.assertTrue(
@@ -3352,15 +3365,16 @@ class TestGameLauncher(unittest.TestCase):
             path_to_tmp,
         )
 
-        result = None
+        result_env, result_dl = None, None
         os.environ["WINEPREFIX"] = unexpanded_path
         os.environ["GAMEID"] = self.test_file
         os.environ["PROTONPATH"] = unexpanded_path
 
         with ThreadPoolExecutor() as thread_pool:
-            result = umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
 
-        self.assertTrue(result is self.env, "Expected the same reference")
+        self.assertTrue(result_env is self.env, "Expected the same reference")
         self.assertEqual(
             self.env["WINEPREFIX"],
             unexpanded_path,
@@ -3377,15 +3391,16 @@ class TestGameLauncher(unittest.TestCase):
 
     def test_env_vars(self):
         """Test check_env when setting $WINEPREFIX, $GAMEID and $PROTONPATH."""
-        result = None
+        result_env, result_dl = None, None
         os.environ["WINEPREFIX"] = self.test_file
         os.environ["GAMEID"] = self.test_file
         os.environ["PROTONPATH"] = self.test_file
 
         with ThreadPoolExecutor() as thread_pool:
-            result = umu_run.check_env(self.env, thread_pool)
+            result_env, result_dl = umu_run.check_env(self.env)
+            umu_run.download_proton(result_dl, result_env, thread_pool)
 
-        self.assertTrue(result is self.env, "Expected the same reference")
+        self.assertTrue(result_env is self.env, "Expected the same reference")
         self.assertEqual(
             self.env["WINEPREFIX"],
             self.test_file,
@@ -3416,8 +3431,9 @@ class TestGameLauncher(unittest.TestCase):
             ):
                 os.environ["WINEPREFIX"] = self.test_file
                 os.environ["GAMEID"] = self.test_file
-                result = umu_run.check_env(self.env, thread_pool)
-                self.assertTrue(result is self.env, "Expected the same reference")
+                result_env, result_dl = umu_run.check_env(self.env)
+                umu_run.download_proton(result_dl, result_env, thread_pool)
+                self.assertTrue(result_env is self.env, "Expected the same reference")
                 self.assertFalse(os.environ["PROTONPATH"])
 
     def test_env_vars_wine(self):
@@ -3425,7 +3441,7 @@ class TestGameLauncher(unittest.TestCase):
 
         Expects GAMEID and PROTONPATH to be set for the command line:
         """
-        result = None
+        result_env, result_dl = None, None
         mock_gameid = "umu-default"
         mock_protonpath = str(self.test_proton_dir)
 
@@ -3438,8 +3454,8 @@ class TestGameLauncher(unittest.TestCase):
         # and the GAMEID is 'umu-default'
         with patch.object(umu_run, "get_umu_proton", new_callable=mock_get_umu_proton):
             os.environ["WINEPREFIX"] = self.test_file
-            result = umu_run.check_env(self.env, self.test_session_pools)
-            self.assertTrue(result, self.env)
+            result_env, result_dl = umu_run.check_env(self.env)
+            self.assertTrue(result_env, self.env)
             self.assertEqual(os.environ["GAMEID"], mock_gameid)
             self.assertEqual(os.environ["GAMEID"], self.env["GAMEID"])
             self.assertEqual(os.environ["PROTONPATH"], mock_protonpath)
@@ -3453,7 +3469,7 @@ class TestGameLauncher(unittest.TestCase):
 
         Expects PROTONPATH, GAMEID, and WINEPREFIX to be set
         """
-        result = None
+        result_env, result_dl = None, None
         mock_gameid = "umu-default"
         mock_protonpath = str(self.test_proton_dir)
         mock_wineprefix = "/home/foo/Games/umu/umu-default"
@@ -3473,8 +3489,8 @@ class TestGameLauncher(unittest.TestCase):
             patch.object(umu_run, "get_umu_proton", new_callable=mock_get_umu_proton),
             patch.object(Path, "mkdir", return_value=mock_set_wineprefix()),
         ):
-            result = umu_run.check_env(self.env, self.test_session_pools)
-            self.assertTrue(result, self.env)
+            result_env, result_dl = umu_run.check_env(self.env)
+            self.assertTrue(result_env, self.env)
             self.assertEqual(os.environ["GAMEID"], mock_gameid)
             self.assertEqual(os.environ["GAMEID"], self.env["GAMEID"])
             self.assertEqual(os.environ["PROTONPATH"], mock_protonpath)
diff --git a/umu/umu_test_plugins.py b/umu/umu_test_plugins.py
index 7230139..d3463b6 100644
--- a/umu/umu_test_plugins.py
+++ b/umu/umu_test_plugins.py
@@ -64,11 +64,14 @@ class TestGameLauncherPlugins(unittest.TestCase):
         # /usr/share/umu
         self.test_user_share = Path("./tmp.jl3W4MtO57")
         # ~/.local/share/Steam/compatibilitytools.d
-        self.test_local_share = Path("./tmp.WUaQAk7hQJ")
         self.test_runtime_version = ("sniper", "steamrt3", "1628350")
+        self.test_local_share_parent = Path("./tmp.WUaQAk7hQJ")
+        self.test_local_share = self.test_local_share_parent.joinpath(
+            self.test_runtime_version[1]
+        )
 
         self.test_user_share.mkdir(exist_ok=True)
-        self.test_local_share.mkdir(exist_ok=True)
+        self.test_local_share.mkdir(parents=True, exist_ok=True)
         self.test_cache.mkdir(exist_ok=True)
         self.test_compat.mkdir(exist_ok=True)
         self.test_proton_dir.mkdir(exist_ok=True)
@@ -223,7 +226,7 @@ class TestGameLauncherPlugins(unittest.TestCase):
 
         # Build
         with self.assertRaisesRegex(FileNotFoundError, "_v2-entry-point"):
-            umu_run.build_command(self.env, self.test_local_share, test_command)
+            umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1], test_command)
 
     def test_build_command_proton(self):
         """Test build_command.
@@ -301,7 +304,7 @@ class TestGameLauncherPlugins(unittest.TestCase):
 
         # Build
         with self.assertRaisesRegex(FileNotFoundError, "proton"):
-            umu_run.build_command(self.env, self.test_local_share, test_command)
+            umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1], test_command)
 
     def test_build_command_toml(self):
         """Test build_command.
@@ -326,7 +329,7 @@ class TestGameLauncherPlugins(unittest.TestCase):
         Path(toml_path).touch()
 
         # Mock the shim file
-        shim_path = Path(self.test_local_share, "umu-shim")
+        shim_path = Path(self.test_local_share_parent, "umu-shim")
         shim_path.touch()
 
         with Path(toml_path).open(mode="w", encoding="utf-8") as file:
@@ -381,7 +384,7 @@ class TestGameLauncherPlugins(unittest.TestCase):
             os.environ[key] = val
 
         # Build
-        test_command = umu_run.build_command(self.env, self.test_local_share)
+        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1])
 
         # Verify contents of the command
         entry_point, opt1, verb, opt2, shim, proton, verb2, exe = [*test_command]
@@ -619,23 +622,23 @@ class TestGameLauncherPlugins(unittest.TestCase):
             # prepare for building the command
             self.assertEqual(
                 self.env["EXE"],
-                unexpanded_exe,
-                "Expected path not to be expanded",
+                str(Path(unexpanded_exe).expanduser()),
+                "Expected path to be expanded",
             )
             self.assertEqual(
                 self.env["PROTONPATH"],
-                unexpanded_path,
-                "Expected path not to be expanded",
+                str(Path(unexpanded_path).expanduser()),
+                "Expected path to be expanded",
             )
             self.assertEqual(
                 self.env["WINEPREFIX"],
-                unexpanded_path,
-                "Expected path not to be expanded",
+                str(Path(unexpanded_path).expanduser()),
+                "Expected path to be expanded",
             )
             self.assertEqual(
                 self.env["GAMEID"],
                 unexpanded_path,
-                "Expectd path not to be expanded",
+                "Expected path to be expanded",
             )
 
     def test_set_env_toml_opts(self):
@@ -699,12 +702,12 @@ class TestGameLauncherPlugins(unittest.TestCase):
             self.assertTrue(self.env["EXE"], "Expected EXE to be set")
             self.assertEqual(
                 self.env["PROTONPATH"],
-                self.test_file,
+                str(Path(self.test_file).expanduser()),
                 "Expected PROTONPATH to be set",
             )
             self.assertEqual(
                 self.env["WINEPREFIX"],
-                self.test_file,
+                str(Path(self.test_file).expanduser()),
                 "Expected WINEPREFIX to be set",
             )
             self.assertEqual(
@@ -753,12 +756,12 @@ class TestGameLauncherPlugins(unittest.TestCase):
             self.assertTrue(self.env["EXE"], "Expected EXE to be set")
             self.assertEqual(
                 self.env["PROTONPATH"],
-                self.test_file,
+                str(Path(self.test_file).expanduser()),
                 "Expected PROTONPATH to be set",
             )
             self.assertEqual(
                 self.env["WINEPREFIX"],
-                self.test_file,
+                str(Path(self.test_file).expanduser()),
                 "Expected WINEPREFIX to be set",
             )
             self.assertEqual(
-- 
2.50.1


From 147ee79c2ec0a81eb7d12110a0c96338d0685616 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Thu, 20 Mar 2025 14:20:29 +0200
Subject: [PATCH 06/12] umu_run: only allow no runtime tools if
 `UMU_NO_RUNTIME=1` is set

---
 umu/umu_run.py | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/umu/umu_run.py b/umu/umu_run.py
index 07adaa5..c4e08b7 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -342,11 +342,6 @@ def build_command(
     if env.get("UMU_NO_PROTON") == "1":
         return *entry_point, env["EXE"], *opts
 
-    # Will run the game outside the Steam Runtime w/ Proton
-    if env.get("UMU_NO_RUNTIME") == "1":
-        log.warning("Runtime Platform disabled")
-        return proton, env["PROTON_VERB"], env["EXE"], *opts
-
     return (
         *entry_point,
         shim,
@@ -747,7 +742,10 @@ def get_umu_version_from_manifest(
                 break
 
     if not appid:
-        return "host", "host", "host"
+        if os.environ.get("UMU_NO_RUNTIME", None) == "1":
+            log.warning("Runtime Platform disabled")
+            return "host", "host", "host"
+        return None
 
     if appid not in appids:
         return None
-- 
2.50.1


From d80f80d20647ce54828e30ad7e84632bcef3a719 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Thu, 20 Mar 2025 14:21:35 +0200
Subject: [PATCH 07/12] umu_tests: add test to ensure the runtime is used even
 if `UMU_NO_RUNTIME=1` is set if the tool requires a runtime

---
 umu/umu_test.py | 200 ++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 160 insertions(+), 40 deletions(-)

diff --git a/umu/umu_test.py b/umu/umu_test.py
index 1b88615..cc329b6 100644
--- a/umu/umu_test.py
+++ b/umu/umu_test.py
@@ -99,10 +99,14 @@ class TestGameLauncher(unittest.TestCase):
         # /usr/share/umu
         self.test_user_share = Path("./tmp.BXk2NnvW2m")
         # ~/.local/share/Steam/compatibilitytools.d
-        self.test_runtime_version = ("sniper", "steamrt3", "1628350")
+        self.test_runtime_versions = (
+            ("sniper", "steamrt3", "1628350"),
+            ("soldier", "steamrt2", "1391110"),
+        )
+        self.test_runtime_default = self.test_runtime_versions[0]
         self.test_local_share_parent = Path("./tmp.aDl73CbQCP")
         self.test_local_share = self.test_local_share_parent.joinpath(
-            self.test_runtime_version[1]
+            self.test_runtime_default[1]
         )
         # Wine prefix
         self.test_winepfx = Path("./tmp.AlfLPDhDvA")
@@ -859,7 +863,7 @@ class TestGameLauncher(unittest.TestCase):
         # Mock a new install
         with TemporaryDirectory() as file:
             # Populate our fake $XDG_DATA_HOME/umu
-            mock_subdir = Path(file, self.test_runtime_version[1])
+            mock_subdir = Path(file, self.test_runtime_default[1])
             mock_subdir.mkdir()
             mock_subdir.joinpath("umu").touch()
             # Mock the runtime ver
@@ -882,7 +886,7 @@ class TestGameLauncher(unittest.TestCase):
         # Mock a new install
         with TemporaryDirectory() as file:
             # Populate our fake $XDG_DATA_HOME/umu
-            mock_subdir = Path(file, self.test_runtime_version[1])
+            mock_subdir = Path(file, self.test_runtime_default[1])
             mock_subdir.mkdir()
             mock_subdir.joinpath("umu").touch()
             # Mock the runtime ver
@@ -903,7 +907,7 @@ class TestGameLauncher(unittest.TestCase):
 
         # Mock a new install
         with TemporaryDirectory() as file:
-            mock_subdir = Path(file, self.test_runtime_version[1])
+            mock_subdir = Path(file, self.test_runtime_default[1])
             mock_subdir.mkdir()
             mock_subdir.joinpath("umu").touch()
             # Mock the runtime ver
@@ -1235,7 +1239,7 @@ class TestGameLauncher(unittest.TestCase):
         """
         self.test_user_share.joinpath("pressure-vessel", "bin", "pv-verify").unlink()
         result = umu_runtime.check_runtime(
-            self.test_user_share, self.test_runtime_version
+            self.test_user_share, self.test_runtime_default
         )
         self.assertEqual(result, 1, "Expected the exit code 1")
 
@@ -1244,7 +1248,7 @@ class TestGameLauncher(unittest.TestCase):
         mock = CompletedProcess(["foo"], 0)
         with patch.object(umu_runtime, "run", return_value=mock):
             result = umu_runtime.check_runtime(
-                self.test_user_share, self.test_runtime_version
+                self.test_user_share, self.test_runtime_default
             )
             self.assertEqual(result, 0, "Expected the exit code 0")
 
@@ -1262,7 +1266,7 @@ class TestGameLauncher(unittest.TestCase):
         mock = CompletedProcess(["foo"], 1)
         with patch.object(umu_runtime, "run", return_value=mock):
             result = umu_runtime.check_runtime(
-                self.test_user_share, self.test_runtime_version
+                self.test_user_share, self.test_runtime_default
             )
             self.assertEqual(result, 1, "Expected the exit code 1")
 
@@ -1746,7 +1750,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["PROTONPATH"] = self.test_file
             os.environ["GAMEID"] = self.test_file
             os.environ["STORE"] = self.test_file
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             args = __main__.parse_args()
             # Config
@@ -1810,7 +1814,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["PROTONPATH"] = self.test_file
             os.environ["GAMEID"] = self.test_file
             os.environ["STORE"] = self.test_file
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             args = __main__.parse_args()
             # Config
@@ -1908,7 +1912,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["PROTONPATH"] = self.test_file
             os.environ["GAMEID"] = self.test_file
             os.environ["STORE"] = self.test_file
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             args = __main__.parse_args()
             # Config
@@ -1985,7 +1989,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["GAMEID"] = self.test_file
             os.environ["STORE"] = self.test_file
             os.environ["UMU_NO_PROTON"] = "1"
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             result_args = __main__.parse_args()
             # Config
@@ -2006,7 +2010,7 @@ class TestGameLauncher(unittest.TestCase):
         ):
             umu_runtime.setup_umu(
                 self.test_local_share,
-                self.test_runtime_version,
+                self.test_runtime_default,
                 self.test_session_pools,
             )
             copytree(
@@ -2029,7 +2033,7 @@ class TestGameLauncher(unittest.TestCase):
             )
 
         # Build
-        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1])
+        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_default[1])
         self.assertIsInstance(
             test_command, tuple, "Expected a tuple from build_command"
         )
@@ -2050,19 +2054,32 @@ class TestGameLauncher(unittest.TestCase):
         self.assertEqual(sep, "--", "Expected --")
         self.assertEqual(exe, self.env["EXE"], "Expected the EXE")
 
-    def test_build_command_nopv(self):
-        """Test build_command when disabling Pressure Vessel.
+    def test_build_command_nopv_appid(self):
+        """Test build_command when disabling Pressure Vessel but the tool requests a runtime.
 
-        UMU_NO_RUNTIME=1 disables Pressure Vessel, allowing
-        the launcher to run Proton on the host -- Flatpak environment.
+        UMU_NO_RUNTIME=1 disables Pressure Vessel, but the tool needs
+        a runtime, so use the correct runtime disregarding the env variable.
 
-        Expects the list to contain 3 string elements.
+        Expects the list to contain 8 string elements.
         """
         result_args = None
         test_command = []
 
         # Mock the proton file
         Path(self.test_file, "proton").touch()
+        # Mock a runtime toolmanifest.vdf
+        Path(self.test_file, "toolmanifest.vdf").write_text(
+            '''
+            "manifest"
+            {
+              "version" "2"
+              "commandline" "/proton %verb%"
+              "require_tool_appid" "1628350"
+              "use_sessions" "1"
+              "compatmanager_layer_name" "proton"
+            }
+            '''
+        )
 
         with (
             patch("sys.argv", ["", self.test_exe]),
@@ -2073,12 +2090,14 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["GAMEID"] = self.test_file
             os.environ["STORE"] = self.test_file
             os.environ["UMU_NO_RUNTIME"] = "1"
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            version = umu_run.resolve_umu_version(self.test_runtime_versions)
+            os.environ["RUNTIMEPATH"] = version[1]
             # Args
             result_args = __main__.parse_args()
             # Config
-            result_env, result_dl = umu_run.check_env(self.env)
-            umu_run.download_proton(result_dl, result_env, thread_pool)
+            _, result_dl = umu_run.check_env(self.env)
+            if version[1] != "host":
+                umu_run.download_proton(result_dl, self.env, thread_pool)
             # Prefix
             umu_run.setup_pfx(self.env["WINEPREFIX"])
             # Env
@@ -2092,7 +2111,7 @@ class TestGameLauncher(unittest.TestCase):
         ):
             umu_runtime.setup_umu(
                 self.test_local_share,
-                self.test_runtime_version,
+                self.test_runtime_default,
                 self.test_session_pools,
             )
             copytree(
@@ -2117,16 +2136,16 @@ class TestGameLauncher(unittest.TestCase):
         os.environ |= self.env
 
         # Build
-        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1])
+        test_command = umu_run.build_command(self.env, self.test_local_share_parent, version[1])
         self.assertIsInstance(
             test_command, tuple, "Expected a tuple from build_command"
         )
         self.assertEqual(
             len(test_command),
-            3,
+            8,
             f"Expected 3 elements, received {len(test_command)}",
         )
-        proton, verb, exe, *_ = [*test_command]
+        _, _, verb, _, _, proton, _, exe = [*test_command]
         self.assertIsInstance(proton, os.PathLike, "Expected proton to be PathLike")
         self.assertEqual(
             proton,
@@ -2136,6 +2155,107 @@ class TestGameLauncher(unittest.TestCase):
         self.assertEqual(verb, "waitforexitandrun", "Expected PROTON_VERB")
         self.assertEqual(exe, self.env["EXE"], "Expected EXE")
 
+    def test_build_command_nopv_noappid(self):
+        """Test build_command when disabling Pressure Vessel and the tool doesn't request a runtime.
+
+        UMU_NO_RUNTIME=1 disables Pressure Vessel, and the tool doesn't set
+        a runtime, allow the tool to run using the host's libraries as it expects.
+
+        Expects the list to contain 4 string elements.
+        """
+        result_args = None
+        test_command = []
+
+        # Mock the proton file
+        Path(self.test_file, "proton").touch()
+        # Mock a non-runtime toolmanifest.vdf
+        Path(self.test_file, "toolmanifest.vdf").write_text(
+            '''
+            "manifest"
+            {
+              "version" "2"
+              "commandline" "/proton %verb%"
+              "use_sessions" "1"
+              "compatmanager_layer_name" "proton"
+            }
+            '''
+        )
+
+        with (
+            patch("sys.argv", ["", self.test_exe]),
+            ThreadPoolExecutor() as thread_pool,
+        ):
+            os.environ["WINEPREFIX"] = self.test_file
+            os.environ["PROTONPATH"] = self.test_file
+            os.environ["GAMEID"] = self.test_file
+            os.environ["STORE"] = self.test_file
+            os.environ["UMU_NO_RUNTIME"] = "1"
+            version = umu_run.resolve_umu_version(self.test_runtime_versions)
+            os.environ["RUNTIMEPATH"] = version[1]
+            # Args
+            result_args = __main__.parse_args()
+            # Config
+            _, result_dl = umu_run.check_env(self.env)
+            if version[1] != "host":
+                umu_run.download_proton(result_dl, self.env, thread_pool)
+            # Prefix
+            umu_run.setup_pfx(self.env["WINEPREFIX"])
+            # Env
+            umu_run.set_env(self.env, result_args)
+            # Game drive
+            umu_run.enable_steam_game_drive(self.env)
+
+        # Mock setting up the runtime
+        with (
+            patch.object(umu_runtime, "_install_umu", return_value=None),
+        ):
+            umu_runtime.setup_umu(
+                self.test_local_share,
+                self.test_runtime_default,
+                self.test_session_pools,
+            )
+            copytree(
+                Path(self.test_user_share, "sniper_platform_0.20240125.75305"),
+                Path(self.test_local_share, "sniper_platform_0.20240125.75305"),
+                dirs_exist_ok=True,
+                symlinks=True,
+            )
+            copy(
+                Path(self.test_user_share, "run"),
+                Path(self.test_local_share, "run"),
+            )
+            copy(
+                Path(self.test_user_share, "run-in-sniper"),
+                Path(self.test_local_share, "run-in-sniper"),
+            )
+            copy(
+                Path(self.test_user_share, "umu"),
+                Path(self.test_local_share, "umu"),
+            )
+
+        os.environ |= self.env
+
+        # Build
+        test_command = umu_run.build_command(self.env, self.test_local_share_parent, version[1])
+        self.assertIsInstance(
+            test_command, tuple, "Expected a tuple from build_command"
+        )
+        self.assertEqual(
+            len(test_command),
+            4,
+            f"Expected 3 elements, received {len(test_command)}",
+        )
+        _, proton, verb, exe, *_ = [*test_command]
+        self.assertIsInstance(proton, os.PathLike, "Expected proton to be PathLike")
+        self.assertEqual(
+            proton,
+            Path(self.env["PROTONPATH"], "proton"),
+            "Expected PROTONPATH",
+        )
+        self.assertEqual(verb, "waitforexitandrun", "Expected PROTON_VERB")
+        self.assertEqual(exe, self.env["EXE"], "Expected EXE")
+
+
     def test_build_command_noproton(self):
         """Test build_command when $PROTONPATH/proton is not found.
 
@@ -2152,7 +2272,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["GAMEID"] = self.test_file
             os.environ["STORE"] = self.test_file
             os.environ["UMU_NO_RUNTIME"] = "pressure-vessel"
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             result_args = __main__.parse_args()
             # Config
@@ -2172,7 +2292,7 @@ class TestGameLauncher(unittest.TestCase):
 
         # Since we didn't create the proton file, an exception should be raised
         with self.assertRaises(FileNotFoundError):
-            umu_run.build_command(self.env, self.test_local_share, self.test_runtime_version[1])
+            umu_run.build_command(self.env, self.test_local_share, self.test_runtime_default[1])
 
     def test_build_command(self):
         """Test build command.
@@ -2201,7 +2321,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["PROTONPATH"] = self.test_file
             os.environ["GAMEID"] = self.test_file
             os.environ["STORE"] = self.test_file
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             result_args = __main__.parse_args()
             # Config
@@ -2223,7 +2343,7 @@ class TestGameLauncher(unittest.TestCase):
         ):
             umu_runtime.setup_umu(
                 self.test_local_share,
-                self.test_runtime_version,
+                self.test_runtime_default,
                 self.test_session_pools,
             )
             copytree(
@@ -2246,7 +2366,7 @@ class TestGameLauncher(unittest.TestCase):
             )
 
         # Build
-        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_version[1])
+        test_command = umu_run.build_command(self.env, self.test_local_share_parent, self.test_runtime_default[1])
         self.assertIsInstance(
             test_command, tuple, "Expected a tuple from build_command"
         )
@@ -2294,7 +2414,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["GAMEID"] = test_str
             os.environ["STORE"] = test_str
             os.environ["PROTON_VERB"] = self.test_verb
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             result = __main__.parse_args()
             # Check
@@ -2376,7 +2496,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["GAMEID"] = umu_id
             os.environ["STORE"] = test_str
             os.environ["PROTON_VERB"] = self.test_verb
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             result = __main__.parse_args()
             # Check
@@ -2454,7 +2574,7 @@ class TestGameLauncher(unittest.TestCase):
                 self.env["PROTONPATH"]
                 + ":"
                 + Path.home()
-                .joinpath(".local", "share", "umu", self.test_runtime_version[1])
+                .joinpath(".local", "share", "umu", self.test_runtime_default[1])
                 .as_posix(),
                 "Expected STEAM_COMPAT_TOOL_PATHS to be set",
             )
@@ -2485,7 +2605,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["GAMEID"] = test_str
             os.environ["STORE"] = test_str
             os.environ["PROTON_VERB"] = self.test_verb
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             result = __main__.parse_args()
             # Check
@@ -2571,7 +2691,7 @@ class TestGameLauncher(unittest.TestCase):
                 self.env["PROTONPATH"]
                 + ":"
                 + Path.home()
-                .joinpath(".local", "share", "umu", self.test_runtime_version[1])
+                .joinpath(".local", "share", "umu", self.test_runtime_default[1])
                 .as_posix(),
                 "Expected STEAM_COMPAT_TOOL_PATHS to be set",
             )
@@ -2602,7 +2722,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["STORE"] = test_str
             os.environ["PROTON_VERB"] = self.test_verb
             os.environ["UMU_RUNTIME_UPDATE"] = "0"
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             result = __main__.parse_args()
             # Check
@@ -2693,7 +2813,7 @@ class TestGameLauncher(unittest.TestCase):
                 self.env["PROTONPATH"]
                 + ":"
                 + Path.home()
-                .joinpath(".local", "share", "umu", self.test_runtime_version[1])
+                .joinpath(".local", "share", "umu", self.test_runtime_default[1])
                 .as_posix(),
                 "Expected STEAM_COMPAT_TOOL_PATHS to be set",
             )
@@ -2733,7 +2853,7 @@ class TestGameLauncher(unittest.TestCase):
             os.environ["PROTONPATH"] = test_dir.as_posix()
             os.environ["GAMEID"] = test_str
             os.environ["PROTON_VERB"] = proton_verb
-            os.environ["RUNTIMEPATH"] = self.test_runtime_version[1]
+            os.environ["RUNTIMEPATH"] = self.test_runtime_default[1]
             # Args
             result = __main__.parse_args()
             # Check
@@ -2823,7 +2943,7 @@ class TestGameLauncher(unittest.TestCase):
                 self.env["PROTONPATH"]
                 + ":"
                 + Path.home()
-                .joinpath(".local", "share", "umu", self.test_runtime_version[1])
+                .joinpath(".local", "share", "umu", self.test_runtime_default[1])
                 .as_posix(),
                 "Expected STEAM_COMPAT_TOOL_PATHS to be set",
             )
-- 
2.50.1


From 1b2a6d587762b410c0b9474b42b37a3f0fcad62e Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Fri, 21 Mar 2025 00:58:50 +0200
Subject: [PATCH 08/12] umu_run: do not set fault runtime path if case proton
 is using the host libraries

---
 umu/umu_run.py | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/umu/umu_run.py b/umu/umu_run.py
index c4e08b7..db712a4 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -232,14 +232,16 @@ def set_env(
     env["SteamGameId"] = env["SteamAppId"]
     env["UMU_INVOCATION_ID"] = token_hex(16)
 
+    runtime_path = f"{UMU_LOCAL}/{os.environ['RUNTIMEPATH']}" if os.environ['RUNTIMEPATH'] != "host" else ""
+
     # PATHS
     env["WINEPREFIX"] = str(pfx)
     env["PROTONPATH"] = str(protonpath)
     env["STEAM_COMPAT_DATA_PATH"] = env["WINEPREFIX"]
     env["STEAM_COMPAT_SHADER_PATH"] = f"{env['STEAM_COMPAT_DATA_PATH']}/shadercache"
-    env["STEAM_COMPAT_TOOL_PATHS"] = (
-        f"{env['PROTONPATH']}:{UMU_LOCAL}/{os.environ['RUNTIMEPATH']}"
-    )
+    env["STEAM_COMPAT_TOOL_PATHS"] = ":".join(
+        [f"{env['PROTONPATH']}", runtime_path]
+    ) if runtime_path else f"{env['PROTONPATH']}"
     env["STEAM_COMPAT_MOUNTS"] = env["STEAM_COMPAT_TOOL_PATHS"]
 
     # Zenity
@@ -258,7 +260,7 @@ def set_env(
     env["UMU_NO_RUNTIME"] = os.environ.get("UMU_NO_RUNTIME") or ""
     env["UMU_RUNTIME_UPDATE"] = os.environ.get("UMU_RUNTIME_UPDATE") or ""
     env["UMU_NO_PROTON"] = os.environ.get("UMU_NO_PROTON") or ""
-    env["RUNTIMEPATH"] = f"{UMU_LOCAL}/{os.environ['RUNTIMEPATH']}"
+    env["RUNTIMEPATH"] = runtime_path
 
     return env
 
@@ -792,7 +794,7 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
     }
     opts: list[str] = []
     prereq: bool = False
-    version: RuntimeVersion | None = None
+    runtime_version: RuntimeVersion | None = None
 
     log.info("umu-launcher version %s (%s)", __version__, sys.version)
 
@@ -840,13 +842,13 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
         opts = args[1]  # Reference the executable options
 
     # Resolve the runtime version for PROTONPATH
-    version = resolve_umu_version(__runtime_versions__)
-    if not version:
+    runtime_version = resolve_umu_version(__runtime_versions__)
+    if not runtime_version:
         err: str = (
             f"Failed to match '{os.environ.get('PROTONPATH')}' with a container runtime"
         )
         raise ValueError(err)
-    os.environ["RUNTIMEPATH"] = version[1]
+    os.environ["RUNTIMEPATH"] = runtime_version[1]
 
     # Opt to use the system's native CA bundle rather than certifi's
     with suppress(ModuleNotFoundError):
@@ -871,11 +873,11 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
         # Setup the launcher and runtime files
         _, do_download = check_env(env)
 
-        if version[1] != "host":
-            UMU_LOCAL.joinpath(version[1]).mkdir(parents=True, exist_ok=True)
+        if runtime_version[1] != "host":
+            UMU_LOCAL.joinpath(runtime_version[1]).mkdir(parents=True, exist_ok=True)
 
             future: Future = thread_pool.submit(
-                setup_umu, UMU_LOCAL / version[1], version, session_pools
+                setup_umu, UMU_LOCAL / runtime_version[1], runtime_version, session_pools
             )
 
             download_proton(do_download, env, session_pools)
@@ -915,7 +917,7 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
         sys.exit(1)
 
     # Build the command
-    command: tuple[Path | str, ...] = build_command(env, UMU_LOCAL, version[1], opts)
+    command: tuple[Path | str, ...] = build_command(env, UMU_LOCAL, runtime_version[1], opts)
     log.debug("%s", command)
 
     # Run the command
-- 
2.50.1


From 0ff6e61532d1e32c89afd78870671086f76965d4 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Fri, 21 Mar 2025 01:03:08 +0200
Subject: [PATCH 09/12] umu_run: make message clearer

---
 umu/umu_run.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/umu/umu_run.py b/umu/umu_run.py
index db712a4..e3e0965 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -745,7 +745,10 @@ def get_umu_version_from_manifest(
 
     if not appid:
         if os.environ.get("UMU_NO_RUNTIME", None) == "1":
-            log.warning("Runtime Platform disabled")
+            log.warning(
+                "Runtime Platform disabled. This mode is UNSUPPORTED by umu and remains only for convenience. "
+                "Issues created while using this mode will be automatically closed."
+            )
             return "host", "host", "host"
         return None
 
-- 
2.50.1


From 00aa3370777bac2dafecbd7c9ec5c057e746d09d Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Fri, 21 Mar 2025 20:05:49 +0200
Subject: [PATCH 10/12] doc: add documentation around UMU_NO_RUNTIME

---
 README.md      | 7 +++++++
 docs/umu.1.scd | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/README.md b/README.md
index 8b89827..287c7aa 100644
--- a/README.md
+++ b/README.md
@@ -84,6 +84,13 @@ Borderlands 3 from EGS store.
 3. In our umu unified database, we create a 'title' column, 'store' column, 'codename' column, 'umu-ID' column. We add a line for Borderlands 3 and fill in the details for each column.
 4. Now the launcher can search 'Catnip' and 'egs' as the codename and store in the database and correlate it with Borderlands 3 and umu-12345. It can then feed umu-12345 to the `umu-run` script.
 
+## Reporting issues
+
+When reporting issues for games that fail to run, be sure to attach a log with your issue report. To acquire a log from umu, add `UMU_LOG=1` to your environment variables for verbose logging. Furthermore, you can use `PROTON_LOG=1` for proton to create a verbose log in your `$HOME` directory. The log will be named `steam-<appid>.log`, where `<appid>` will be `default` if you haven't set a `GAMEID` or a number, depending on what you have set for `GAMEID`.
+
+Do **NOT** report issues when using `UMU_NO_RUNTIME=1`, this option is provided for convenience for compatibility tools that do not set their runtime requirements, such as Proton < `5.13`, and they do not work with any of the supported runtimes.
+This mode does not make use of a container runtime, and issues while using it are irrelevant to umu-launcher in general. Thus such issues will be automatically closed.
+
 ## Building
 
 Building umu-launcher currently requires `bash`, `make`, and `scdoc` for distribution, as well as the following Python build tools: [build](https://github.com/pypa/build), [hatchling](https://github.com/pypa/hatch), [installer](https://github.com/pypa/installer), and [pip](https://github.com/pypa/pip).
diff --git a/docs/umu.1.scd b/docs/umu.1.scd
index 40c3c69..2ab4f0e 100644
--- a/docs/umu.1.scd
+++ b/docs/umu.1.scd
@@ -179,6 +179,13 @@ _UMU_NO_PROTON_
 
 	Set _1_ to run the executable natively within the SLR.
 
+_UMU_NO_RUNTIME_
+	Optional. Allows for the configured compatibility tool to run outside of the Steam Linux Runtime.
+	This option is effective only if the compatibility tool doesn't require a runtime through its configuration.
+	On compatibility tools that require a runtime, this option is ignored.
+
+	Set _1_ to silence umu's error that it couldn't resolve a runtime to use, and run using the host's libraries.
+
 # SEE ALSO
 
 _umu_(5), _winetricks_(1), _zenity_(1)
-- 
2.50.1


From a63629dccd6e31875f4b85bb09866f7850234744 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Wed, 9 Apr 2025 11:22:33 +0300
Subject: [PATCH 11/12] umu_run: unpack runtime_version tuple instead of
 accessing by index

---
 umu/umu_run.py | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/umu/umu_run.py b/umu/umu_run.py
index e3e0965..274f45e 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -851,7 +851,9 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
             f"Failed to match '{os.environ.get('PROTONPATH')}' with a container runtime"
         )
         raise ValueError(err)
-    os.environ["RUNTIMEPATH"] = runtime_version[1]
+    # runtime_name, runtime_variant, runtime_appid
+    _, runtime_variant, _ = runtime_version
+    os.environ["RUNTIMEPATH"] = runtime_variant
 
     # Opt to use the system's native CA bundle rather than certifi's
     with suppress(ModuleNotFoundError):
@@ -876,11 +878,11 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
         # Setup the launcher and runtime files
         _, do_download = check_env(env)
 
-        if runtime_version[1] != "host":
-            UMU_LOCAL.joinpath(runtime_version[1]).mkdir(parents=True, exist_ok=True)
+        if runtime_variant != "host":
+            UMU_LOCAL.joinpath(runtime_variant).mkdir(parents=True, exist_ok=True)
 
             future: Future = thread_pool.submit(
-                setup_umu, UMU_LOCAL / runtime_version[1], runtime_version, session_pools
+                setup_umu, UMU_LOCAL / runtime_variant, runtime_version, session_pools
             )
 
             download_proton(do_download, env, session_pools)
@@ -920,7 +922,7 @@ def umu_run(args: Namespace | tuple[str, list[str]]) -> int:
         sys.exit(1)
 
     # Build the command
-    command: tuple[Path | str, ...] = build_command(env, UMU_LOCAL, runtime_version[1], opts)
+    command: tuple[Path | str, ...] = build_command(env, UMU_LOCAL, runtime_variant, opts)
     log.debug("%s", command)
 
     # Run the command
-- 
2.50.1


From 525cbe1c9ec74b2308d7a5d13108e811ba7e9f24 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas <loathingkernel@gmail.com>
Date: Sat, 7 Jun 2025 03:13:48 +0300
Subject: [PATCH 12/12] umu_run: don't require UMU_NO_RUNTIME to allow tools
 without a runtime to work

---
 umu/umu_run.py | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/umu/umu_run.py b/umu/umu_run.py
index 274f45e..be126ac 100755
--- a/umu/umu_run.py
+++ b/umu/umu_run.py
@@ -744,13 +744,8 @@ def get_umu_version_from_manifest(
                 break
 
     if not appid:
-        if os.environ.get("UMU_NO_RUNTIME", None) == "1":
-            log.warning(
-                "Runtime Platform disabled. This mode is UNSUPPORTED by umu and remains only for convenience. "
-                "Issues created while using this mode will be automatically closed."
-            )
-            return "host", "host", "host"
-        return None
+        os.environ["UMU_RUNTIME_UPDATE"] = "0"
+        return "host", "host", "host"
 
     if appid not in appids:
         return None
-- 
2.50.1

openSUSE Build Service is sponsored by