Refactor check_output usage + remove disks module + move terminal functions to linux module

This commit is contained in:
Mathieu Comandon 2021-06-04 15:44:06 -07:00
parent 9938a856c4
commit d4324b9646
23 changed files with 147 additions and 187 deletions

View file

@ -21,7 +21,7 @@ from lutris.exceptions import GameConfigError, watch_lutris_errors
from lutris.gui import dialogs
from lutris.runner_interpreter import export_bash_script, get_launch_parameters
from lutris.runners import InvalidRunner, import_runner, wine
from lutris.util import audio, jobs, strings, system, xdgshortcuts
from lutris.util import audio, jobs, linux, strings, system, xdgshortcuts
from lutris.util.display import (
DISPLAY_MANAGER, SCREEN_SAVER_INHIBITOR, disable_compositing, enable_compositing, restore_gamma
)
@ -293,7 +293,7 @@ class Game(GObject.Object):
if runtime_updater.is_updating():
logger.warning("Runtime updates: %s", runtime_updater.current_updates)
dialogs.ErrorDialog(_("Runtime currently updating"), _("Game might not work as expected"))
if ("wine" in self.runner_name and not wine.get_system_wine_version() and not LINUX_SYSTEM.is_flatpak):
if ("wine" in self.runner_name and not wine.get_wine_version() and not LINUX_SYSTEM.is_flatpak):
# TODO find a reference to the root window or better yet a way not
# to have Gtk dependent code in this class.
root_window = None
@ -375,7 +375,7 @@ class Game(GObject.Object):
Remember that only games using text mode should use the terminal.
"""
if self.runner.system_config.get("terminal"):
terminal = self.runner.system_config.get("terminal_app", system.get_default_terminal())
terminal = self.runner.system_config.get("terminal_app", linux.get_default_terminal())
if terminal and not system.find_executable(terminal):
raise GameConfigError(_("The selected terminal application could not be launched:\n%s") % terminal)
return terminal

View file

@ -3,12 +3,12 @@ from gettext import gettext as _
from gi.repository import GObject, Gtk
from lutris import runners
from lutris.util.log import logger
from lutris.gui.config.runner import RunnerConfigDialog
from lutris.gui.dialogs import ErrorDialog, QuestionDialog
from lutris.gui.dialogs.download import simple_downloader
from lutris.gui.dialogs.runner_install import RunnerInstallDialog
from lutris.gui.widgets.utils import ICON_SIZE, get_icon
from lutris.util.log import logger
class RunnerBox(Gtk.Box):

View file

@ -14,7 +14,7 @@ from lutris.cache import get_cache_path
from lutris.command import MonitoredCommand
from lutris.installer.errors import ScriptingError
from lutris.runners import import_task
from lutris.util import disks, extract, selective_merge, system
from lutris.util import extract, linux, selective_merge, system
from lutris.util.fileio import EvilConfigParser, MultiOrderedDict
from lutris.util.log import logger
from lutris.util.wine.wine import WINE_DEFAULT_ARCH, get_wine_version_exe
@ -131,7 +131,7 @@ class CommandsMixin:
raise ScriptingError("Unable to find executable %s" % file_ref)
if terminal:
terminal = system.get_default_terminal()
terminal = linux.get_default_terminal()
if not working_dir or not os.path.exists(working_dir):
working_dir = self.target_path
@ -223,7 +223,7 @@ class CommandsMixin:
if extra_path:
drives = [extra_path]
else:
drives = disks.get_mounted_discs()
drives = system.get_mounted_discs()
for drive in drives:
required_abspath = os.path.join(drive, requires)
required_abspath = system.fix_path_case(required_abspath)

View file

@ -20,7 +20,7 @@ from lutris.util.display import DISPLAY_MANAGER
from lutris.util.jobs import AsyncCall
from lutris.util.log import logger
from lutris.util.strings import unpack_dependencies
from lutris.util.wine.wine import get_system_wine_version, get_wine_version_exe
from lutris.util.wine.wine import get_wine_version, get_wine_version_exe
class ScriptInterpreter(GObject.Object, CommandsMixin):
@ -233,7 +233,7 @@ class ScriptInterpreter(GObject.Object, CommandsMixin):
logger.info("Runner %s needs to be installed", runner)
runners_to_install.append(runner)
if self.installer.runner.startswith("wine") and not get_system_wine_version():
if self.installer.runner.startswith("wine") and not get_wine_version():
WineNotInstalledWarning(parent=self.parent)
return runners_to_install

View file

@ -1,4 +1,4 @@
from lutris.util import system
from lutris.util import linux
def get_game_launcher(script):
@ -8,7 +8,7 @@ def get_game_launcher(script):
added.
"""
launcher_value = None
exe = "exe64" if "exe64" in script and system.LINUX_SYSTEM.is_64_bit else "exe"
exe = "exe64" if "exe64" in script and linux.LINUX_SYSTEM.is_64_bit else "exe"
for launcher in (exe, "iso", "rom", "disk", "main_file"):
if launcher not in script:
continue

