forked from Mirror/pmbootstrap
pmb: Make RunOutputTypeDefault and RunOutputTypePopen enums
This allows us to get rid of some of the validation in sanity_checks() as mypy handles this validation at "build time", and any typos in the enum instantiation would be a runtime error rather than a silent failure. Additionally, it allows us to encode some of the behaviour of the different output types into the type definition itself by using methods. Part-of: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/merge_requests/2642 (cherry picked from commit7d2f055bcb
) pmb: Fix PmbArgs containing a string for output While the annotations were changed to suggest that the output property of PmbArgs contains a RunOutputType, at runtime it actually contained a string because the argument parsing code hadn't been adapted to create a RunOutputType. Fix this, and also change it to RunOutputTypeDefault as while at it as that's more accurate. Fixes7d2f055bcb
Part-of: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/merge_requests/2644
This commit is contained in:
parent
3ea5a3433b
commit
861de1e507
21 changed files with 193 additions and 88 deletions
|
@ -2,7 +2,14 @@
|
|||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
import fcntl
|
||||
from pmb.core.context import get_context
|
||||
from pmb.types import PathString, Env, RunOutputType, RunReturnType
|
||||
from pmb.types import (
|
||||
PathString,
|
||||
Env,
|
||||
RunOutputType,
|
||||
RunOutputTypeDefault,
|
||||
RunOutputTypePopen,
|
||||
RunReturnType,
|
||||
)
|
||||
from pmb.helpers import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
@ -51,25 +58,23 @@ def flat_cmd(
|
|||
|
||||
|
||||
def sanity_checks(
|
||||
output: RunOutputType = "log", output_return: bool = False, check: bool | None = None
|
||||
output: RunOutputType = RunOutputTypeDefault.LOG,
|
||||
output_return: bool = False,
|
||||
check: bool | None = None,
|
||||
) -> None:
|
||||
"""Raise an exception if the parameters passed to core() don't make sense.
|
||||
|
||||
(all parameters are described in core() below).
|
||||
"""
|
||||
vals = ["log", "stdout", "interactive", "tui", "background", "pipe", "null"]
|
||||
if output not in vals:
|
||||
raise RuntimeError("Invalid output value: " + str(output))
|
||||
|
||||
# Prevent setting the check parameter with output="background".
|
||||
# The exit code won't be checked when running in background, so it would
|
||||
# always by check=False. But we prevent it from getting set to check=False
|
||||
# as well, so it does not look like you could change it to check=True.
|
||||
if check is not None and output == "background":
|
||||
if check is not None and output == RunOutputTypePopen.BACKGROUND:
|
||||
raise RuntimeError("Can't use check with output: background")
|
||||
|
||||
if output_return and output in ["tui", "background"]:
|
||||
raise RuntimeError("Can't use output_return with output: " + output)
|
||||
if output_return and output in [RunOutputTypeDefault.TUI, RunOutputTypePopen.BACKGROUND]:
|
||||
raise RuntimeError(f"Can't use output_return with output: {output}")
|
||||
|
||||
|
||||
def background(
|
||||
|
@ -361,7 +366,7 @@ def core(
|
|||
log_message: str,
|
||||
cmd: Sequence[PathString],
|
||||
working_dir: Path | None = None,
|
||||
output: RunOutputType = "log",
|
||||
output: RunOutputType = RunOutputTypeDefault.LOG,
|
||||
output_return: bool = False,
|
||||
check: bool | None = None,
|
||||
sudo: bool = False,
|
||||
|
@ -380,18 +385,18 @@ def core(
|
|||
:param working_dir: path in host system where the command should run
|
||||
:param output: where to write the output (stdout and stderr) of the
|
||||
process. We almost always write to the log file, which can
|
||||
be read with "pmbootstrap log" (output values: "log",
|
||||
"stdout", "interactive", "background"), so it's easy to
|
||||
be read with "pmbootstrap log" (output values: LOG,
|
||||
STDOUT, INTERACTIVE, BACKGROUND), so it's easy to
|
||||
trace what pmbootstrap does.
|
||||
|
||||
The exceptions are "tui" (text-based user interface), where
|
||||
The exceptions are TUI (text-based user interface), where
|
||||
it does not make sense to write to the log file (think of
|
||||
ncurses UIs, such as "menuconfig") and "pipe" where the
|
||||
output is written to a pipe for manual asynchronous
|
||||
consumption by the caller.
|
||||
|
||||
When the output is not set to "interactive", "tui",
|
||||
"background" or "pipe", we kill the process if it does not
|
||||
When the output is not set to INTERACTIVE, TUI,
|
||||
BACKGROUND or PIPE, we kill the process if it does not
|
||||
output anything for 5 minutes (time can be set with
|
||||
"pmbootstrap --timeout").
|
||||
|
||||
|
@ -399,17 +404,17 @@ def core(
|
|||
their properties. "wait" indicates that we wait for the
|
||||
process to complete.
|
||||
|
||||
============= ======= ========== ============= ==== ==========
|
||||
output value timeout out to log out to stdout wait pass stdin
|
||||
============= ======= ========== ============= ==== ==========
|
||||
"log" x x x
|
||||
"stdout" x x x x
|
||||
"interactive" x x x x
|
||||
"tui" x x x
|
||||
"background" x
|
||||
"pipe"
|
||||
"null"
|
||||
============= ======= ========== ============= ==== ==========
|
||||
============ ======= ========== ============= ==== ==========
|
||||
output value timeout out to log out to stdout wait pass stdin
|
||||
============ ======= ========== ============= ==== ==========
|
||||
LOG x x x
|
||||
STDOUT x x x x
|
||||
INTERACTIVE x x x x
|
||||
TUI x x x
|
||||
BACKGROUND x
|
||||
PIPE
|
||||
NULL
|
||||
============ ======= ========== ============= ==== ==========
|
||||
|
||||
:param output_return: in addition to writing the program's output to the
|
||||
destinations above in real time, write to a buffer and return it as string when the
|
||||
|
@ -438,34 +443,34 @@ def core(
|
|||
# raise e
|
||||
|
||||
# Background
|
||||
if output == "background":
|
||||
if output == RunOutputTypePopen.BACKGROUND:
|
||||
return background(cmd, working_dir)
|
||||
|
||||
# Pipe
|
||||
if output == "pipe":
|
||||
if output == RunOutputTypePopen.PIPE:
|
||||
return pipe(cmd, working_dir)
|
||||
|
||||
# Foreground
|
||||
output_after_run = ""
|
||||
if output == "tui":
|
||||
if output == RunOutputTypeDefault.TUI:
|
||||
# Foreground TUI
|
||||
code = foreground_tui(cmd, working_dir)
|
||||
else:
|
||||
# Foreground pipe (always redirects to the error log file)
|
||||
output_to_stdout = False
|
||||
if not context.details_to_stdout and output in ["stdout", "interactive"]:
|
||||
if not context.details_to_stdout and output.is_to_stdout():
|
||||
output_to_stdout = True
|
||||
|
||||
output_timeout = output in ["log", "stdout"] and not disable_timeout
|
||||
output_timeout = output.has_timeout() and not disable_timeout
|
||||
|
||||
stdin = subprocess.DEVNULL if output in ["log", "stdout"] else None
|
||||
stdin = None if output.has_pass_stdin() else subprocess.DEVNULL
|
||||
|
||||
(code, output_after_run) = foreground_pipe(
|
||||
cmd,
|
||||
working_dir,
|
||||
output_to_stdout,
|
||||
output_return,
|
||||
output != "null",
|
||||
output != RunOutputTypeDefault.NULL,
|
||||
output_timeout,
|
||||
sudo,
|
||||
stdin,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue