diff --git a/umu/umu_dl_util.py b/umu/umu_dl_util.py index ff53afd13..f412a138f 100644 --- a/umu/umu_dl_util.py +++ b/umu/umu_dl_util.py @@ -25,9 +25,6 @@ def get_umu_proton(env: Dict[str, str]) -> Union[Dict[str, str]]: Downloads the latest if not first found in: ~/.local/share/Steam/compatibilitytools.d - - The cache directory ~/.cache/umu is referenced for the latest then as - fallback """ files: List[Tuple[str, str]] = [] tmp: Path = Path(mkdtemp()) @@ -124,6 +121,7 @@ def _fetch_proton( hash, hash_url = files[0] proton, proton_url = files[1] proton_dir: str = proton[: proton.find(".tar.gz")] # Proton dir + ret: int = 0 # Exit code from zenity log.console(f"Downloading {hash} ...") @@ -147,8 +145,8 @@ def _fetch_proton( file.write(resp.read()) # Proton - # Check for Zenity otherwise print - try: + # Create a popup with zenity when the env var is set + if environ.get("UMU_ZENITY") == "1": bin: str = "curl" opts: List[str] = [ "-LJO", @@ -157,18 +155,18 @@ def _fetch_proton( "--output-dir", tmp.as_posix(), ] - msg: str = f"Downloading {proton_dir} ..." - enable_zenity(bin, opts, msg) - except TimeoutError: - err: str = f"Unable to download {proton}\ngithub.com request timed out" - raise TimeoutError(err) - except FileNotFoundError: + ret = enable_zenity(bin, opts, msg) + if ret: + tmp.joinpath(proton).unlink(missing_ok=True) + log.warning("zenity exited with the status code: %s", ret) + log.console("Retrying from Python ...") + if not environ.get("UMU_ZENITY") or ret: log.console(f"Downloading {proton} ...") - - with urlopen(proton_url, timeout=180, context=create_default_context()) as resp: # noqa: S310 + with urlopen( # noqa: S310 + proton_url, timeout=300, context=create_default_context() + ) as resp: # Without Proton, the launcher will not work - # Continue by referring to cache if resp.status != 200: err: str = ( f"Unable to download {proton}\n" @@ -185,7 +183,8 @@ def _fetch_proton( sha512(file.read()).hexdigest() != tmp.joinpath(hash).read_text().split(" ")[0] ): - err: str = "Digests mismatched.\nFalling back to cache ..." + err: str = "Digests mismatched" + log.warning(err) raise ValueError(err) log.console(f"{proton}: SHA512 is OK") @@ -196,9 +195,9 @@ def _fetch_proton( return env -def _extract_dir(proton: Path, steam_compat: Path) -> None: +def _extract_dir(file: Path, steam_compat: Path) -> None: """Extract from the cache to another location.""" - with tar_open(proton.as_posix(), "r:gz") as tar: + with tar_open(file.as_posix(), "r:gz") as tar: if tar_filter: log.debug("Using filter for archive") tar.extraction_filter = tar_filter @@ -206,23 +205,23 @@ def _extract_dir(proton: Path, steam_compat: Path) -> None: log.debug("Using no filter for archive") log.warning("Archive will be extracted insecurely") - log.console(f"Extracting {proton} -> {steam_compat} ...") + log.console(f"Extracting {file} -> {steam_compat} ...") # TODO: Rather than extracting all of the contents, we should prefer # the difference (e.g., rsync) tar.extractall(path=steam_compat.as_posix()) # noqa: S202 log.console("Completed.") -def _cleanup(tarball: str, proton: str, cache: Path, steam_compat: Path) -> None: +def _cleanup(tarball: str, proton: str, tmp: Path, steam_compat: Path) -> None: """Remove files that may have been left in an incomplete state to avoid corruption. We want to do this when a download for a new release is interrupted """ log.console("Keyboard Interrupt.\nCleaning ...") - if cache.joinpath(tarball).is_file(): - log.console(f"Purging {tarball} in {cache} ...") - cache.joinpath(tarball).unlink() + if tmp.joinpath(tarball).is_file(): + log.console(f"Purging {tarball} in {tmp} ...") + tmp.joinpath(tarball).unlink() if steam_compat.joinpath(proton).is_dir(): log.console(f"Purging {proton} in {steam_compat} ...") rmtree(steam_compat.joinpath(proton).as_posix()) diff --git a/umu/umu_plugins.py b/umu/umu_plugins.py index d49da16d9..fa5035fe2 100644 --- a/umu/umu_plugins.py +++ b/umu/umu_plugins.py @@ -180,6 +180,7 @@ def enable_zenity(command: str, opts: List[str], msg: str) -> int: f"--text={msg}", "--percentage=0", "--pulsate", + "--no-cancel", ], stdin=PIPE, ) as zenity_proc, diff --git a/umu/umu_run.py b/umu/umu_run.py index 11041f53b..39c91d3cd 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -278,6 +278,7 @@ def main() -> int: # noqa: D103 "PROTON_VERB": "", "UMU_ID": "", "ULWGL_ID": "", + "UMU_ZENITY": "", } command: List[str] = [] opts: List[str] = None diff --git a/umu/umu_util.py b/umu/umu_util.py index 0f755752e..d0effd2bb 100644 --- a/umu/umu_util.py +++ b/umu/umu_util.py @@ -1,5 +1,5 @@ from tarfile import open as tar_open, TarInfo -from os import getuid +from os import getuid, environ from umu_consts import CONFIG, STEAM_COMPAT, UMU_LOCAL from typing import Any, Dict, List, Callable from json import load, dump @@ -72,46 +72,35 @@ def setup_runtime(json: Dict[str, Any]) -> None: # noqa: D103 # Step 1: Define the URL of the file to download # We expect the archive name to not change base_url: str = f"https://repo.steampowered.com/steamrt3/images/{version}/{archive}" + bin: str = "curl" + opts: List[str] = [ + "-LJO", + "--silent", + f"{base_url}", + "--output-dir", + tmp.as_posix(), + ] + ret: int = 0 # Exit code from zenity + log.debug("URL: %s", base_url) # Download the runtime - # Attempt to create a popup with zenity otherwise print - try: - bin: str = "curl" - opts: List[str] = [ - "-LJO", - "--silent", - base_url, - "--output-dir", - tmp.as_posix(), - ] - - msg: str = "Downloading Runtime, please wait..." + # Optionally create a popup with zenity + if environ.get("UMU_ZENITY") == "1": + msg: str = "Downloading UMU-Runtime ..." ret: int = enable_zenity(bin, opts, msg) - - # Handle the symbol lookup error from the zenity flatpak in lutris if ret: - log.warning("zenity exited with the status code: %s", ret) - log.warning("zenity will not be used") tmp.joinpath(archive).unlink(missing_ok=True) - raise FileNotFoundError - except TimeoutError: - # Without the runtime, the launcher will not work - # Just exit on timeout or download failure - err: str = ( - "Unable to download the Steam Runtime\n" - "repo.steampowered.com request timed out " - "or timeout limit was reached" - ) - raise TimeoutError(err) - except FileNotFoundError: - log.console(f"Downloading {runtime_platform_value} ...") - - # We hardcode the URL and trust it - with urlopen(base_url, timeout=60, context=create_default_context()) as resp: # noqa: S310 + log.warning("zenity exited with the status code: %s", ret) + log.console("Retrying from Python ...") + if not environ.get("UMU_ZENITY") or ret: + log.console(f"Downloading {runtime_platform_value}, please wait ...") + with urlopen( # noqa: S310 + base_url, timeout=300, context=create_default_context() + ) as resp: if resp.status != 200: err: str = ( - "Unable to download the Steam Runtime\n" + f"Unable to download {hash}\n" f"repo.steampowered.com returned the status: {resp.status}" ) raise HTTPException(err) @@ -225,11 +214,11 @@ def _install_umu( local.mkdir(parents=True, exist_ok=True) # Config - log.console(f"Copying {CONFIG} -> {local} ...") + log.console(f"Copied {CONFIG} -> {local}") copy(root.joinpath(CONFIG), local.joinpath(CONFIG)) # Reaper - log.console(f"Copying reaper -> {local} ...") + log.console(f"Copied reaper -> {local}") copy(root.joinpath("reaper"), local.joinpath("reaper")) # Runtime platform @@ -239,7 +228,7 @@ def _install_umu( # Launcher files for file in root.glob("*.py"): if not file.name.startswith("umu_test"): - log.console(f"Copying {file} -> {local} ...") + log.console(f"Copied {file} -> {local}") copy(file, local.joinpath(file.name)) local.joinpath("umu-run").symlink_to("umu_run.py") @@ -247,7 +236,7 @@ def _install_umu( # Runner steam_compat.mkdir(parents=True, exist_ok=True) - log.console(f"Copying umu-launcher -> {steam_compat} ...") + log.console(f"Copied umu-launcher -> {steam_compat}") # Remove existing files if they exist -- this is a clean install. if steam_compat.joinpath("umu-launcher").is_dir():