stderr will still be logged, but callers that don't care about what's
printed to stderr can ignore it.
---
pyanaconda/iutil.py | 30 ++++++++++++++++++++++++------
tests/pyanaconda_tests/iutil_test.py | 19 +++++++++++++++++++
2 files changed, 43 insertions(+), 6 deletions(-)
diff --git a/pyanaconda/iutil.py b/pyanaconda/iutil.py
index 97b9f35..2ee0ebb 100644
--- a/pyanaconda/iutil.py
+++ b/pyanaconda/iutil.py
@@ -161,21 +161,29 @@ def startProgram(argv, root='/', stdin=None,
stdout=subprocess.PIPE, stderr=subp
close_fds=True,
preexec_fn=preexec, cwd=root, env=env, **kwargs)
-def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None,
log_output=True, binary_output=False):
+def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None,
log_output=True,
+ binary_output=False, filter_stderr=False):
""" Run an external program, log the output and return it to the
caller
:param argv: The command to run and argument
:param root: The directory to chroot to before running command.
:param stdin: The file object to read stdin from.
- :param stdout: Optional file object to write stdout and stderr to.
+ :param stdout: Optional file object to write the output to.
:param env_prune: environment variable to remove before execution
:param log_output: whether to log the output of command
:param binary_output: whether to treat the output of command as binary data
+ :param filter_stderr: whether to exclude the contents of stderr from the returned
output
:return: The return code of the command and the output
"""
try:
- proc = startProgram(argv, root=root, stdin=stdin, env_prune=env_prune)
+ if filter_stderr:
+ stderr = subprocess.PIPE
+ else:
+ stderr = subprocess.STDOUT
- output_string = proc.communicate()[0]
+ proc = startProgram(argv, root=root, stdin=stdin, stdout=subprocess.PIPE,
stderr=stderr,
+ env_prune=env_prune)
+
+ (output_string, err_string) = proc.communicate()
if output_string:
if binary_output:
output_lines = [output_string]
@@ -192,6 +200,14 @@ def _run_program(argv, root='/', stdin=None, stdout=None,
env_prune=None, log_ou
if stdout:
stdout.write(output_string)
+ # If stderr was filtered, log it separately
+ if filter_stderr and err_string and log_output:
+ err_lines = err_string.splitlines(True)
+
+ with program_log_lock:
+ for line in err_lines:
+ program_log.info(line.strip())
+
except OSError as e:
with program_log_lock:
program_log.error("Error running %s: %s", argv[0], e.strerror)
@@ -234,13 +250,14 @@ def execWithRedirect(command, argv, stdin=None, stdout=None,
return _run_program(argv, stdin=stdin, stdout=stdout, root=root,
env_prune=env_prune,
log_output=log_output, binary_output=binary_output)[0]
-def execWithCapture(command, argv, stdin=None, root='/', log_output=True):
+def execWithCapture(command, argv, stdin=None, root='/', log_output=True,
filter_stderr=False):
""" Run an external program and capture standard out and err.
:param command: The command to run
:param argv: The argument list
:param stdin: The file object to read stdin from.
:param root: The directory to chroot to before running command.
:param log_output: Whether to log the output of command
+ :param filter_stderr: Whether stderr should be excluded from the returned output
:return: The output of the command
"""
if flags.testing:
@@ -249,7 +266,8 @@ def execWithCapture(command, argv, stdin=None, root='/',
log_output=True):
return ""
argv = [command] + argv
- return _run_program(argv, stdin=stdin, root=root, log_output=log_output)[1]
+ return _run_program(argv, stdin=stdin, root=root, log_output=log_output,
+ filter_stderr=filter_stderr)[1]
def execReadlines(command, argv, stdin=None, root='/', env_prune=None):
""" Execute an external command and return the line output of the
command
diff --git a/tests/pyanaconda_tests/iutil_test.py b/tests/pyanaconda_tests/iutil_test.py
index 4d28606..dde3129 100644
--- a/tests/pyanaconda_tests/iutil_test.py
+++ b/tests/pyanaconda_tests/iutil_test.py
@@ -93,6 +93,25 @@ class RunProgramTests(unittest.TestCase):
# check no output is returned
self.assertEqual(len(iutil.execWithCapture('true', [])), 0)
+ def exec_with_capture_no_stderr_test(self):
+ """Test execWithCapture with no stderr"""
+
+ with tempfile.NamedTemporaryFile() as testscript:
+ testscript.write("""#!/bin/sh
+echo "output"
+echo "error" >&2
+""")
+ testscript.flush()
+
+ # check that only the output is captured
+ self.assertEqual(
+ iutil.execWithCapture("/bin/sh", [testscript.name],
filter_stderr=True),
+ "output\n")
+
+ # check that both output and error are captured
+ self.assertEqual(iutil.execWithCapture("/bin/sh",
[testscript.name]),
+ "output\nerror\n")
+
def exec_readlines_test(self):
"""Test execReadlines."""
--
1.9.3