View file

@ -8,7 +8,7 @@ from lutris import runtime, settings
from lutris.command import MonitoredCommand
from lutris.config import LutrisConfig
from lutris.runners import import_runner
from lutris.util import system
from lutris.util import linux, system
from lutris.util.log import logger
from lutris.util.shell import get_shell_command
from lutris.util.strings import split_arguments
@ -408,5 +408,5 @@ def open_wine_terminal(terminal, wine_path, prefix, env):
}
env["WINEPREFIX"] = prefix
shell_command = get_shell_command(prefix, env, aliases)
terminal = terminal or system.get_default_terminal()
system.execute([system.get_default_terminal(), "-e", shell_command])
terminal = terminal or linux.get_default_terminal()
system.execute([linux.get_default_terminal(), "-e", shell_command])

View file

@ -316,7 +316,7 @@ class Runner: # pylint: disable=too-many-public-methods
return
versions = runner_info.get("versions") or []
arch = system.LINUX_SYSTEM.arch
arch = LINUX_SYSTEM.arch
if version:
if version.endswith("-i386") or version.endswith("-x86_64"):
version, arch = version.rsplit("-", 1)
@ -329,9 +329,9 @@ class Runner: # pylint: disable=too-many-public-methods
default_version = [v for v in versions_for_arch if v["default"] is True]
if default_version:
return default_version[0]
elif len(versions) == 1 and system.LINUX_SYSTEM.is_64_bit:
elif len(versions) == 1 and LINUX_SYSTEM.is_64_bit:
return versions[0]
elif len(versions) > 1 and system.LINUX_SYSTEM.is_64_bit:
elif len(versions) > 1 and LINUX_SYSTEM.is_64_bit:
default_version = [v for v in versions if v["default"] is True]
if default_version:
return default_version[0]

View file

@ -1,15 +1,13 @@
"""Steam for Linux runner"""
# Standard Library
import os
import subprocess
import time
from gettext import gettext as _
# Lutris Modules
from lutris.command import MonitoredCommand
from lutris.runners import NonInstallableRunnerError
from lutris.runners.runner import Runner
from lutris.util import system
from lutris.util import linux, system
from lutris.util.log import logger
from lutris.util.steam.appmanifest import get_appmanifest_from_appid, get_path_from_appmanifest
from lutris.util.steam.config import STEAM_DATA_DIRS, get_default_acf, get_steam_dir, read_config
@ -136,7 +134,7 @@ class steam(Runner):
@property
def runnable_alone(self):
return not system.LINUX_SYSTEM.is_flatpak
return not linux.LINUX_SYSTEM.is_flatpak
@property
def appid(self):
@ -175,7 +173,7 @@ class steam(Runner):
return appmanifests[0]
def get_executable(self):
if system.LINUX_SYSTEM.is_flatpak:
if linux.LINUX_SYSTEM.is_flatpak:
# Use xdg-open for Steam URIs in Flatpak
return system.find_executable("xdg-open")
if self.runner_config.get("lsi_steam") and system.find_executable("lsi-steam"):
@ -198,7 +196,7 @@ class steam(Runner):
def launch_args(self):
"""Provide launch arguments for Steam"""
args = [self.get_executable()]
if system.LINUX_SYSTEM.is_flatpak:
if linux.LINUX_SYSTEM.is_flatpak:
return args
if self.runner_config.get("start_in_big_picture"):
args.append("-bigpicture")
@ -309,8 +307,7 @@ class steam(Runner):
command = [binary_path]
else:
# Start through steam
if system.LINUX_SYSTEM.is_flatpak:
if linux.LINUX_SYSTEM.is_flatpak:
if game_args:
steam_uri = "steam://run/%s//%s/" % (self.appid, game_args)
else:

