diff --git a/ulwgl_consts.py b/ulwgl_consts.py new file mode 100644 index 0000000..dd1a4c5 --- /dev/null +++ b/ulwgl_consts.py @@ -0,0 +1,26 @@ +from enum import Enum +from logging import INFO, WARNING, DEBUG, ERROR + +SIMPLE_FORMAT = "%(levelname)s: %(message)s" + +DEBUG_FORMAT = "%(levelname)s [%(module)s.%(funcName)s:%(lineno)s]:%(message)s" + + +class Level(Enum): + """Represent the Log level values for the logger module.""" + + INFO = INFO + WARNING = WARNING + DEBUG = DEBUG + ERROR = ERROR + + +class Color(Enum): + """Represent the color to be applied to a string.""" + + RESET = "\u001b[0m" + INFO = "\u001b[34m" + WARNING = "\033[33m" + ERROR = "\033[31m" + BOLD = "\033[1m" + DEBUG = "\u001b[35m" diff --git a/ulwgl_log.py b/ulwgl_log.py new file mode 100644 index 0000000..8f2fa76 --- /dev/null +++ b/ulwgl_log.py @@ -0,0 +1,13 @@ +import logging +from sys import stderr +from ulwgl_consts import SIMPLE_FORMAT, DEBUG_FORMAT + +simple_formatter = logging.Formatter(SIMPLE_FORMAT) +debug_formatter = logging.Formatter(DEBUG_FORMAT) + +log = logging.getLogger(__name__) + +console_handler = logging.StreamHandler(stream=stderr) +console_handler.setFormatter(simple_formatter) +log.addHandler(console_handler) +log.setLevel(logging.CRITICAL + 1) diff --git a/ulwgl_run.py b/ulwgl_run.py index 6e29a14..c42ab99 100755 --- a/ulwgl_run.py +++ b/ulwgl_run.py @@ -11,6 +11,9 @@ from ulwgl_plugins import enable_steam_game_drive, set_env_toml from re import match import subprocess from ulwgl_dl_util import get_ulwgl_proton +from ulwgl_consts import Level +from ulwgl_util import msg +from ulwgl_log import log, console_handler, debug_formatter verbs: Set[str] = { "waitforexitandrun", @@ -34,6 +37,7 @@ example usage: WINEPREFIX= GAMEID= PROTONPATH= {exe} "" WINEPREFIX= GAMEID= PROTONPATH= PROTON_VERB= {exe} /home/foo/example.exe WINEPREFIX= GAMEID= PROTONPATH= STORE= {exe} /home/foo/example.exe + ULWGL_LOG= GAMEID= {exe} /home/foo/example.exe {exe} --config /home/foo/example.toml """ parser: ArgumentParser = argparse.ArgumentParser( @@ -59,6 +63,27 @@ example usage: return sys.argv[1], sys.argv[2:] +def set_log() -> None: + """Adjust the log level for the logger.""" + levels: Set[str] = {"1", "warn", "debug"} + + if os.environ["ULWGL_LOG"] not in levels: + return + + if os.environ["ULWGL_LOG"] == "1": + # Show the envvars and command at this level + log.setLevel(level=Level.INFO.value) + elif os.environ["ULWGL_LOG"] == "warn": + log.setLevel(level=Level.WARNING.value) + elif os.environ["ULWGL_LOG"] == "debug": + # Show all logs + console_handler.setFormatter(debug_formatter) + log.addHandler(console_handler) + log.setLevel(level=Level.DEBUG.value) + + os.environ.pop("ULWGL_LOG") + + def setup_pfx(path: str) -> None: """Create a symlink to the WINE prefix and tracked_files file.""" pfx: Path = Path(path).joinpath("pfx").expanduser() @@ -115,8 +140,6 @@ def check_env( else: env["PROTONPATH"] = os.environ["PROTONPATH"] - print(env["PROTONPATH"], file=sys.stderr) - # If download fails/doesn't exist in the system, raise an error if not os.environ["PROTONPATH"]: err: str = "Download failed.\nProton could not be found in cache or compatibilitytools.d\nPlease set $PROTONPATH or visit https://github.com/Open-Wine-Components/ULWGL-Proton/releases" @@ -250,6 +273,9 @@ def main() -> int: # noqa: D103 args: Union[Namespace, Tuple[str, List[str]]] = parse_args() opts: List[str] = None + if "ULWGL_LOG" in os.environ: + set_log() + if isinstance(args, Namespace) and getattr(args, "config", None): set_env_toml(env, args) else: @@ -266,15 +292,21 @@ def main() -> int: # noqa: D103 # Set all environment variables # NOTE: `env` after this block should be read only for key, val in env.items(): + log.info(msg(f"{key}={val}", Level.INFO)) os.environ[key] = val build_command(env, command, opts) + log.debug(msg(command, Level.DEBUG)) return subprocess.run(command).returncode if __name__ == "__main__": try: sys.exit(main()) + except KeyboardInterrupt: + # Until Reaper is part of the command sequence, spawned process may still be alive afterwards + log.warning(msg("Keyboard Interrupt", Level.WARNING)) + sys.exit(1) except Exception as e: # noqa: BLE001 print_exception(e) sys.exit(1) diff --git a/ulwgl_util.py b/ulwgl_util.py new file mode 100644 index 0000000..b096059 --- /dev/null +++ b/ulwgl_util.py @@ -0,0 +1,20 @@ +from ulwgl_consts import Color, Level +from typing import Any + + +def msg(msg: Any, level: Level): + """Return a log message depending on the log level. + + The message will bolden the typeface and apply a color. + Expects the first parameter to be a string or implement __str__ + """ + log: str = "" + + if level == Level.INFO: + log = f"{Color.BOLD.value}{Color.INFO.value}{msg}{Color.RESET.value}" + elif level == Level.WARNING: + log = f"{Color.BOLD.value}{Color.WARNING.value}{msg}{Color.RESET.value}" + elif level == Level.DEBUG: + log = f"{Color.BOLD.value}{Color.DEBUG.value}{msg}{Color.RESET.value}" + + return log