Source code for core.launcher

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Launching of programs, folders, URLs, etc.."""

import copy
import os
import re
import subprocess
import sys

from . import hacks, log, paths, terminal
from .lnp import lnp


[docs]def toggle_autoclose(): """Toggle automatic closing of the UI when launching DF.""" lnp.userconfig['autoClose'] = not lnp.userconfig.get_bool('autoClose') lnp.userconfig.save_data()
[docs]def get_df_executable(): """Returns the path of the executable needed to launch Dwarf Fortress.""" spawn_terminal = False if sys.platform == 'win32': if ('legacy' in lnp.df_info.variations and lnp.df_info.version <= '0.31.14'): df_filename = 'dwarfort.exe' else: df_filename = 'Dwarf Fortress.exe' elif sys.platform == 'darwin' and lnp.df_info.version <= '0.28.181.40d': df_filename = 'Dwarf Fortress.app' else: # Linux/OSX: Run DFHack if available and enabled if (os.path.isfile(paths.get('df', 'dfhack')) and hacks.is_dfhack_enabled()): df_filename = 'dfhack' spawn_terminal = True else: df_filename = 'df' if lnp.args.df_executable: df_filename = lnp.args.df_executable return df_filename, spawn_terminal
[docs]def run_df(force=False): """Launches Dwarf Fortress.""" validation_result = lnp.settings.validate_config() if validation_result: if not lnp.ui.on_invalid_config(validation_result): return None df_filename, spawn_terminal = get_df_executable() executable = paths.get('df', df_filename) result = run_program(executable, force, True, spawn_terminal) if (force and not result) or result is False: log.e('Could not launch ' + executable) raise Exception('Failed to run Dwarf Fortress.') for prog in lnp.autorun: utility = paths.get('utilities', prog) if os.access(utility, os.F_OK): run_program(utility) if lnp.userconfig.get_bool('autoClose'): sys.exit() return result
[docs]def run_program(path, force=False, is_df=False, spawn_terminal=False): """ Launches an external program. Args: path: the path of the program to launch. spawn_terminal: whether to spawn a new terminal for this app. Used only for DFHack. """ path = os.path.abspath(path) check_nonchild = ((spawn_terminal and sys.platform.startswith('linux')) or (sys.platform == 'darwin' and ( path.endswith('.app') or spawn_terminal))) is_running = program_is_running(path, check_nonchild) if not force and is_running: log.i(path + ' is already running') lnp.ui.on_program_running(path, is_df) return None try: workdir = os.path.dirname(path) run_args = path if spawn_terminal and not sys.platform.startswith('win'): run_args = terminal.get_terminal_command([path,]) elif path.endswith('.jar'): # Explicitly launch JAR files with Java run_args = ['java', '-jar', os.path.basename(path)] elif path.endswith('.app'): # OS X application bundle run_args = ['open', path] workdir = path environ = os.environ if lnp.bundle: # pylint: disable=protected-access environ = copy.deepcopy(os.environ) if ('TCL_LIBRARY' in environ and sys._MEIPASS in environ['TCL_LIBRARY']): del environ['TCL_LIBRARY'] if ('TK_LIBRARY' in environ and sys._MEIPASS in environ['TK_LIBRARY']): del environ['TK_LIBRARY'] if 'LD_LIBRARY_PATH' in environ: del environ['LD_LIBRARY_PATH'] if 'PYTHONPATH' in environ: del environ['PYTHONPATH'] with subprocess.Popen(run_args, cwd=workdir, env=environ) as p: lnp.running[path] = p return True except OSError: sys.excepthook(*sys.exc_info()) return False
[docs]def program_is_running(path, nonchild=False): """ Returns True if a program is currently running. Args: path: the path of the program. nonchild: if set to True, attempts to check for the process among all running processes, not just known child processes. Used for DFHack on Linux and OS X; currently unsupported for Windows. """ if nonchild: with subprocess.Popen(['ps', 'axww'], stdout=subprocess.PIPE) as ps: s = ps.stdout.read() encoding = sys.getfilesystemencoding() if encoding is None: # Encoding was not detected, assume UTF-8 encoding = 'UTF-8' s = s.decode(encoding, 'replace') return re.search('\\B%s( |$)' % re.escape(path), s, re.M) is not None if path not in lnp.running: return False lnp.running[path].poll() return lnp.running[path].returncode is None
[docs]def open_folder_idx(i): """Opens the folder specified by index i, as listed in PyLNP.json.""" open_file(os.path.join( paths.get('root'), lnp.config['folders'][i][1].replace( '<df>', paths.get('df'))))
[docs]def open_savegames(): """Opens the save game folder.""" open_file(paths.get('save'))
[docs]def open_url(url): """Launches a web browser to the Dwarf Fortress webpage.""" import webbrowser webbrowser.open(url)
[docs]def open_file(path): """ Opens a file with the system default viewer for the respective file type. Args: path: the file path to open. """ path = os.path.normpath(path) try: if sys.platform == 'darwin': subprocess.check_call(['open', '--', path]) elif sys.platform.startswith('linux'): subprocess.check_call(['xdg-open', path]) elif sys.platform in ['windows', 'win32']: os.startfile(path) else: log.e('Unknown platform, cannot open file') except Exception: log.e('Could not open file ' + path)