diff --git a/pmb/__init__.py b/pmb/__init__.py index 43787957..fce6e025 100644 --- a/pmb/__init__.py +++ b/pmb/__init__.py @@ -29,10 +29,11 @@ if version < (3, 9): sys.exit() -def print_log_hint(args: Any) -> None: +def print_log_hint() -> None: + log = config.get("log") # Hints about the log file (print to stdout only) log_hint = "Run 'pmbootstrap log' for details." - if not args or not os.path.exists(args.log): + if not os.path.exists(log): log_hint += (" Alternatively you can use '--details-to-stdout' to get more" " output, e.g. 'pmbootstrap --details-to-stdout init'.") print() @@ -93,12 +94,12 @@ def main() -> int: except BuildFailedError as exception: logging.error(f"ERROR: {exception}") - print_log_hint(args) + print_log_hint() return 3 except Exception as e: # Dump log to stdout when args (and therefore logging) init failed - if not args: + if "args" not in locals(): import logging as pylogging pylogging.getLogger().setLevel(logging.DEBUG) @@ -106,7 +107,7 @@ def main() -> int: logging.info("See also: ") logging.debug(traceback.format_exc()) - print_log_hint(args) + print_log_hint() print() print("Before you report this error, ensure that pmbootstrap is " "up to date.") diff --git a/pmb/core/__init__.py b/pmb/core/__init__.py index ca808cd4..25f445c3 100644 --- a/pmb/core/__init__.py +++ b/pmb/core/__init__.py @@ -2,3 +2,16 @@ # SPDX-License-Identifier: GPL-3.0-or-later from pmb.core.chroot import Chroot, ChrootType +from pmb.core.context import Context + +__context: Context + +def get_context() -> Context: + """Get immutable global runtime context.""" + global __context + + # We must defer this to first call to avoid + # circular imports. + if "__context" not in globals(): + __context = Context() + return __context diff --git a/pmb/core/context.py b/pmb/core/context.py new file mode 100644 index 00000000..4d96d66b --- /dev/null +++ b/pmb/core/context.py @@ -0,0 +1,15 @@ +# Copyright 2024 Caleb Connolly +# SPDX-License-Identifier: GPL-3.0-or-later + +"""Global runtime context""" + +class Context(): + details_to_stdout: bool + quiet: bool + command_timeout: float + sudo_timer: bool + + def __init__(self): + self.details_to_stdout = False + self.command_timeout = 0 + self.sudo_timer = False diff --git a/pmb/core/types.py b/pmb/core/types.py index d989c7ee..e1f967e5 100644 --- a/pmb/core/types.py +++ b/pmb/core/types.py @@ -54,7 +54,7 @@ class PmbArgs(Namespace): config: Path config_channels: str details: bool - details_to_stdout: str + details_to_stdout: bool device: str deviceinfo: Dict[str, str] deviceinfo_parse_kernel: str @@ -145,7 +145,7 @@ class PmbArgs(Namespace): src: str ssh_keys: str strict: str - sudo_timer: str + sudo_timer: bool suffix: str systemd: str timeout: float diff --git a/pmb/helpers/args.py b/pmb/helpers/args.py index 3d96e66c..0ae4f609 100644 --- a/pmb/helpers/args.py +++ b/pmb/helpers/args.py @@ -114,9 +114,23 @@ def init(args: PmbArgs) -> PmbArgs: pmb.config.merge_with_args(args) replace_placeholders(args) + # Configure runtime context + context = pmb.core.get_context() + context.command_timeout = args.timeout + context.details_to_stdout = args.details_to_stdout + context.sudo_timer = args.sudo_timer + context.quiet = args.quiet + # Initialize logs (we could raise errors below) pmb.helpers.logging.init(args) + # Remove attributes from args so they don't get used by mistake + delattr(args, "timeout") + delattr(args, "details_to_stdout") + delattr(args, "sudo_timer") + delattr(args, "log") + delattr(args, "quiet") + # Initialization code which may raise errors check_pmaports_path(args) if args.action not in ["init", "checksum", "config", "bootimg_analyze", "log", diff --git a/pmb/helpers/run_core.py b/pmb/helpers/run_core.py index e4379fe7..48236bc9 100644 --- a/pmb/helpers/run_core.py +++ b/pmb/helpers/run_core.py @@ -1,6 +1,7 @@ # Copyright 2023 Oliver Smith # SPDX-License-Identifier: GPL-3.0-or-later import fcntl +from pmb.core import get_context from pmb.core.types import PathString, Env from pmb.helpers import logging import os @@ -175,6 +176,7 @@ def foreground_pipe(args: PmbArgs, cmd, working_dir=None, output_to_stdout=False * output: "" * output: full program output string (output_return is True) """ + context = pmb.core.get_context() # Start process in background (stdout and stderr combined) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=working_dir, @@ -193,7 +195,7 @@ def foreground_pipe(args: PmbArgs, cmd, working_dir=None, output_to_stdout=False output_buffer: list[bytes] = [] sel = selectors.DefaultSelector() sel.register(stdout, selectors.EVENT_READ) - timeout = args.timeout + timeout = context.command_timeout while process.poll() is None: wait_start = time.perf_counter() sel.select(timeout) @@ -203,12 +205,12 @@ def foreground_pipe(args: PmbArgs, cmd, working_dir=None, output_to_stdout=False # timeout was not reached.) if output_timeout: wait_end = time.perf_counter() - if wait_end - wait_start >= args.timeout: + if wait_end - wait_start >= timeout: logging.info("Process did not write any output for " + - str(args.timeout) + " seconds. Killing it.") + str(timeout) + " seconds. Killing it.") logging.info("NOTE: The timeout can be increased with" " 'pmbootstrap -t'.") - kill_command(args, process.pid, sudo) + kill_command(process.pid, sudo) continue # Read all currently available output