View file

@ -7,7 +7,7 @@ from urllib.parse import urlparse
from lutris import settings
from lutris.database.games import get_game_by_field
from lutris.runners.runner import Runner
from lutris.util import datapath, resources, system
from lutris.util import datapath, linux, resources, system
from lutris.util.strings import split_arguments
DEFAULT_ICON = os.path.join(datapath.get(), "media/default_icon.png")
@ -258,7 +258,7 @@ class web(Runner):
if self.runner_config.get("user_agent"):
command.append("--user-agent")
command.append(self.runner_config.get("user_agent"))
if system.LINUX_SYSTEM.is_flatpak:
if linux.LINUX_SYSTEM.is_flatpak:
command.append("--no-sandbox")
return {"command": command, "env": self.get_env(False)}

View file

@ -26,8 +26,8 @@ from lutris.util.wine.prefix import DEFAULT_DLL_OVERRIDES, WinePrefixManager, fi
from lutris.util.wine.wine import (
POL_PATH, WINE_DIR, WINE_PATHS, detect_arch, display_vulkan_error, esync_display_limit_warning,
esync_display_version_warning, fsync_display_support_warning, fsync_display_version_warning, get_default_version,
get_overrides_env, get_proton_paths, get_real_executable, get_system_wine_version, get_wine_versions,
is_esync_limit_set, is_fsync_supported, is_gstreamer_build, is_version_esync, is_version_fsync
get_overrides_env, get_proton_paths, get_real_executable, get_wine_version, get_wine_versions, is_esync_limit_set,
is_fsync_supported, is_gstreamer_build, is_version_esync, is_version_fsync
)
from lutris.util.wine.x360ce import X360ce
@ -123,7 +123,7 @@ class wine(Runner):
versions = get_wine_versions()
for version in versions:
if version in labels.keys():
version_number = get_system_wine_version(WINE_PATHS[version])
version_number = get_wine_version(WINE_PATHS[version])
label = labels[version].format(version_number)
else:
label = version

View file

@ -1,10 +1,9 @@
# Standard Library
import os
from gettext import gettext as _
# Lutris Modules
from lutris.runners.runner import Runner
from lutris.util import display, system
from lutris.util.linux import LINUX_SYSTEM
from lutris.util.log import logger
from lutris.util.strings import split_arguments
@ -107,7 +106,7 @@ class zdoom(Runner):
return executable
def prelaunch(self):
if not system.LINUX_SYSTEM.get_soundfonts():
if not LINUX_SYSTEM.get_soundfonts():
logger.warning("FluidSynth is not installed, you might not have any music")
return True

View file

