1
0
Fork 1
mirror of https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git synced 2025-07-13 11:29:46 +03:00

core: introduce global context (MR 2252)

We can't totally escape the need for some runtime state defined by args.
To make the migration easier, introduce a global "Context" class and
move some of the read-only global options there.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
This commit is contained in:
Caleb Connolly 2024-05-24 17:57:31 +02:00 committed by Oliver Smith
parent b82c4eb167
commit 2a7c769e14
No known key found for this signature in database
GPG key ID: 5AE7F5513E0885CB
6 changed files with 56 additions and 11 deletions

View file

@ -29,10 +29,11 @@ if version < (3, 9):
sys.exit() 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) # Hints about the log file (print to stdout only)
log_hint = "Run 'pmbootstrap log' for details." 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" log_hint += (" Alternatively you can use '--details-to-stdout' to get more"
" output, e.g. 'pmbootstrap --details-to-stdout init'.") " output, e.g. 'pmbootstrap --details-to-stdout init'.")
print() print()
@ -93,12 +94,12 @@ def main() -> int:
except BuildFailedError as exception: except BuildFailedError as exception:
logging.error(f"ERROR: {exception}") logging.error(f"ERROR: {exception}")
print_log_hint(args) print_log_hint()
return 3 return 3
except Exception as e: except Exception as e:
# Dump log to stdout when args (and therefore logging) init failed # Dump log to stdout when args (and therefore logging) init failed
if not args: if "args" not in locals():
import logging as pylogging import logging as pylogging
pylogging.getLogger().setLevel(logging.DEBUG) pylogging.getLogger().setLevel(logging.DEBUG)
@ -106,7 +107,7 @@ def main() -> int:
logging.info("See also: <https://postmarketos.org/troubleshooting>") logging.info("See also: <https://postmarketos.org/troubleshooting>")
logging.debug(traceback.format_exc()) logging.debug(traceback.format_exc())
print_log_hint(args) print_log_hint()
print() print()
print("Before you report this error, ensure that pmbootstrap is " print("Before you report this error, ensure that pmbootstrap is "
"up to date.") "up to date.")

View file

@ -2,3 +2,16 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from pmb.core.chroot import Chroot, ChrootType 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

15
pmb/core/context.py Normal file
View file

@ -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

View file

@ -54,7 +54,7 @@ class PmbArgs(Namespace):
config: Path config: Path
config_channels: str config_channels: str
details: bool details: bool
details_to_stdout: str details_to_stdout: bool
device: str device: str
deviceinfo: Dict[str, str] deviceinfo: Dict[str, str]
deviceinfo_parse_kernel: str deviceinfo_parse_kernel: str
@ -145,7 +145,7 @@ class PmbArgs(Namespace):
src: str src: str
ssh_keys: str ssh_keys: str
strict: str strict: str
sudo_timer: str sudo_timer: bool
suffix: str suffix: str
systemd: str systemd: str
timeout: float timeout: float

View file

@ -114,9 +114,23 @@ def init(args: PmbArgs) -> PmbArgs:
pmb.config.merge_with_args(args) pmb.config.merge_with_args(args)
replace_placeholders(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) # Initialize logs (we could raise errors below)
pmb.helpers.logging.init(args) 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 # Initialization code which may raise errors
check_pmaports_path(args) check_pmaports_path(args)
if args.action not in ["init", "checksum", "config", "bootimg_analyze", "log", if args.action not in ["init", "checksum", "config", "bootimg_analyze", "log",

View file

@ -1,6 +1,7 @@
# Copyright 2023 Oliver Smith # Copyright 2023 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import fcntl import fcntl
from pmb.core import get_context
from pmb.core.types import PathString, Env from pmb.core.types import PathString, Env
from pmb.helpers import logging from pmb.helpers import logging
import os import os
@ -175,6 +176,7 @@ def foreground_pipe(args: PmbArgs, cmd, working_dir=None, output_to_stdout=False
* output: "" * output: ""
* output: full program output string (output_return is True) * output: full program output string (output_return is True)
""" """
context = pmb.core.get_context()
# Start process in background (stdout and stderr combined) # Start process in background (stdout and stderr combined)
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, cwd=working_dir, 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] = [] output_buffer: list[bytes] = []
sel = selectors.DefaultSelector() sel = selectors.DefaultSelector()
sel.register(stdout, selectors.EVENT_READ) sel.register(stdout, selectors.EVENT_READ)
timeout = args.timeout timeout = context.command_timeout
while process.poll() is None: while process.poll() is None:
wait_start = time.perf_counter() wait_start = time.perf_counter()
sel.select(timeout) sel.select(timeout)
@ -203,12 +205,12 @@ def foreground_pipe(args: PmbArgs, cmd, working_dir=None, output_to_stdout=False
# timeout was not reached.) # timeout was not reached.)
if output_timeout: if output_timeout:
wait_end = time.perf_counter() 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 " + 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" logging.info("NOTE: The timeout can be increased with"
" 'pmbootstrap -t'.") " 'pmbootstrap -t'.")
kill_command(args, process.pid, sudo) kill_command(process.pid, sudo)
continue continue
# Read all currently available output # Read all currently available output