pmb.helpers.run_core: add output=pipe (MR 1996)
This adds a new output mode "pipe" that is identical to the existing "background" mode except for that its stdout is redirected into a pipe so that it can be retrieved.
This commit is contained in:
parent
82d149c85d
commit
45dbeca587
|
@ -20,7 +20,7 @@ def sanity_checks(output="log", output_return=False, check=None,
|
||||||
Raise an exception if the parameters passed to core() don't make sense
|
Raise an exception if the parameters passed to core() don't make sense
|
||||||
(all parameters are described in core() below).
|
(all parameters are described in core() below).
|
||||||
"""
|
"""
|
||||||
if output not in ["log", "stdout", "interactive", "tui", "background"]:
|
if output not in ["log", "stdout", "interactive", "tui", "background", "pipe"]:
|
||||||
raise RuntimeError("Invalid output value: " + str(output))
|
raise RuntimeError("Invalid output value: " + str(output))
|
||||||
|
|
||||||
# Prevent setting the check parameter with output="background".
|
# Prevent setting the check parameter with output="background".
|
||||||
|
@ -45,6 +45,14 @@ def background(args, cmd, working_dir=None):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def pipe(args, cmd, working_dir=None):
|
||||||
|
""" Run a subprocess in background and redirect its output to a pipe. """
|
||||||
|
ret = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=args.logfd,
|
||||||
|
cwd=working_dir)
|
||||||
|
logging.verbose(f"New background process: pid={ret.pid}, output=pipe")
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def pipe_read(args, process, output_to_stdout=False, output_return=False,
|
def pipe_read(args, process, output_to_stdout=False, output_return=False,
|
||||||
output_return_buffer=False):
|
output_return_buffer=False):
|
||||||
"""
|
"""
|
||||||
|
@ -215,14 +223,16 @@ def core(args, log_message, cmd, working_dir=None, output="log",
|
||||||
"stdout", "interactive", "background"), so it's easy to
|
"stdout", "interactive", "background"), so it's easy to
|
||||||
trace what pmbootstrap does.
|
trace what pmbootstrap does.
|
||||||
|
|
||||||
The exception is "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
|
it does not make sense to write to the log file (think of
|
||||||
ncurses UIs, such as "menuconfig").
|
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" or
|
When the output is not set to "interactive", "tui",
|
||||||
"background", we kill the process if it does not output
|
"background" or "pipe", we kill the process if it does not
|
||||||
anything for 5 minutes (time can be set with "pmbootstrap
|
output anything for 5 minutes (time can be set with
|
||||||
--timeout").
|
"pmbootstrap --timeout").
|
||||||
|
|
||||||
The table below shows all possible values along with
|
The table below shows all possible values along with
|
||||||
their properties. "wait" indicates that we wait for the
|
their properties. "wait" indicates that we wait for the
|
||||||
|
@ -235,18 +245,20 @@ def core(args, log_message, cmd, working_dir=None, output="log",
|
||||||
"interactive" | | x | x | x
|
"interactive" | | x | x | x
|
||||||
"tui" | | | x | x
|
"tui" | | | x | x
|
||||||
"background" | | x | |
|
"background" | | x | |
|
||||||
|
"pipe" | | | |
|
||||||
|
|
||||||
:param output_return: in addition to writing the program's output to the
|
:param output_return: in addition to writing the program's output to the
|
||||||
destinations above in real time, write to a buffer
|
destinations above in real time, write to a buffer
|
||||||
and return it as string when the command has
|
and return it as string when the command has
|
||||||
completed. This is not possible when output is
|
completed. This is not possible when output is
|
||||||
"background" or "tui".
|
"background", "pipe" or "tui".
|
||||||
:param check: an exception will be raised when the command's return code
|
:param check: an exception will be raised when the command's return code
|
||||||
is not 0. Set this to False to disable the check. This
|
is not 0. Set this to False to disable the check. This
|
||||||
parameter can not be used when the output is "background".
|
parameter can not be used when the output is "background" or
|
||||||
|
"pipe".
|
||||||
:param kill_as_root: use sudo to kill the process when it hits the timeout.
|
:param kill_as_root: use sudo to kill the process when it hits the timeout.
|
||||||
:returns: * program's return code (default)
|
:returns: * program's return code (default)
|
||||||
* subprocess.Popen instance (output is "background")
|
* subprocess.Popen instance (output is "background" or "pipe")
|
||||||
* the program's entire output (output_return is True)
|
* the program's entire output (output_return is True)
|
||||||
"""
|
"""
|
||||||
sanity_checks(output, output_return, check, kill_as_root)
|
sanity_checks(output, output_return, check, kill_as_root)
|
||||||
|
@ -259,6 +271,10 @@ def core(args, log_message, cmd, working_dir=None, output="log",
|
||||||
if output == "background":
|
if output == "background":
|
||||||
return background(args, cmd, working_dir)
|
return background(args, cmd, working_dir)
|
||||||
|
|
||||||
|
# Pipe
|
||||||
|
if output == "pipe":
|
||||||
|
return pipe(args, cmd, working_dir)
|
||||||
|
|
||||||
# Foreground
|
# Foreground
|
||||||
output_after_run = ""
|
output_after_run = ""
|
||||||
if output == "tui":
|
if output == "tui":
|
||||||
|
|
|
@ -56,6 +56,20 @@ def test_background(args):
|
||||||
assert process.poll() is None
|
assert process.poll() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_pipe(args):
|
||||||
|
# Sleep in background
|
||||||
|
process = pmb.helpers.run_core.pipe(args, ["sleep", "1"], "/")
|
||||||
|
|
||||||
|
# Check if it is still running
|
||||||
|
assert process.poll() is None
|
||||||
|
|
||||||
|
# Print output in background
|
||||||
|
process = pmb.helpers.run_core.pipe(args, ["echo", "-n", "hello"], "/")
|
||||||
|
|
||||||
|
# Read output
|
||||||
|
assert process.communicate()[0].decode('utf-8') == "hello"
|
||||||
|
|
||||||
|
|
||||||
def test_foreground_pipe(args):
|
def test_foreground_pipe(args):
|
||||||
func = pmb.helpers.run_core.foreground_pipe
|
func = pmb.helpers.run_core.foreground_pipe
|
||||||
cmd = ["echo", "test"]
|
cmd = ["echo", "test"]
|
||||||
|
|
Loading…
Reference in New Issue