def create_prefix(prefix, wine_path=None, arch='win32'): """Create a new Wine prefix.""" logger.debug("Creating a %s prefix in %s", arch, prefix) # Avoid issue of 64bit Wine refusing to create win32 prefix # over an existing empty folder. if os.path.isdir(prefix) and not os.listdir(prefix): os.rmdir(prefix) if not wine_path: wine_path = wine().get_executable() wineboot_path = os.path.join(os.path.dirname(wine_path), 'wineboot') env = { 'WINEARCH': arch, 'WINEPREFIX': prefix } system.execute([wineboot_path], env=env) for i in range(20): time.sleep(.25) if os.path.exists(os.path.join(prefix, 'user.reg')): break if not os.path.exists(os.path.join(prefix, 'user.reg')): logger.error('No user.reg found after prefix creation. ' 'Prefix might not be valid') logger.info('%s Prefix created in %s', arch, prefix) prefix_manager = WinePrefixManager(prefix) prefix_manager.setup_defaults()
def dosexec(config_file=None, executable=None, args=None, exit=True, working_dir=None): """Execute Dosbox with given config_file.""" if config_file: run_with = "config {}".format(config_file) if not working_dir: working_dir = os.path.dirname(config_file) elif executable: run_with = "executable {}".format(executable) if not working_dir: working_dir = os.path.dirname(executable) else: raise ValueError("Neither a config file or an executable were provided") logger.debug("Running dosbox with {}".format(run_with)) working_dir = system.create_folder(working_dir) dosbox_runner = dosbox() command = [dosbox_runner.get_executable()] if config_file: command += ['-conf', config_file] if executable: if not os.path.exists(executable): raise OSError("Can't find file {}".format(executable)) command += [executable] if args: command += args.split() if exit: command.append('-exit') system.execute(command, cwd=working_dir)
def install_game(self, appid, generate_acf=False): if not appid: raise ValueError("Missing appid in winesteam.install_game") system.execute( self.launch_args + ["steam://install/%s" % appid], env=self.get_env() )
def validate_game(self, appid): if not appid: raise ValueError("Missing appid in winesteam.validate_game") system.execute( self.launch_args + ["steam://validate/%s" % appid], env=self.get_env() )
def install_game(self, appid, generate_acf=False): """Install a game with Steam""" if not appid: raise ValueError("Missing appid in winesteam.install_game") system.execute( self.launch_args + ["steam://install/%s" % appid], env=self.get_env() )
def validate_game(self, appid): """Validate game files with Steam""" if not appid: raise ValueError("Missing appid in winesteam.validate_game") system.execute( self.launch_args + ["steam://validate/%s" % appid], env=self.get_env() )
def get_compositor_commands(): """Nominated for the worst function in lutris""" start_compositor = None stop_compositor = None desktop_session = os.environ.get("DESKTOP_SESSION") if desktop_session == "plasma": stop_compositor = ("qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.suspend") start_compositor = ("qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.resume") elif ( desktop_session == "mate" and system.execute("gsettings get org.mate.Marco.general compositing-manager", shell=True) == "true" ): stop_compositor = ("gsettings set org.mate.Marco.general compositing-manager false") start_compositor = ("gsettings set org.mate.Marco.general compositing-manager true") elif ( desktop_session == "xfce" and system.execute( "xfconf-query --channel=xfwm4 --property=/general/use_compositing", shell=True, ) == "true" ): stop_compositor = ("xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=false") start_compositor = ("xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=true") elif ( desktop_session == "deepin" and system.execute( "dbus-send --session --dest=com.deepin.WMSwitcher --type=method_call " "--print-reply=literal /com/deepin/WMSwitcher com.deepin.WMSwitcher.CurrentWM", shell=True, ) == "deepin wm" ): start_compositor, stop_compositor = ( "dbus-send --session --dest=com.deepin.WMSwitcher --type=method_call " "/com/deepin/WMSwitcher com.deepin.WMSwitcher.RequestSwitchWM", ) * 2 return start_compositor, stop_compositor
def dosexec(config_file=None, executable=None, args=None, exit=True, working_dir=None): """Execute Dosbox with given config_file.""" if config_file: run_with = "config {}".format(config_file) if not working_dir: working_dir = os.path.dirname(config_file) elif executable: run_with = "executable {}".format(executable) if not working_dir: working_dir = os.path.dirname(executable) else: raise ValueError( "Neither a config file or an executable were provided") logger.debug("Running dosbox with {}".format(run_with)) working_dir = system.create_folder(working_dir) dosbox_runner = dosbox() command = [dosbox_runner.get_executable()] if config_file: command += ['-conf', config_file] if executable: if not os.path.exists(executable): raise OSError("Can't find file {}".format(executable)) command += [executable] if args: command += args.split() if exit: command.append('-exit') system.execute(command, cwd=working_dir)
def open_uri(uri): """Opens a local or remote URI with the default application""" system.reset_library_preloads() try: Gtk.show_uri(None, uri, Gdk.CURRENT_TIME) except GLib.Error as ex: logger.exception("Failed to open URI %s: %s, falling back to xdg-open", uri, ex) system.execute(["xdg-open", uri])
def set_desktop_compositing(self, enable): if enable: system.execute(self.start_compositor, shell=True) else: self.start_compositor, self.stop_compositor = display.get_compositor_commands() if not (self.compositor_disabled or not self.stop_compositor): system.execute(self.stop_compositor, shell=True) self.compositor_disabled = True
def stop(self): """The kill command runs wineserver -k.""" wine_path = self.get_executable() wine_root = os.path.dirname(wine_path) command = os.path.join(wine_root, "wineserver") + " -k" if self.prefix_path: command = "WINEPREFIX=%s %s" % (self.prefix_path, command) logger.debug("Killing all wine processes: %s" % command) system.execute(command, shell=True)
def reset_pulse(): """Reset pulseaudio.""" if not system.find_executable("pulseaudio"): logger.warning("PulseAudio not installed. Nothing to do.") return system.execute(["pulseaudio", "--kill"]) time.sleep(1) system.execute(["pulseaudio", "--start"]) logger.debug("PulseAudio restarted")
def open_wine_terminal(terminal, wine_path, prefix, env): aliases = { "wine": wine_path, "winecfg": wine_path + "cfg", "wineserver": wine_path + "server", "wineboot": wine_path + "boot", } env["WINEPREFIX"] = prefix shell_command = get_shell_command(prefix, env, aliases) terminal = terminal or linux.get_default_terminal() system.execute([linux.get_default_terminal(), "-e", shell_command])
def set_desktop_compositing(self, enable): """Enables or disables compositing""" if enable: system.execute(self.start_compositor, shell=True) else: self.start_compositor, self.stop_compositor = ( display.get_compositor_commands() ) if not (self.compositor_disabled or not self.stop_compositor): system.execute(self.stop_compositor, shell=True) self.compositor_disabled = True
def extract_from_cab(self, cabfile, component): """Extracts files matching a `component` name from a `cabfile` Params: cabfile (str): Path to a cabfile to extract from component (str): component to extract from the cab file Returns: list: Files extracted from the cab file """ 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 create_prefix(prefix, wine_path=None, arch='win32', overrides={}, install_gecko=None, install_mono=None): """Create a new Wine prefix.""" logger.debug("Creating a %s prefix in %s", arch, prefix) # Avoid issue of 64bit Wine refusing to create win32 prefix # over an existing empty folder. if os.path.isdir(prefix) and not os.listdir(prefix): os.rmdir(prefix) if not wine_path: wine = import_runner('wine') wine_path = wine().get_executable() if not wine_path: logger.error("Wine not found, can't create prefix") return wineboot_path = os.path.join(os.path.dirname(wine_path), 'wineboot') if not system.path_exists(wineboot_path): logger.error( "No wineboot executable found in %s, " "your wine installation is most likely broken", wine_path) return if install_gecko == 'False': overrides['mshtml'] = 'disabled' if install_mono == 'False': overrides['mscoree'] = 'disabled' wineenv = { 'WINEARCH': arch, 'WINEPREFIX': prefix, 'WINEDLLOVERRIDES': get_overrides_env(overrides) } system.execute([wineboot_path], env=wineenv) for loop_index in range(50): time.sleep(.25) if system.path_exists(os.path.join(prefix, 'user.reg')): break if loop_index == 20: logger.warning( "Wine prefix creation is taking longer than expected...") if not os.path.exists(os.path.join(prefix, 'user.reg')): logger.error('No user.reg found after prefix creation. ' 'Prefix might not be valid') return logger.info('%s Prefix created in %s', arch, prefix) prefix_manager = WinePrefixManager(prefix) prefix_manager.setup_defaults()
def shutdown(): """ Shutdown Steam in a clean way. TODO: Detect wine binary """ pid = system.get_pid('Steam.exe') if not pid: return False cwd = system.get_cwd(pid) cmdline = system.get_command_line(pid) steam_exe = os.path.join(cwd, cmdline) logger.debug("Shutting winesteam: %s", steam_exe) system.execute(['wine', steam_exe, '-shutdown'])
def shutdown(): """ Shutdown Steam in a clean way. TODO: Detect wine binary """ pid = system.get_pid('Steam.exe$') if not pid: return False cwd = system.get_cwd(pid) cmdline = system.get_command_line(pid) steam_exe = os.path.join(cwd, cmdline) logger.debug("Shutting winesteam: %s", steam_exe) system.execute(['wine', steam_exe, '-shutdown'])
def set_desktop_compositing(self, enable): """Enables or disables compositing""" if enable: system.execute(self.start_compositor, shell=True) else: ( self.start_compositor, self.stop_compositor, ) = get_compositor_commands() if not (self.compositor_disabled or not self.stop_compositor): system.execute(self.stop_compositor, shell=True) self.compositor_disabled = True
def prelaunch(self): if not system.path_exists(os.path.join(self.config_dir, "mame.ini")): try: os.makedirs(self.config_dir) except OSError: pass system.execute( [self.get_executable(), "-createconfig", "-inipath", self.config_dir], env=runtime.get_env(), cwd=self.working_dir ) return True
def shutdown(self): """Shutdown Steam in a clean way.""" pid = system.get_pid('Steam.exe$') if not pid: return False command = [] command.append('WINEARCH=%s ' % self.wine_arch) command.append('WINEPREFIX="%s" ' % self.prefix_path) command += self.launch_args command.append('-shutdown') logger.debug("Shutting winesteam: %s", command) system.execute(' '.join(command), shell=True)
def get_compositor_commands(): """Nominated for the worst function in lutris""" start_compositor = None stop_compositor = None desktop_session = os.environ.get('DESKTOP_SESSION') if desktop_session == "plasma": stop_compositor = "qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.suspend" start_compositor = "qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.resume" elif desktop_session == "mate" and system.execute("gsettings get org.mate.Marco.general compositing-manager", shell=True) == 'true': stop_compositor = "gsettings set org.mate.Marco.general compositing-manager false" start_compositor = "gsettings set org.mate.Marco.general compositing-manager true" elif desktop_session == "xfce" and system.execute("xfconf-query --channel=xfwm4 --property=/general/use_compositing", shell=True) == 'true': stop_compositor = "xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=false" start_compositor = "xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=true" return start_compositor, stop_compositor
def cancel_installation(self, widget=None): """Ask a confirmation before cancelling the install""" confirm_cancel_dialog = QuestionDialog({ "question": "Are you sure you want to cancel the installation?", "title": "Cancel installation?", }) if confirm_cancel_dialog.result != Gtk.ResponseType.YES: logger.warning( "Attempting to terminate with the system wineserver. " "This is most likely to fail or to have no effect.") system.execute([system.find_executable("wineserver"), "-k9"]) return True if self.interpreter: self.interpreter.revert() self.interpreter.cleanup() self.destroy()
def winekill(prefix, arch='win32', wine_path=None, env=None, initial_pids=None): """Kill processes in Wine prefix.""" initial_pids = initial_pids or [] for pid in initial_pids: logger.debug(Process(pid)) if not wine_path: wine_path = wine().get_executable() wine_root = os.path.dirname(wine_path) if not env: env = {'WINEARCH': arch, 'WINEPREFIX': prefix} command = [os.path.join(wine_root, "wineserver"), "-k"] logger.debug("Killing all wine processes: %s" % command) logger.debug("\tWine prefix: %s", prefix) logger.debug("\tWine arch: %s", arch) logger.debug("\tInitial pids: %s", initial_pids) system.execute(command, env=env, quiet=True) logger.debug("Waiting for wine processes to terminate") # Wineserver needs time to terminate processes num_cycles = 0 while True: num_cycles += 1 running_processes = [ pid for pid in initial_pids if os.path.exists("/proc/%s" % pid) ] logger.debug("running_processes: %s, cycles: %s", running_processes, num_cycles) for pid in running_processes: logger.debug(Process(pid)) if not running_processes: logger.debug("Done in %s cycles", num_cycles) break if num_cycles > 300: logger.warning("Some wine processes are still running: %s", ', '.join(running_processes)) break time.sleep(0.1)
def write_xml_list(self): """Write the full game list in XML to disk""" if not os.path.exists(self.cache_dir): os.makedirs(self.cache_dir) with open(self.xml_path, "w") as xml_file: output = system.execute([self.get_executable(), "-listxml"]) xml_file.write(output) logger.info("MAME XML list written to %s", self.xml_path)
def cancel_installation(self, widget=None): """Ask a confirmation before cancelling the install""" confirm_cancel_dialog = QuestionDialog( { "question": "Are you sure you want to cancel the installation?", "title": "Cancel installation?", } ) if confirm_cancel_dialog.result != Gtk.ResponseType.YES: logger.warning("Attempting to terminate with the system wineserver. " "This is most likely to fail or to have no effect.") system.execute([system.find_executable("wineserver"), "-k9"]) return True if self.interpreter: self.interpreter.revert() self.interpreter.cleanup() self.destroy()
def winekill(prefix, arch=WINE_DEFAULT_ARCH, wine_path=None, env=None, initial_pids=None): """Kill processes in Wine prefix.""" initial_pids = initial_pids or [] if not wine_path: wine = import_runner("wine") wine_path = wine().get_executable() wine_root = os.path.dirname(wine_path) if not env: env = {"WINEARCH": arch, "WINEPREFIX": prefix} command = [os.path.join(wine_root, "wineserver"), "-k"] logger.debug("Killing all wine processes: %s", command) logger.debug("\tWine prefix: %s", prefix) logger.debug("\tWine arch: %s", arch) if initial_pids: logger.debug("\tInitial pids: %s", initial_pids) system.execute(command, env=env, quiet=True) logger.debug("Waiting for wine processes to terminate") # Wineserver needs time to terminate processes num_cycles = 0 while True: num_cycles += 1 running_processes = [ pid for pid in initial_pids if system.path_exists("/proc/%s" % pid) ] if not running_processes: break if num_cycles > 20: logger.warning( "Some wine processes are still running: %s", ", ".join(running_processes), ) break time.sleep(0.1) logger.debug("Done waiting.")
def create_prefix(prefix, wine_path=None, arch='win32', overrides={}, install_gecko=None, install_mono=None): """Create a new Wine prefix.""" logger.debug("Creating a %s prefix in %s", arch, prefix) # Avoid issue of 64bit Wine refusing to create win32 prefix # over an existing empty folder. if os.path.isdir(prefix) and not os.listdir(prefix): os.rmdir(prefix) if not wine_path: wine_path = wine().get_executable() wineboot_path = os.path.join(os.path.dirname(wine_path), 'wineboot') if not system.path_exists(wineboot_path): logger.error("No wineboot executable found in %s, " "your wine installation is most likely broken", wine_path) return if install_gecko is 'False': overrides['mshtml'] = 'disabled' if install_mono is 'False': overrides['mscoree'] = 'disabled' wineenv = { 'WINEARCH': arch, 'WINEPREFIX': prefix, 'WINEDLLOVERRIDES': get_overrides_env(overrides) } system.execute([wineboot_path], env=wineenv) for i in range(20): time.sleep(.25) if os.path.exists(os.path.join(prefix, 'user.reg')): break if not os.path.exists(os.path.join(prefix, 'user.reg')): logger.error('No user.reg found after prefix creation. ' 'Prefix might not be valid') return logger.info('%s Prefix created in %s', arch, prefix) prefix_manager = WinePrefixManager(prefix) prefix_manager.setup_defaults()
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None, working_dir=None, winetricks_wine='', blocking=False, config=None): """Execute a Wine command.""" detected_arch = detect_prefix_arch(prefix) executable = str(executable) if executable else '' if arch not in ('win32', 'win64'): arch = detected_arch or 'win32' if not wine_path: wine_path = wine().get_executable() if not working_dir: if os.path.isfile(executable): working_dir = os.path.dirname(executable) if executable.endswith(".msi"): executable = 'msiexec /i "%s"' % executable elif executable: executable = '%s' % executable # Create prefix if necessary if not detected_arch: wine_bin = winetricks_wine if winetricks_wine else wine_path create_prefix(prefix, wine_path=wine_bin, arch=arch) env = {'WINEARCH': arch} if winetricks_wine: env['WINE'] = winetricks_wine else: env['WINE'] = wine_path if prefix: env['WINEPREFIX'] = prefix wine_config = config or LutrisConfig(runner_slug='wine') if not wine_config.system_config[ 'disable_runtime'] and not runtime.is_disabled(): env['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths()) command = [wine_path] if executable: command.append(executable) command += shlex.split(args) if blocking: return system.execute(command, env=env, cwd=working_dir) else: thread = LutrisThread(command, runner=wine(), env=env, cwd=working_dir) thread.start() return thread
def write_xml_list(self): """Write the full game list in XML to disk""" if not os.path.exists(self.cache_dir): os.makedirs(self.cache_dir) output = system.execute([self.get_executable(), "-listxml"], env=runtime.get_env()) if output: with open(self.xml_path, "w") as xml_file: xml_file.write(output) logger.info("MAME XML list written to %s", self.xml_path) else: logger.warning("Couldn't get any output for mame -listxml")
def winekill(prefix, arch='win32', wine_path=None, env=None, initial_pids=None): """Kill processes in Wine prefix.""" initial_pids = initial_pids or [] if not wine_path: wine_path = wine().get_executable() wine_root = os.path.dirname(wine_path) if not env: env = { 'WINEARCH': arch, 'WINEPREFIX': prefix } command = [os.path.join(wine_root, "wineserver"), "-k"] logger.debug("Killing all wine processes: %s" % command) logger.debug("\tWine prefix: %s", prefix) logger.debug("\tWine arch: %s", arch) if initial_pids: logger.debug("\tInitial pids: %s", initial_pids) system.execute(command, env=env, quiet=True) logger.debug("Waiting for wine processes to terminate") # Wineserver needs time to terminate processes num_cycles = 0 while True: num_cycles += 1 running_processes = [ pid for pid in initial_pids if os.path.exists("/proc/%s" % pid) ] if not running_processes: break if num_cycles > 20: logger.warning("Some wine processes are still running: %s", ', '.join(running_processes)) break time.sleep(0.1)
def cancel_installation(self, widget=None): """Ask a confirmation before cancelling the install""" remove_checkbox = Gtk.CheckButton.new_with_label("Remove game files") if self.interpreter: remove_checkbox.set_active(self.interpreter.game_dir_created) remove_checkbox.show() confirm_cancel_dialog = QuestionDialog( { "question": "Are you sure you want to cancel the installation?", "title": "Cancel installation?", "widgets": [remove_checkbox] } ) if confirm_cancel_dialog.result != Gtk.ResponseType.YES: logger.warning("Attempting to terminate with the system wineserver. " "This is most likely to fail or to have no effect.") system.execute([system.find_executable("wineserver"), "-k9"]) return True if self.interpreter: self.interpreter.game_dir_created = remove_checkbox.get_active() self.interpreter.revert() self.interpreter.cleanup() self.destroy()
def _get_graphics_adapters(): """Return the list of graphics cards available on a system Returns: list: list of tuples containing PCI ID and description of the VGA adapter """ lspci_path = system.find_executable("lspci") if not lspci_path: logger.warning( "lspci is not available. List of graphics cards not available") return [] return [(pci_id, vga_desc.split(": ")[1]) for pci_id, vga_desc in [ line.split(maxsplit=1) for line in system.execute(lspci_path).split("\n") if "VGA" in line ]]
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None, working_dir=None, winetricks_wine='', blocking=False): """Execute a Wine command.""" detected_arch = detect_prefix_arch(prefix) executable = str(executable) if executable else '' if arch not in ('win32', 'win64'): arch = detected_arch or 'win32' if not wine_path: wine_path = wine().get_executable() if not working_dir: if os.path.isfile(executable): working_dir = os.path.dirname(executable) if executable.endswith(".msi"): executable = 'msiexec /i "%s"' % executable elif executable: executable = '%s' % executable # Create prefix if necessary if not detected_arch: wine_bin = winetricks_wine if winetricks_wine else wine_path create_prefix(prefix, wine_path=wine_bin, arch=arch) env = { 'WINEARCH': arch } if winetricks_wine: env['WINE'] = winetricks_wine else: env['WINE'] = wine_path if prefix: env['WINEPREFIX'] = prefix wine_config = LutrisConfig(runner_slug='wine') if not wine_config.system_config['disable_runtime'] and not runtime.is_disabled(): env['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths()) command = [wine_path] if executable: command.append(executable) command += shlex.split(args) if blocking: return system.execute(command, env=env, cwd=working_dir) else: thread = LutrisThread(command, runner=wine(), env=env, cwd=working_dir) thread.start() return thread
def _get_graphics_adapters(): """Return the list of graphics cards available on a system Returns: list: list of tuples containing PCI ID and description of the display controller """ lspci_path = system.find_executable("lspci") dev_subclasses = ["VGA", "XGA", "3D controller", "Display controller"] if not lspci_path: logger.warning( "lspci is not available. List of graphics cards not available") return [] return [(pci_id, device_desc.split(": ")[1]) for pci_id, device_desc in [ line.split(maxsplit=1) for line in system.execute(lspci_path, timeout=3).split("\n") if any(subclass in line for subclass in dev_subclasses) ]]
def desktop_effects(self, enable): if enable: system.execute(self.start_compositor, shell=True) else: if os.environ.get('DESKTOP_SESSION') == "plasma": self.stop_compositor = "qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.suspend" self.start_compositor = "qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.resume" elif os.environ.get('DESKTOP_SESSION') == "mate" and system.execute("gsettings get org.mate.Marco.general compositing-manager", shell=True) == 'true': self.stop_compositor = "gsettings set org.mate.Marco.general compositing-manager false" self.start_compositor = "gsettings set org.mate.Marco.general compositing-manager true" elif os.environ.get('DESKTOP_SESSION') == "xfce" and system.execute("xfconf-query --channel=xfwm4 --property=/general/use_compositing", shell=True) == 'true': self.stop_compositor = "xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=false" self.start_compositor = "xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=true" if not (self.compositor_disabled or self.stop_compositor == ""): system.execute(self.stop_compositor, shell=True) self.compositor_disabled = True;
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None, working_dir=None, winetricks_wine='', blocking=False, config=None, include_processes=[]): """ Execute a Wine command. Args: executable (str): wine program to run, pass None to run wine itself args (str): program arguments wine_path (str): path to the wine version to use prefix (str): path to the wine prefix to use arch (str): wine architecture of the prefix working_dir (str): path to the working dir for the process winetricks_wine (str): path to the wine version used by winetricks blocking (bool): if true, do not run the process in a thread config (LutrisConfig): LutrisConfig object for the process context watch (list): list of process names to monitor (even when in a ignore list) Returns: Process results if the process is running in blocking mode or LutrisThread instance otherwise. """ detected_arch = detect_prefix_arch(prefix) executable = str(executable) if executable else '' if arch not in ('win32', 'win64'): arch = detected_arch or 'win32' if not wine_path: wine_path = wine().get_executable() if not working_dir: if os.path.isfile(executable): working_dir = os.path.dirname(executable) if executable.endswith(".msi"): args = '/i "%s"' % executable executable = 'msiexec' # Create prefix if necessary if not detected_arch: wine_bin = winetricks_wine if winetricks_wine else wine_path create_prefix(prefix, wine_path=wine_bin, arch=arch) env = { 'WINEARCH': arch } if winetricks_wine: env['WINE'] = winetricks_wine else: env['WINE'] = wine_path if prefix: env['WINEPREFIX'] = prefix wine_config = config or LutrisConfig(runner_slug='wine') if not wine_config.system_config['disable_runtime'] and not runtime.is_disabled(): env['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths()) command = [wine_path] if executable: command.append(executable) command += shlex.split(args) if blocking: return system.execute(command, env=env, cwd=working_dir) else: thread = LutrisThread(command, runner=wine(), env=env, cwd=working_dir, include_processes=include_processes) thread.start() return thread
def wineexec( executable, args="", wine_path=None, prefix=None, arch=None, # pylint: disable=too-many-locals working_dir=None, winetricks_wine="", blocking=False, config=None, include_processes=[], exclude_processes=[], disable_runtime=False, env={}, overrides=None, ): """ Execute a Wine command. Args: executable (str): wine program to run, pass None to run wine itself args (str): program arguments wine_path (str): path to the wine version to use prefix (str): path to the wine prefix to use arch (str): wine architecture of the prefix working_dir (str): path to the working dir for the process winetricks_wine (str): path to the wine version used by winetricks blocking (bool): if true, do not run the process in a thread config (LutrisConfig): LutrisConfig object for the process context watch (list): list of process names to monitor (even when in a ignore list) Returns: Process results if the process is running in blocking mode or MonitoredCommand instance otherwise. """ executable = str(executable) if executable else "" if isinstance(include_processes, str): include_processes = shlex.split(include_processes) if isinstance(exclude_processes, str): exclude_processes = shlex.split(exclude_processes) if not wine_path: wine = import_runner("wine") wine_path = wine().get_executable() if not wine_path: raise RuntimeError("Wine is not installed") if not working_dir: if os.path.isfile(executable): working_dir = os.path.dirname(executable) executable, _args, working_dir = get_real_executable(executable, working_dir) if _args: args = '{} "{}"'.format(_args[0], _args[1]) # Create prefix if necessary if arch not in ("win32", "win64"): arch = detect_arch(prefix, wine_path) if not detect_prefix_arch(prefix): wine_bin = winetricks_wine if winetricks_wine else wine_path create_prefix(prefix, wine_path=wine_bin, arch=arch) wineenv = {"WINEARCH": arch} if winetricks_wine: wineenv["WINE"] = winetricks_wine else: wineenv["WINE"] = wine_path if prefix: wineenv["WINEPREFIX"] = prefix wine_config = config or LutrisConfig(runner_slug="wine") disable_runtime = disable_runtime or wine_config.system_config["disable_runtime"] if use_lutris_runtime(wine_path=wineenv["WINE"], force_disable=disable_runtime): if WINE_DIR in wine_path: wine_root_path = os.path.dirname(os.path.dirname(wine_path)) elif WINE_DIR in winetricks_wine: wine_root_path = os.path.dirname(os.path.dirname(winetricks_wine)) else: wine_root_path = None wineenv["LD_LIBRARY_PATH"] = ":".join( runtime.get_paths( prefer_system_libs=wine_config.system_config["prefer_system_libs"], wine_path=wine_root_path, ) ) if overrides: wineenv["WINEDLLOVERRIDES"] = get_overrides_env(overrides) wineenv.update(env) command_parameters = [wine_path] if executable: command_parameters.append(executable) command_parameters += shlex.split(args) if blocking: return system.execute(command_parameters, env=wineenv, cwd=working_dir) wine = import_runner("wine") command = MonitoredCommand( command_parameters, runner=wine(), env=wineenv, cwd=working_dir, include_processes=include_processes, exclude_processes=exclude_processes, ) command.start() return command
def create_prefix( prefix, wine_path=None, arch=WINE_DEFAULT_ARCH, overrides={}, install_gecko=None, install_mono=None, ): """Create a new Wine prefix.""" if not prefix: raise ValueError("No Wine prefix path given") logger.info("Creating a %s prefix in %s", arch, prefix) # Follow symlinks, don't delete existing ones as it would break some setups if os.path.islink(prefix): prefix = os.readlink(prefix) # Avoid issue of 64bit Wine refusing to create win32 prefix # over an existing empty folder. if os.path.isdir(prefix) and not os.listdir(prefix): os.rmdir(prefix) if not wine_path: wine = import_runner("wine") wine_path = wine().get_executable() if not wine_path: logger.error("Wine not found, can't create prefix") return wineboot_path = os.path.join(os.path.dirname(wine_path), "wineboot") if not system.path_exists(wineboot_path): logger.error( "No wineboot executable found in %s, " "your wine installation is most likely broken", wine_path, ) return if install_gecko == "False": overrides["mshtml"] = "disabled" if install_mono == "False": overrides["mscoree"] = "disabled" wineenv = { "WINEARCH": arch, "WINEPREFIX": prefix, "WINEDLLOVERRIDES": get_overrides_env(overrides), } system.execute([wineboot_path], env=wineenv) for loop_index in range(50): time.sleep(0.25) if system.path_exists(os.path.join(prefix, "user.reg")): break if loop_index == 20: logger.warning("Wine prefix creation is taking longer than expected...") if not os.path.exists(os.path.join(prefix, "user.reg")): logger.error( "No user.reg found after prefix creation. " "Prefix might not be valid" ) return logger.info("%s Prefix created in %s", arch, prefix) prefix_manager = WinePrefixManager(prefix) prefix_manager.setup_defaults() if 'steamapps/common' in prefix.lower(): from lutris.runners.winesteam import winesteam runner = winesteam() logger.info("Transfering Steam information from default prefix to new prefix") dest_path = '/tmp/steam.reg' default_prefix = runner.get_default_prefix(runner.default_arch) wineexec( "regedit", args=r"/E '%s' 'HKEY_CURRENT_USER\Software\Valve\Steam'" % dest_path, prefix=default_prefix ) set_regedit_file( dest_path, wine_path=wine_path, prefix=prefix, arch=arch ) try: os.remove(dest_path) except FileNotFoundError: logger.error("File %s was already removed", dest_path) steam_drive_path = os.path.join(prefix, 'dosdevices', 's:') if not system.path_exists(steam_drive_path): logger.info("Linking Steam default prefix to drive S:") os.symlink(os.path.join(default_prefix, 'drive_c'), steam_drive_path)
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None, working_dir=None, winetricks_wine='', blocking=False, config=None, include_processes=[], exclude_processes=[], disable_runtime=False, env={}, overrides=None): """ Execute a Wine command. Args: executable (str): wine program to run, pass None to run wine itself args (str): program arguments wine_path (str): path to the wine version to use prefix (str): path to the wine prefix to use arch (str): wine architecture of the prefix working_dir (str): path to the working dir for the process winetricks_wine (str): path to the wine version used by winetricks blocking (bool): if true, do not run the process in a thread config (LutrisConfig): LutrisConfig object for the process context watch (list): list of process names to monitor (even when in a ignore list) Returns: Process results if the process is running in blocking mode or LutrisThread instance otherwise. """ executable = str(executable) if executable else '' if not wine_path: wine_path = wine().get_executable() if not working_dir: if os.path.isfile(executable): working_dir = os.path.dirname(executable) executable, _args, working_dir = get_real_executable(executable, working_dir) if _args: args = '{} "{}"'.format(_args[0], _args[1]) # Create prefix if necessary detected_arch = detect_prefix_arch(prefix) if arch not in ('win32', 'win64'): arch = detected_arch or 'win32' if not detected_arch: wine_bin = winetricks_wine if winetricks_wine else wine_path create_prefix(prefix, wine_path=wine_bin, arch=arch) wineenv = { 'WINEARCH': arch } if winetricks_wine: wineenv['WINE'] = winetricks_wine else: wineenv['WINE'] = wine_path if prefix: wineenv['WINEPREFIX'] = prefix wine_config = config or LutrisConfig(runner_slug='wine') if ( not runtime.RUNTIME_DISABLED and not disable_runtime and not wine_config.system_config['disable_runtime'] ): wineenv['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths()) if overrides: wineenv['WINEDLLOVERRIDES'] = get_overrides_env(overrides) wineenv.update(env) command = [wine_path] if executable: command.append(executable) command += shlex.split(args) if blocking: return system.execute(command, env=wineenv, cwd=working_dir) else: thread = LutrisThread(command, runner=wine(), env=wineenv, cwd=working_dir, include_processes=include_processes, exclude_processes=exclude_processes) thread.start() return thread
def wineexec( executable, args="", wine_path=None, prefix=None, arch=None, # pylint: disable=too-many-locals working_dir=None, winetricks_wine='', blocking=False, config=None, include_processes=[], exclude_processes=[], disable_runtime=False, env={}, overrides=None): """ Execute a Wine command. Args: executable (str): wine program to run, pass None to run wine itself args (str): program arguments wine_path (str): path to the wine version to use prefix (str): path to the wine prefix to use arch (str): wine architecture of the prefix working_dir (str): path to the working dir for the process winetricks_wine (str): path to the wine version used by winetricks blocking (bool): if true, do not run the process in a thread config (LutrisConfig): LutrisConfig object for the process context watch (list): list of process names to monitor (even when in a ignore list) Returns: Process results if the process is running in blocking mode or LutrisThread instance otherwise. """ executable = str(executable) if executable else '' if not wine_path: wine = import_runner('wine') wine_path = wine().get_executable() if not wine_path: raise RuntimeError("Wine is not installed") if not working_dir: if os.path.isfile(executable): working_dir = os.path.dirname(executable) executable, _args, working_dir = get_real_executable( executable, working_dir) if _args: args = '{} "{}"'.format(_args[0], _args[1]) # Create prefix if necessary if arch not in ('win32', 'win64'): arch = detect_arch(prefix, wine_path) if not detect_prefix_arch(prefix): wine_bin = winetricks_wine if winetricks_wine else wine_path create_prefix(prefix, wine_path=wine_bin, arch=arch) wineenv = {'WINEARCH': arch} if winetricks_wine: wineenv['WINE'] = winetricks_wine else: wineenv['WINE'] = wine_path if prefix: wineenv['WINEPREFIX'] = prefix wine_config = config or LutrisConfig(runner_slug='wine') disable_runtime = disable_runtime or wine_config.system_config[ 'disable_runtime'] if use_lutris_runtime(wine_path=wineenv['WINE'], force_disable=disable_runtime): if WINE_DIR in wine_path: wine_root_path = os.path.dirname(os.path.dirname(wine_path)) elif WINE_DIR in winetricks_wine: wine_root_path = os.path.dirname(os.path.dirname(winetricks_wine)) else: wine_root_path = None wineenv['LD_LIBRARY_PATH'] = ':'.join( runtime.get_paths(prefer_system_libs=wine_config. system_config['prefer_system_libs'], wine_path=wine_root_path)) if overrides: wineenv['WINEDLLOVERRIDES'] = get_overrides_env(overrides) wineenv.update(env) command = [wine_path] if executable: command.append(executable) command += shlex.split(args) if blocking: return system.execute(command, env=wineenv, cwd=working_dir) wine = import_runner('wine') thread = LutrisThread(command, runner=wine(), env=wineenv, cwd=working_dir, include_processes=include_processes, exclude_processes=exclude_processes) thread.start() return thread
def create_prefix( prefix, wine_path=None, arch=WINE_DEFAULT_ARCH, overrides={}, install_gecko=None, install_mono=None, ): """Create a new Wine prefix.""" if not prefix: raise ValueError("No Wine prefix path given") logger.info("Creating a %s prefix in %s", arch, prefix) # Follow symlinks, don't delete existing ones as it would break some setups if os.path.islink(prefix): prefix = os.readlink(prefix) # Avoid issue of 64bit Wine refusing to create win32 prefix # over an existing empty folder. if os.path.isdir(prefix) and not os.listdir(prefix): os.rmdir(prefix) if not wine_path: wine = import_runner("wine") wine_path = wine().get_executable() if not wine_path: logger.error("Wine not found, can't create prefix") return wineboot_path = os.path.join(os.path.dirname(wine_path), "wineboot") if not system.path_exists(wineboot_path): logger.error( "No wineboot executable found in %s, " "your wine installation is most likely broken", wine_path, ) return if install_gecko == "False": overrides["mshtml"] = "disabled" if install_mono == "False": overrides["mscoree"] = "disabled" wineenv = { "WINEARCH": arch, "WINEPREFIX": prefix, "WINEDLLOVERRIDES": get_overrides_env(overrides), } system.execute([wineboot_path], env=wineenv) for loop_index in range(50): time.sleep(0.25) if system.path_exists(os.path.join(prefix, "user.reg")): break if loop_index == 20: logger.warning( "Wine prefix creation is taking longer than expected...") if not os.path.exists(os.path.join(prefix, "user.reg")): logger.error("No user.reg found after prefix creation. " "Prefix might not be valid") return logger.info("%s Prefix created in %s", arch, prefix) prefix_manager = WinePrefixManager(prefix) prefix_manager.setup_defaults() if 'steamapps/common' in prefix.lower(): from lutris.runners.winesteam import winesteam runner = winesteam() logger.info( "Transfering Steam information from default prefix to new prefix") dest_path = '/tmp/steam.reg' default_prefix = runner.get_default_prefix(runner.default_arch) wineexec("regedit", args=r"/E '%s' 'HKEY_CURRENT_USER\Software\Valve\Steam'" % dest_path, prefix=default_prefix) set_regedit_file(dest_path, wine_path=wine_path, prefix=prefix, arch=arch) try: os.remove(dest_path) except FileNotFoundError: logger.error("File %s was already removed", dest_path) steam_drive_path = os.path.join(prefix, 'dosdevices', 's:') if not system.path_exists(steam_drive_path): logger.info("Linking Steam default prefix to drive S:") os.symlink(os.path.join(default_prefix, 'drive_c'), steam_drive_path)
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None, working_dir=None, winetricks_wine='', blocking=False, config=None, include_processes=[]): """ Execute a Wine command. Args: executable (str): wine program to run, pass None to run wine itself args (str): program arguments wine_path (str): path to the wine version to use prefix (str): path to the wine prefix to use arch (str): wine architecture of the prefix working_dir (str): path to the working dir for the process winetricks_wine (str): path to the wine version used by winetricks blocking (bool): if true, do not run the process in a thread config (LutrisConfig): LutrisConfig object for the process context watch (list): list of process names to monitor (even when in a ignore list) Returns: Process results if the process is running in blocking mode or LutrisThread instance otherwise. """ detected_arch = detect_prefix_arch(prefix) executable = str(executable) if executable else '' if arch not in ('win32', 'win64'): arch = detected_arch or 'win32' if not wine_path: wine_path = wine().get_executable() if not working_dir: if os.path.isfile(executable): working_dir = os.path.dirname(executable) executable, _args = get_real_executable(executable) if _args: args = '{} "{}"'.format(_args[0], _args[1]) # Create prefix if necessary if not detected_arch: wine_bin = winetricks_wine if winetricks_wine else wine_path create_prefix(prefix, wine_path=wine_bin, arch=arch) env = { 'WINEARCH': arch } if winetricks_wine: env['WINE'] = winetricks_wine else: env['WINE'] = wine_path if prefix: env['WINEPREFIX'] = prefix wine_config = config or LutrisConfig(runner_slug='wine') if not wine_config.system_config['disable_runtime'] and not runtime.is_disabled(): env['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths()) command = [wine_path] if executable: command.append(executable) command += shlex.split(args) if blocking: return system.execute(command, env=env, cwd=working_dir) else: thread = LutrisThread(command, runner=wine(), env=env, cwd=working_dir, include_processes=include_processes) thread.start() return thread