diff --git a/src/mo2-lint/command/install.py b/src/mo2-lint/command/install.py index 426c81b..7cadc95 100644 --- a/src/mo2-lint/command/install.py +++ b/src/mo2-lint/command/install.py @@ -9,7 +9,7 @@ from util.nexus.install_handler import install as install_handler from step.workarounds import apply_workarounds from step.load_game_info import get_launcher, get_library -from step.external_resources import download +from step.external_resources import download, download_winetricks from step.configure_prefix import prompt as configure_prefix from step.launch_opt import add_launch_opt @@ -66,6 +66,7 @@ def install( ) raise SystemExit(1) + download_winetricks() configure_prefix() download() install_handler() diff --git a/src/mo2-lint/step/external_resources.py b/src/mo2-lint/step/external_resources.py index 9db406d..7c37117 100644 --- a/src/mo2-lint/step/external_resources.py +++ b/src/mo2-lint/step/external_resources.py @@ -8,16 +8,15 @@ from urllib.request import urlopen, Request from util import lang, variables as var, state_file as state from util.checksum import compare_checksum -from util.download import download as dl, download_nexus as nexus_dl +from util.download import download as dl, download_nexus as nexus_dl, download_dir from util.state_file import symlink_instance +from util.wine.winetricks import winetricks_path import json import ssl import certifi ssl_context = ssl.create_default_context(cafile=certifi.where()) -cache_dir: Path = Path("~/.cache/mo2-lint").expanduser() -download_dir = cache_dir / "downloads" extract_dir = download_dir / "extracted" @@ -62,6 +61,9 @@ def download_winetricks(): """ Runs the download process for Winetricks. """ + if str(winetricks_path) != str(download_dir / "winetricks"): + logger.info("Using provided Winetricks. Skipping download") + return logger.info("Starting download process for Winetricks") url = var.resource_info.winetricks.download_url checksum = var.resource_info.winetricks.checksum @@ -385,7 +387,6 @@ def download(): """ Runs the download process for all required external resources. """ - cache_dir.mkdir(parents=True, exist_ok=True) params = var.input_params game_info = var.game_info script_extenders = game_info.script_extenders if game_info is not None else None @@ -395,7 +396,6 @@ def download(): if params.plugins: for plugin in params.plugins: download_plugin(plugin) - download_winetricks() if params.script_extender: for entry in script_extenders or []: match = False diff --git a/src/mo2-lint/util/download.py b/src/mo2-lint/util/download.py index 8792e87..7c6b919 100644 --- a/src/mo2-lint/util/download.py +++ b/src/mo2-lint/util/download.py @@ -9,6 +9,8 @@ import certifi ssl_context = ssl.create_default_context(cafile=certifi.where()) +cache_dir: Path = Path("~/.cache/mo2-lint").expanduser() +download_dir = cache_dir / "downloads" def download( diff --git a/src/mo2-lint/util/wine/protontricks.py b/src/mo2-lint/util/wine/protontricks.py index 101c323..11c0bf9 100644 --- a/src/mo2-lint/util/wine/protontricks.py +++ b/src/mo2-lint/util/wine/protontricks.py @@ -4,13 +4,21 @@ from loguru import logger from pathlib import Path from protontricks.cli.main import main as pt -from typing import List from shared.logger import remove_loggers, add_loggers +from typing import List +from util.wine.winetricks import winetricks_path, cached_winetricks import os import re import sys import threading +winetricks_str = str(winetricks_path) +if winetricks_str == str(cached_winetricks): + logger.debug("setting WINETRICKS") + os.environ["WINETRICKS"] = winetricks_str +else: + logger.debug("not setting WINETRICKS") + def run(command: List[str]) -> List[str]: """ diff --git a/src/mo2-lint/util/wine/winetricks.py b/src/mo2-lint/util/wine/winetricks.py index c59bde0..f3578df 100644 --- a/src/mo2-lint/util/wine/winetricks.py +++ b/src/mo2-lint/util/wine/winetricks.py @@ -2,20 +2,30 @@ from loguru import logger from pathlib import Path -from typing import List, Optional +from typing import List from shared.logger import remove_loggers, add_loggers +from util.download import download_dir import os import re import shutil import subprocess -found_exec = shutil.which("winetricks") or "~/.cache/mo2-lint/downloads/winetricks" +cached_winetricks = download_dir / "winetricks" +found_exec = shutil.which("winetricks") +# Try to use $WINETRICKS, only if it provides a file +winetricks_path = os.environ.get("WINETRICKS") +if winetricks_path: + winetricks_path = Path(winetricks_path).expanduser() +elif found_exec: + winetricks_path = Path(found_exec) +else: + winetricks_path = cached_winetricks def run( - exec: Optional[Path | str] = found_exec, - prefix: Path = None, - command: List[str] = None, + exe: Path | str = winetricks_path, + prefix: Path | str = None, + command: List[str] = [], ) -> List[str]: """ Runs a winetricks command and captures its output. @@ -33,34 +43,33 @@ def run( The output lines from the winetricks command. """ + if not isinstance(exe, (str, Path)): + raise TypeError("exe parameter must be a Path or string") + if not isinstance(prefix, (str, Path)): + raise TypeError("prefix parameter must be a Path or string") + if not isinstance(command, list): + raise TypeError("command parameter must be a list") + if isinstance(exe, str): + exe = Path(exe) + exe = exe.expanduser().resolve() + if isinstance(prefix, str): + prefix = Path(prefix) prefix = prefix.expanduser().resolve() - exec = ( - exec.expanduser().resolve() - if isinstance(exec, Path) - else str(exec.expanduser().resolve()) - ) - - # Convert executable to string, with absolute path - if str(exec).startswith("/usr/bin"): - if isinstance(exec, str): - exec = str(Path(exec).name) - elif isinstance(exec, Path): - exec = str(exec.name) - elif isinstance(exec, str): - if not Path(exec).exists(): - logger.error(f"Winetricks executable not found at specified path: {exec}") - return [] - exec = exec - elif isinstance(exec, Path): - if not exec.exists(): - logger.error(f"Winetricks executable not found at specified path: {exec}") + + if exe.is_relative_to("/usr/bin"): + # If referring to winetricks by bare name when possible is correct behavior, then it should + # probably be done whenever bool(found_exec), not just when it was found in /usr/bin? + exe = str(exe.name) + else: + if not exe.exists(): + logger.error(f"Winetricks executable not found at specified path: {exe}") return [] - exec = str(exec) - logger.info(f"Using winetricks executable: {exec}") + exe = str(exe) + logger.info(f"Using winetricks executable: {exe}") - command = ["-q", "-f"] + command # -q for unattended, -f to force - cmd = [exec] + command + cmd = ["-q", "-f"] + command # -q for unattended, -f to force logger.debug(f"Constructed winetricks command: {' '.join(cmd)}") + cmd.insert(exe) env = os.environ.copy() env.setdefault("WINEPREFIX", str(prefix)) logger.trace(f"Using Wine prefix: {prefix}") @@ -69,7 +78,7 @@ def run( add_loggers(script="mo2-lint", process="winetricks") output_lines = [] - if not cmd == [exec, "-q", "-f"]: + if not cmd == [exe, "-q", "-f"]: proc = subprocess.Popen( cmd, stdout=subprocess.PIPE, @@ -100,9 +109,8 @@ def run( def apply( - exec: Optional[Path | str] = found_exec, - prefix: Path = None, - tricks: List[str] = None, + prefix: Path, + tricks: List[str], ): """ Applies tricks to the specified prefix. @@ -119,7 +127,7 @@ def apply( logger.warning("No tricks provided to apply, skipping winetricks execution.") return logger.info(f"Applying tricks to prefix with winetricks: {tricks}") - run(exec, prefix, tricks) + run(prefix=prefix, tricks=tricks) def log_translation(input: str = None):