[master 4/4] Simplify iutil.execReadlines
David Shea
dshea at redhat.com
Fri Aug 8 19:32:50 UTC 2014
Remove the thread and queue between execReadlines and the process it
starts. Share the process starting code between execReadlines and
_run_program.
---
pyanaconda/iutil.py | 101 +++++++++++++++++++++-------------------------------
1 file changed, 40 insertions(+), 61 deletions(-)
diff --git a/pyanaconda/iutil.py b/pyanaconda/iutil.py
index 29aff76..1334f24 100644
--- a/pyanaconda/iutil.py
+++ b/pyanaconda/iutil.py
@@ -30,8 +30,6 @@ import unicodedata
import string
import types
import re
-from threading import Thread
-from Queue import Queue, Empty
from urllib import quote, unquote
from pyanaconda.flags import flags
@@ -97,16 +95,15 @@ def setSysroot(path):
global _sysroot
_sysroot = path
-def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_output=True, binary_output=False):
- """ Run an external program, log the output and return it to the caller
+def _start_program(argv, root='/', stdin=None, env_prune=None):
+ """ Start an external program and return the Popen object.
+ stdout is set to PIPE, stderr is redirected to stdout.
+
: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 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
- :return: The return code of the command and the output
+ :return: A Popen object for the running command.
"""
if env_prune is None:
env_prune = []
@@ -125,17 +122,31 @@ def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_ou
with program_log_lock:
program_log.info("Running... %s", " ".join(argv))
- env = augmentEnv()
- for var in env_prune:
- env.pop(var, None)
+ env = augmentEnv()
+ for var in env_prune:
+ env.pop(var, None)
- try:
- proc = subprocess.Popen(argv,
- stdin=stdin,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- preexec_fn=chroot, cwd=root, env=env)
+ return subprocess.Popen(argv,
+ stdin=stdin,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ preexec_fn=chroot, cwd=root, env=env)
+def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_output=True, binary_output=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 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
+ :return: The return code of the command and the output
+ """
+ try:
+ proc = _start_program(argv, root, stdin, env_prune)
+
+ with program_log_lock:
output_string = proc.communicate()[0]
if output_string:
if binary_output:
@@ -152,10 +163,12 @@ def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_ou
if stdout:
stdout.write(line)
- except OSError as e:
+ except OSError as e:
+ with program_log_lock:
program_log.error("Error running %s: %s", argv[0], e.strerror)
- raise
+ raise
+ with program_log_lock:
program_log.debug("Return code: %d", proc.returncode)
return (proc.returncode, output_string)
@@ -224,55 +237,21 @@ def execReadlines(command, argv, stdin=None, root='/', env_prune=None):
Output from the file is not logged to program.log
This returns a generator with the lines from the command until it has finished
"""
- if env_prune is None:
- env_prune = []
-
- # Return the lines from stdout via a Queue
- def queue_lines(out, queue):
- for line in iter(out.readline, b''):
- queue.put(line.strip())
- out.close()
-
- def chroot():
- if root and root != '/':
- os.chroot(root)
- os.chdir("/")
-
argv = [command] + argv
- with program_log_lock:
- program_log.info("Running... %s", " ".join(argv))
- env = augmentEnv()
- for var in env_prune:
- env.pop(var, None)
try:
- proc = subprocess.Popen(argv,
- stdin=stdin,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- bufsize=1,
- preexec_fn=chroot, cwd=root, env=env)
+ proc = _start_program(argv, root, stdin, env_prune)
except OSError as e:
- program_log.error("Error running %s: %s", argv[0], e.strerror)
+ with program_log_lock:
+ program_log.error("Error running %s: %s", argv[0], e.strerror)
raise
- q = Queue()
- t = Thread(target=queue_lines, args=(proc.stdout, q))
- t.daemon = True # thread dies with the program
- t.start()
-
- while True:
- try:
- line = q.get(timeout=.1)
- yield line
- q.task_done()
- except Empty:
- if proc.poll() is not None:
- if os.WIFSIGNALED(proc.returncode):
- raise OSError("process '%s' was killed" % argv)
- break
- q.join()
+ for line in iter(proc.stdout.readline, b''):
+ yield line.strip()
+ if proc.poll() is not None:
+ if os.WIFSIGNALED(proc.returncode):
+ raise OSError("process '%s' was killed" % argv)
## Run a shell.
def execConsole():
--
1.9.3
More information about the anaconda-patches
mailing list