Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functionality to use winetricks #109

Merged
merged 39 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
80242c1
umu_proton: add proton class
R1kaB3rN Jun 5, 2024
08289ad
umu_util: add winetricks functionality
R1kaB3rN Jun 5, 2024
0f53c09
umu_run: add checks when using winetricks
R1kaB3rN Jun 5, 2024
79eb63c
umu_run: set environment variables for winetricks
R1kaB3rN Jun 5, 2024
1ae869b
umu_run: config winetricks to run unattended
R1kaB3rN Jun 5, 2024
93dad7f
umu_run: change directory when using winetricks
R1kaB3rN Jun 5, 2024
757ffe5
umu_run: fix exception when passing no winetricks verbs
R1kaB3rN Jun 5, 2024
232ef14
umu_run: set WINEDLLPATH
R1kaB3rN Jun 5, 2024
14c9807
umu_run: fix exit 3 status code for winetricks
R1kaB3rN Jun 5, 2024
06eb0ee
umu_run: delete winetricks and protonfix paths
R1kaB3rN Jun 5, 2024
09e9168
umu_run: update comments
R1kaB3rN Jun 5, 2024
2b43f99
umu_util: add missing type
R1kaB3rN Jun 5, 2024
a65d5e2
umu_run: fix not setting EXE and STEAM_COMPAT_INSTALL_PATH
R1kaB3rN Jun 5, 2024
d3e4a9e
umu_util: allow processing winetricks verbs in bulk
R1kaB3rN Jun 5, 2024
6e9c1f2
umu_run: update logic when swapping option and verb
R1kaB3rN Jun 5, 2024
b6b4f42
Ruff lint
R1kaB3rN Jun 5, 2024
5e6ea86
umu_run: respect order of winetricks verbs
R1kaB3rN Jun 5, 2024
b57ae57
umu_run: add winetricks as positional argument
R1kaB3rN Jun 6, 2024
0eddba4
umu_run: prefer surrounding verb with quotes
R1kaB3rN Jun 6, 2024
b40ffc2
umu_run: update comment
R1kaB3rN Jun 6, 2024
f67ad22
umu_run: prefer assigning a new list than list.insert
R1kaB3rN Jun 6, 2024
485ab42
umu_util: fix bug when parsing verbs
R1kaB3rN Jun 6, 2024
a329762
umu_util: update logic
R1kaB3rN Jun 6, 2024
e64e761
umu_util: rename function
R1kaB3rN Jun 6, 2024
46377e8
umu_util: add checks for is_installed_verb
R1kaB3rN Jun 6, 2024
f2cb4d4
umu_test: add test for is_installed_verb
R1kaB3rN Jun 6, 2024
29c0f2f
umu_test: add test for is_winetricks_verb
R1kaB3rN Jun 6, 2024
69afa9a
umu_test: add tests when passing winetricks as positional argument
R1kaB3rN Jun 6, 2024
4767f61
docs: add example of installing winetricks verbs
R1kaB3rN Jun 6, 2024
253c3d8
umu_util: fix logic when checking winetricks verbs
R1kaB3rN Jun 7, 2024
ab236c2
umu_util: refactor is_winetricks_verb to log messages
R1kaB3rN Jun 7, 2024
9256856
umu_run: remove error messages for winetricks
R1kaB3rN Jun 7, 2024
1d58834
umu_util: always process in bulk
R1kaB3rN Jun 7, 2024
6a35883
umu_util: always pass verbs as a list
R1kaB3rN Jun 7, 2024
3543a13
umu_test: update tests
R1kaB3rN Jun 7, 2024
56aa1f6
Ruff lint
R1kaB3rN Jun 7, 2024
e41393f
umu_util: fix AttributeError when checking winetricks verbs
R1kaB3rN Jun 7, 2024
40a832e
umu_test: update tests
R1kaB3rN Jun 7, 2024
1557909
docs: update example
R1kaB3rN Jun 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/umu.1.scd
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ $ WINEPREFIX=~/.wine GAMEID=0 PROTONPATH=GE-Proton9-1 umu-run ~/foo.exe
$ WINEPREFIX=~/.wine GAMEID=0 PROTONPATH=GE-Proton umu-run ~/foo.exe
```

*Example 11. Run winetricks verbs*

```
$ GAMEID=0 PROTONPATH=GE-Proton umu-run winetricks quartz wmp11 qasf
```

# SEE ALSO

_umu_(5)
Expand Down
18 changes: 18 additions & 0 deletions umu/umu_proton.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@
tar_filter: Callable[[str, str], TarInfo] = None


class Proton:
"""Model paths to relevant files and directories for Proton."""

def __init__(self, base_dir: str) -> None: # noqa: D107
self.base_dir = base_dir + "/"
self.dist_dir = self.path("files/")
self.bin_dir = self.path("files/bin/")
self.lib_dir = self.path("files/lib/")
self.lib64_dir = self.path("files/lib64/")
self.version_file = self.path("version")
self.wine_bin = self.bin_dir + "wine"
self.wine64_bin = self.bin_dir + "wine64"
self.wineserver_bin = self.bin_dir + "wineserver"

def path(self, dir: str) -> str: # noqa: D102
return self.base_dir + dir


def get_umu_proton(
env: dict[str, str], thread_pool: ThreadPoolExecutor
) -> dict[str, str]:
Expand Down
80 changes: 75 additions & 5 deletions umu/umu_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
)
from umu_log import CustomFormatter, console_handler, log
from umu_plugins import set_env_toml
from umu_proton import get_umu_proton
from umu_proton import Proton, get_umu_proton
from umu_runtime import setup_umu
from umu_util import get_libc
from umu_util import get_libc, is_installed_verb, is_winetricks_verb

THREAD_POOL: ThreadPoolExecutor = ThreadPoolExecutor()

Expand All @@ -46,11 +46,30 @@ def parse_args() -> Namespace | tuple[str, list[str]]: # noqa: D103
parser.add_argument(
"--config", help=("path to TOML file (requires Python 3.11+)")
)
parser.add_argument(
"winetricks",
help=("run winetricks (requires UMU-Proton or GE-Proton)"),
nargs="?",
default=None,
)

if not sys.argv[1:]:
parser.print_help(sys.stderr)
sys.exit(1)

# Winetricks
# Exit if no winetricks verbs were passed
if sys.argv[1].endswith("winetricks") and not sys.argv[2:]:
err: str = "No winetricks verb specified"
log.error(err)
sys.exit(1)

# Exit if argument is not a verb
if sys.argv[1].endswith("winetricks") and not is_winetricks_verb(
sys.argv[2:]
):
sys.exit(1)

if sys.argv[1:][0] in opt_args:
return parser.parse_args(sys.argv[1:])

Expand Down Expand Up @@ -80,8 +99,6 @@ def set_log() -> None:
log.addHandler(console_handler)
log.setLevel(level=DEBUG)

os.environ.pop("UMU_LOG")


def setup_pfx(path: str) -> None:
"""Create a symlink to the WINE prefix and tracked_files file."""
Expand Down Expand Up @@ -203,6 +220,21 @@ def set_env(
env["EXE"] = ""
env["STEAM_COMPAT_INSTALL_PATH"] = ""
env["PROTON_VERB"] = "waitforexitandrun"
elif isinstance(args, tuple) and args[0] == "winetricks":
# Make an absolute path to winetricks that is within GE-Proton or
# UMU-Proton, which includes the dependencies bundled within the
# protonfixes directory. Fixes exit 3 status codes after applying
# winetricks verbs
bin: str = (
Path(env["PROTONPATH"], "protonfixes", "winetricks")
.expanduser()
.resolve(strict=True)
.as_posix()
)
log.debug("EXE: %s -> %s", args[0], bin)
args: tuple[str, list[str]] = (bin, args[1])
env["EXE"] = bin
env["STEAM_COMPAT_INSTALL_PATH"] = Path(env["EXE"]).parent.as_posix()
elif isinstance(args, tuple):
try:
env["EXE"] = (
Expand Down Expand Up @@ -257,6 +289,24 @@ def set_env(
# Game drive
enable_steam_game_drive(env)

# Winetricks
if env.get("EXE").endswith("winetricks"):
proton: Proton = Proton(os.environ["PROTONPATH"])
env["WINE"] = proton.wine_bin
env["WINELOADER"] = proton.wine_bin
env["WINESERVER"] = proton.wineserver_bin
env["WINETRICKS_LATEST_VERSION_CHECK"] = "disabled"
env["LD_PRELOAD"] = ""
env["WINEDLLPATH"] = ":".join(
[
Path(proton.lib_dir, "wine").as_posix(),
Path(proton.lib64_dir, "wine").as_posix(),
]
)
env["WINETRICKS_SUPER_QUIET"] = (
"" if os.environ.get("UMU_LOG") == "debug" else "1"
)

return env


Expand Down Expand Up @@ -338,6 +388,12 @@ def build_command(
err: str = "The following file was not found in PROTONPATH: proton"
raise FileNotFoundError(err)

# Configure winetricks to not be prompted for any windows
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]

if opts:
command.extend(
[
Expand Down Expand Up @@ -378,6 +434,7 @@ def run_command(command: list[str]) -> int:
proc: Popen = None
ret: int = 0
libc: str = get_libc()
cwd: str = ""

if not command:
err: str = f"Command list is empty or None: {command}"
Expand All @@ -386,6 +443,12 @@ def run_command(command: list[str]) -> int:
if not libc:
log.warning("Will not set subprocess as subreaper")

# For winetricks, change directory to $PROTONPATH/protonfixes
if os.environ.get("EXE").endswith("winetricks"):
cwd = Path(os.environ.get("PROTONPATH"), "protonfixes").as_posix()
else:
cwd = Path.cwd().as_posix()

# Create a subprocess but do not set it as subreaper
# Unnecessary in a Flatpak and prctl() will fail if libc could not be found
if FLATPAK_PATH or not libc:
Expand All @@ -408,6 +471,7 @@ def run_command(command: list[str]) -> int:
command,
start_new_session=True,
preexec_fn=lambda: prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0, 0),
cwd=cwd,
)
ret = proc.wait()
log.debug("Child %s exited with wait status: %s", proc.pid, ret)
Expand Down Expand Up @@ -441,7 +505,7 @@ def main() -> int: # noqa: D103
"UMU_ZENITY": "",
}
command: list[str] = []
opts: list[str] = None
opts: list[str] = []
root: Path = Path(__file__).resolve(strict=True).parent
future: Future = None
args: Namespace | tuple[str, list[str]] = parse_args()
Expand Down Expand Up @@ -519,6 +583,12 @@ def main() -> int: # noqa: D103
future.result()
THREAD_POOL.shutdown()

# Exit if the winetricks verb is already installed to avoid reapplying it
if env.get("EXE").endswith("winetricks") and is_installed_verb(
opts, Path(env.get("WINEPREFIX"))
):
sys.exit(1)

# Run
build_command(env, UMU_LOCAL, command, opts)
log.debug("%s", command)
Expand Down
Loading