@ -9,8 +9,8 @@ from lutris import settings
from lutris.util import http, jobs, system
from lutris.util.downloader import Downloader
from lutris.util.extract import extract_archive
from lutris.util.linux import LINUX_SYSTEM
from lutris.util.log import logger
from lutris.util.system import LINUX_SYSTEM
RUNTIME_DISABLED = os.environ.get("LUTRIS_RUNTIME", "").lower() in ("0", "off")
DEFAULT_RUNTIME = "Ubuntu-18.04"
@ -220,7 +220,7 @@ class RuntimeUpdater:
# Skip 32bit runtimes on 64 bit systems except the main runtime
if (
runtime["architecture"] == "i386" and system.LINUX_SYSTEM.is_64_bit
runtime["architecture"] == "i386" and LINUX_SYSTEM.is_64_bit
and not runtime["name"].startswith(("Ubuntu", "lib32"))
):
logger.debug(
@ -231,7 +231,7 @@ class RuntimeUpdater:
continue
# Skip 64bit runtimes on 32 bit systems
if runtime["architecture"] == "x86_64" and not system.LINUX_SYSTEM.is_64_bit:
if runtime["architecture"] == "x86_64" and not LINUX_SYSTEM.is_64_bit:
logger.debug(
"Skipping runtime %s for %s",
runtime["name"],
@ -299,7 +299,7 @@ def get_runtime_paths(version=None, prefer_system_libs=True, wine_path=None):
"steam/i386/usr/lib",
]
if system.LINUX_SYSTEM.is_64_bit:
if LINUX_SYSTEM.is_64_bit:
if version == "legacy":
lutris_runtime_path = "lib64"
else:

View file

@ -11,7 +11,7 @@ from lutris.installer.installer_file import InstallerFile
from lutris.services.base import OnlineService
from lutris.services.service_game import ServiceGame
from lutris.services.service_media import ServiceMedia
from lutris.util import system
from lutris.util import linux
from lutris.util.http import HTTPError, Request
from lutris.util.log import logger
from lutris.util.strings import slugify
@ -331,7 +331,7 @@ def pick_download_url_from_download_info(download_info):
bonus = 1
if "deb" not in name:
bonus = 2
if system.LINUX_SYSTEM.is_64_bit:
if linux.LINUX_SYSTEM.is_64_bit:
if "386" in name or "32" in name:
return -1
else:

View file

@ -5,7 +5,7 @@ from collections import OrderedDict
from gettext import gettext as _
from lutris import runners
from lutris.util import system
from lutris.util import linux, system
from lutris.util.display import DISPLAY_MANAGER, SCREEN_SAVER_INHIBITOR, USE_DRI_PRIME
VULKAN_DATA_DIRS = [
@ -236,8 +236,8 @@ system_options = [ # pylint: disable=invalid-name
{
"option": "gamemode",
"type": "bool",
"default": system.LINUX_SYSTEM.gamemode_available(),
"condition": system.LINUX_SYSTEM.gamemode_available,
"default": linux.LINUX_SYSTEM.gamemode_available(),
"condition": linux.LINUX_SYSTEM.gamemode_available,
"label": _("Enable Feral GameMode"),
"help": _("Request a set of optimisations be temporarily applied to the host OS"),
},
@ -309,8 +309,8 @@ system_options = [ # pylint: disable=invalid-name
"option": "terminal_app",
"label": _("Text based games emulator"),
"type": "choice_with_entry",
"choices": system.get_terminal_apps,
"default": system.get_default_terminal(),
"choices": linux.get_terminal_apps,
"default": linux.get_default_terminal(),
"advanced": True,
"help": _("The terminal emulator used with the CLI mode. "
"Choose from the list of detected terminal apps or enter "

View file

@ -1,56 +0,0 @@
"""Filesystem utilities"""
# Standard Library
import os
import subprocess
# Third Party Libraries
from gi.repository import Gio
# Lutris Modules
from lutris.util.log import logger
def get_mounted_discs():
"""Return a list of mounted discs and ISOs
:rtype: list of Gio.Mount
"""
volumes = Gio.VolumeMonitor.get()
drives = []
for mount in volumes.get_mounts():
if mount.get_volume():
device = mount.get_volume().get_identifier("unix-device")
if not device:
logger.debug("No device for mount %s", mount.get_name())
continue
# Device is a disk drive or ISO image
if "/dev/sr" in device or "/dev/loop" in device:
drives.append(mount.get_root().get_path())
return drives
def find_mount_point(path):
"""Return the mount point a file is located on"""
path = os.path.abspath(path)
while not os.path.ismount(path):
path = os.path.dirname(path)
return path
def get_mountpoint_drives():
"""Return a mapping of mount points with their corresponding drives"""
mounts = subprocess.check_output(["mount", "-v"]).decode("utf-8").split("\n")
mount_map = []
for mount in mounts:
mount_parts = mount.split()
if len(mount_parts) < 3:
continue
mount_map.append((mount_parts[2], mount_parts[0]))
return dict(mount_map)
def get_drive_for_path(path):
"""Return the physical drive a file is located on"""
return get_mountpoint_drives().get(find_mount_point(path))

View file

@ -257,7 +257,7 @@ def check_inno_exe(path):
def get_innoextract_list(file_path):
"""Return the list of files contained in a GOG archive"""
output = subprocess.check_output([get_innoextract_path(), "-lmq", file_path])
output = system.read_process_output([get_innoextract_path(), "-lmq", file_path])
return [line[3:] for line in output.decode().split("\n") if line]

View file

@ -1,18 +1,13 @@
"""Parser for the glxinfo utility"""
# Standard Library
import subprocess
# Lutris Modules
from lutris.util.log import logger
from lutris.util.system import read_process_output
class Container: # pylint: disable=too-few-public-methods
"""A dummy container for data"""
class GlxInfo:
"""Give access to the glxinfo information"""
def __init__(self, output=None):
@ -30,11 +25,7 @@ class GlxInfo:
@staticmethod
def get_glxinfo_output():
"""Return the glxinfo -B output"""
try:
return subprocess.check_output(["glxinfo", "-B"]).decode()
except subprocess.CalledProcessError as ex:
logger.error("glxinfo call failed: %s", ex)
return ""
return read_process_output(["glxinfo", "-B"])
def as_dict(self):
"""Return the attributes as a dict"""

View file

@ -1,11 +1,10 @@
"""XrandR based display management"""
# Standard Library
import re
import subprocess
from collections import namedtuple
# Lutris Modules
from lutris.util.log import logger
from lutris.util.system import read_process_output
Output = namedtuple("Output", ("name", "mode", "position", "rotation", "primary", "rate"))
@ -13,13 +12,7 @@ Output = namedtuple("Output", ("name", "mode", "position", "rotation", "primary"
def _get_vidmodes():
"""Return video modes from XrandR"""
logger.debug("Retrieving video modes from XrandR")
try:
xrandr_output = subprocess.check_output(["xrandr"])
except subprocess.CalledProcessError as ex:
logger.error("Unable to read xrandr: %s", ex)
return ""
return xrandr_output.decode().split("\n")
return read_process_output(["xrandr"]).split("\n")
def get_outputs(): # pylint: disable=too-many-locals

View file

@ -5,12 +5,10 @@ import platform
import re
import resource
import shutil
import subprocess
import sys
from collections import Counter, defaultdict
from lutris.util import system
from lutris.util.disks import get_drive_for_path
from lutris.util.graphics import drivers, glxinfo, vkquery
from lutris.util.log import logger
@ -160,12 +158,12 @@ class LinuxSystem: # pylint: disable=too-many-public-methods
@staticmethod
def get_drives():
"""Return a list of drives with their filesystems"""
try:
output = subprocess.check_output(["lsblk", "-f", "--json"]).decode()
except subprocess.CalledProcessError as ex:
logger.error("Failed to get drive information: %s", ex)
return None
return [drive for drive in json.loads(output)["blockdevices"] if drive["fstype"] != "squashfs"]
lsblk_output = system.read_process_output(["lsblk", "-f", "--json"])
return [
drive
for drive in json.loads(lsblk_output)["blockdevices"]
if drive["fstype"] != "squashfs"
]
@staticmethod
def get_ram_info():
@ -243,7 +241,7 @@ class LinuxSystem: # pylint: disable=too-many-public-methods
def get_fs_type_for_path(self, path):
"""Return the filesystem type a given path uses"""
path_drive = get_drive_for_path(path)
path_drive = system.get_drive_for_path(path)
for drive in self.get_drives():
for partition in drive.get("children", []):
if "/dev/%s" % partition["name"] == path_drive:
@ -312,11 +310,7 @@ class LinuxSystem: # pylint: disable=too-many-public-methods
if not ldconfig:
logger.error("Could not detect ldconfig on this system")
return []
try:
output = (subprocess.check_output([ldconfig, "-p"]).decode("utf-8", errors="ignore").split("\n"))
except subprocess.CalledProcessError as ex:
logger.error("Failed to get libraries from ldconfig: %s", ex)
return []
output = system.read_process_output([ldconfig, "-p"]).split("\n")
return [line.strip("\t") for line in output if line.startswith("\t")]
def get_shared_libraries(self):
@ -490,3 +484,16 @@ def gather_system_info_str():
output += '{}{}{}\n'.format(key + ":", tabs, dictionary[key])
output += '\n'
return output
def get_terminal_apps():
"""Return the list of installed terminal emulators"""
return LINUX_SYSTEM.get_terminals()
def get_default_terminal():
"""Return the default terminal emulator"""
terms = get_terminal_apps()
if terms:
return terms[0]
logger.error("Couldn't find a terminal emulator.")

View file

@ -8,10 +8,9 @@ import stat
import string
import subprocess
from gi.repository import GLib
from gi.repository import Gio, GLib
from lutris import settings
from lutris.util.linux import LINUX_SYSTEM
from lutris.util.log import logger
# Home folders that should never get deleted. This should be localized and return the
@ -79,6 +78,18 @@ def execute(command, env=None, cwd=None, log_errors=False, quiet=False, shell=Fa
return stdout.decode(errors="replace").strip()
def read_process_output(command, timeout=2):
"""Return the output of a command as a string"""
try:
return subprocess.check_output(
command,
timeout=timeout
).decode("utf-8", errors="ignore").strip()
except (OSError, subprocess.CalledProcessError) as ex:
logger.error("%s command failed: %s", command, ex)
return ""
def get_md5_hash(filename):
"""Return the md5 hash of a file."""
md5 = hashlib.md5()
@ -115,9 +126,6 @@ def find_executable(exec_name):
"""Return the absolute path of an executable"""
if not exec_name:
return None
cached = LINUX_SYSTEM.get(exec_name)
if cached:
return cached
return shutil.which(exec_name)
@ -298,19 +306,6 @@ def get_pids_using_file(path):
return set(fuser_output.split())
def get_terminal_apps():
"""Return the list of installed terminal emulators"""
return LINUX_SYSTEM.get_terminals()
def get_default_terminal():
"""Return the default terminal emulator"""
terms = get_terminal_apps()
if terms:
return terms[0]
logger.error("Couldn't find a terminal emulator.")
def reverse_expanduser(path):
"""Replace '/home/username' with '~' in given path."""
if not path:
@ -387,3 +382,49 @@ def get_disk_size(path):
def get_running_pid_list():
"""Return the list of PIDs from processes currently running"""
return [p for p in os.listdir("/proc") if p[0].isdigit()]
def get_mounted_discs():
"""Return a list of mounted discs and ISOs
:rtype: list of Gio.Mount
"""
volumes = Gio.VolumeMonitor.get()
drives = []
for mount in volumes.get_mounts():
if mount.get_volume():
device = mount.get_volume().get_identifier("unix-device")
if not device:
logger.debug("No device for mount %s", mount.get_name())
continue
# Device is a disk drive or ISO image
if "/dev/sr" in device or "/dev/loop" in device:
drives.append(mount.get_root().get_path())
return drives
def find_mount_point(path):
"""Return the mount point a file is located on"""
path = os.path.abspath(path)
while not os.path.ismount(path):
path = os.path.dirname(path)
return path
def get_mountpoint_drives():
"""Return a mapping of mount points with their corresponding drives"""
mounts = read_process_output(["mount", "-v"]).split("\n")
mount_map = []
for mount in mounts:
mount_parts = mount.split()
if len(mount_parts) < 3:
continue
mount_map.append((mount_parts[2], mount_parts[0]))
return dict(mount_map)
def get_drive_for_path(path):
"""Return the physical drive a file is located on"""
return get_mountpoint_drives().get(find_mount_point(path))

View file

@ -1,5 +1,3 @@
# pylint: disable=missing-docstring
# Standard Library
import os
import re
import shutil
@ -7,12 +5,11 @@ import subprocess
import tempfile
import xml.etree.ElementTree
# Lutris Modules
from lutris.util.log import logger
from lutris.util.system import execute, read_process_output
class CabInstaller:
"""Extract and install contents of cab files
Based on an implementation by tonix64: https://github.com/tonix64/python-installcab
@ -45,7 +42,7 @@ class CabInstaller:
@staticmethod
def get_arch_from_dll(dll_path):
if "x86-64" in subprocess.check_output(["file", dll_path]).decode():
if "x86-64" in read_process_output(["file", dll_path]):
return "win64"
return "win32"
@ -197,7 +194,7 @@ class CabInstaller:
Returns:
list: Files extracted from the cab file
"""
subprocess.check_output(["cabextract", "-F", "*%s*" % component, "-d", self.tmpdir, cabfile])
execute(["cabextract", "-F", "*%s*" % component, "-d", self.tmpdir, cabfile])
return [os.path.join(r, file) for r, d, f in os.walk(self.tmpdir) for file in f]
def install(self, cabfile, component):

View file

@ -1,11 +1,9 @@
"""Gallium Nine helper module"""
# Standard Library
import os
import shutil
# Lutris Modules
from lutris.runners.commands.wine import wineexec
from lutris.util import system
from lutris.util import linux, system
from lutris.util.log import logger
from lutris.util.wine.cabinstall import CabInstaller
@ -37,7 +35,7 @@ class NineManager:
"""
for mesa_file in NineManager.mesa_files:
if not any(
[os.path.exists(os.path.join(lib, "d3d", mesa_file)) for lib in system.LINUX_SYSTEM.iter_lib_folders()]
[os.path.exists(os.path.join(lib, "d3d", mesa_file)) for lib in linux.LINUX_SYSTEM.iter_lib_folders()]
):
return False
@ -53,7 +51,7 @@ class NineManager:
if not any(
[
os.path.exists(os.path.join(lib, "wine/fakedlls", nine_file))
for lib in system.LINUX_SYSTEM.iter_lib_folders()
for lib in linux.LINUX_SYSTEM.iter_lib_folders()
]
):
return False
@ -95,7 +93,7 @@ class NineManager:
def prepare_prefix(self):
for nine_file in NineManager.nine_files:
for lib in system.LINUX_SYSTEM.iter_lib_folders():
for lib in linux.LINUX_SYSTEM.iter_lib_folders():
nine_file_path = os.path.join(lib, "wine/fakedlls", nine_file)
if (os.path.exists(nine_file_path) and CabInstaller.get_arch_from_dll(nine_file_path) == "win32"):

View file

@ -1,6 +1,5 @@
"""Utilities for manipulating Wine"""
import os
import subprocess
from collections import OrderedDict
from functools import lru_cache
from gettext import gettext as _
@ -8,13 +7,13 @@ from gettext import gettext as _
from lutris import runtime, settings
from lutris.gui.dialogs import DontShowAgainDialog, ErrorDialog
from lutris.runners.steam import steam
from lutris.util import system
from lutris.util import linux, system
from lutris.util.log import logger
from lutris.util.strings import parse_version, version_sort
from lutris.util.wine import fsync
WINE_DIR = os.path.join(settings.RUNNER_DIR, "wine")
WINE_DEFAULT_ARCH = "win64" if system.LINUX_SYSTEM.is_64_bit else "win32"
WINE_DEFAULT_ARCH = "win64" if linux.LINUX_SYSTEM.is_64_bit else "win32"
WINE_PATHS = {
"winehq-devel": "/opt/wine-devel/bin/wine",
"winehq-staging": "/opt/wine-staging/bin/wine",
@ -157,7 +156,7 @@ def get_system_wine_versions():
"""Return the list of wine versions installed on the system"""
versions = []
for build in sorted(WINE_PATHS.keys()):
version = get_system_wine_version(WINE_PATHS[build])
version = get_wine_version(WINE_PATHS[build])
if version:
versions.append(build)
return versions
@ -230,7 +229,7 @@ def is_esync_limit_set():
if ESYNC_LIMIT_CHECK in ("0", "off"):
logger.info("fd limit check for esync was manually disabled")
return True
return system.LINUX_SYSTEM.has_enough_file_descriptors()
return linux.LINUX_SYSTEM.has_enough_file_descriptors()
def is_fsync_supported():
@ -252,9 +251,10 @@ def get_default_version():
return
def get_system_wine_version(wine_path="wine"):
def get_wine_version(wine_path="wine"):
"""Return the version of Wine installed on the system."""
if wine_path != "wine" and not system.path_exists(wine_path):
logger.warning("Non existent Wine path: %s", wine_path)
return
if wine_path == "wine" and not system.find_executable("wine"):
return
@ -263,16 +263,13 @@ def get_system_wine_version(wine_path="wine"):
if wine_stats.st_size < 2000:
# This version is a script, ignore it
return
try:
version = subprocess.check_output([wine_path, "--version"]).decode().strip()
except (OSError, subprocess.CalledProcessError) as ex:
logger.exception("Error reading wine version for %s: %s", wine_path, ex)
version = system.read_process_output([wine_path, "--version"])
if not version:
logger.error("Error reading wine version for %s", wine_path)
return
else:
if version.startswith("wine-"):
version = version[5:]
return version
return
if version.startswith("wine-"):
version = version[5:]
return version
def is_version_esync(path):
@ -294,8 +291,8 @@ def is_version_esync(path):
for esync_version in esync_compatible_versions:
if esync_version in version_prefix or esync_version in version_suffix:
return True
wine_ver = str(subprocess.check_output([path, "--version"])).lower()
return "esync" in wine_ver or "staging" in wine_ver
wine_version = get_wine_version(path).lower()
return "esync" in wine_version or "staging" in wine_version
def is_version_fsync(path):
@ -317,11 +314,7 @@ def is_version_fsync(path):
for fsync_version in fsync_compatible_versions:
if fsync_version in version_prefix or fsync_version in version_suffix:
return True
wine_ver = str(subprocess.check_output([path, "--version"])).lower()
if "fsync" in wine_ver:
return True
return False
return "fsync" in get_wine_version(path).lower()
def get_real_executable(windows_executable, working_dir=None):