[PATCH] Use tee thread to ensure line buffered output to screen and log file at the same moment... (#506664)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 iutil.py |   84 ++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 60 insertions(+), 24 deletions(-)

diff --git a/iutil.py b/iutil.py
index 5b91310..e19e51f 100644
--- a/iutil.py
+++ b/iutil.py
@@ -31,6 +31,7 @@ import subprocess
 from flags import flags
 from constants import *
 import re
+import threading
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
@@ -38,6 +39,32 @@ _ = lambda x: gettext.ldgettext("anaconda", x)
 import logging
 log = logging.getLogger("anaconda")
 
+#Python reimplementation of the shell tee process, so we can
+#feed the pipe output into two places at the same time
+class tee(threading.Thread):
+    def __init__(self, inputdesc, outputdesc, outputfile):
+        threading.Thread.__init__(self)
+        self.inputdesc = os.fdopen(inputdesc, "r")
+        self.outputdesc = outputdesc
+        if isinstance(outputfile, file):
+            self.file = outputfile
+        else:
+            self.file = open(outputfile, "a")
+        self.running = True
+
+    def run(self):
+        while self.running:
+            data = self.inputdesc.readline()
+            if data == "":
+                self.running = False
+            else:
+                self.file.write(data)
+                os.write(self.outputdesc, data)
+
+    def stop(self):
+        self.running = False
+        return self
+
 ## Run an external program and redirect the output to a file.
 # @param command The command to run.
 # @param argv A list of arguments.
@@ -55,14 +82,6 @@ def execWithRedirect(command, argv, stdin = None, stdout = None,
         if not searchPath and not os.access (command, os.X_OK):
             raise RuntimeError, command + " can not be run"
 
-    def closefds ():
-        runningLog.close()
-        stdinclose()
-        stdoutclose()
-        stderrclose()
-
-    stdinclose = stdoutclose = stderrclose = lambda : None
-
     argv = list(argv)
     if isinstance(stdin, str):
         if os.access(stdin, os.R_OK):
@@ -94,36 +113,53 @@ def execWithRedirect(command, argv, stdin = None, stdout = None,
     runningLog = open("/tmp/program.log", "a")
     runningLog.write("Running... %s\n" % ([command] + argv,))
 
+    #prepare os pipes for feeding tee proceses
+    pstdout, pstdin = os.pipe()
+    perrout, perrin = os.pipe()
+   
     env = os.environ.copy()
     env.update({"LC_ALL": "C"})
 
     try:
+        #prepare tee proceses
+        proc_std = tee(pstdout, stdout, runningLog)
+        proc_err = tee(perrout, stderr, runningLog)
+
+        #start monitoring the outputs
+        proc_std.start()
+        proc_err.start()
+
         proc = subprocess.Popen([command] + argv, stdin=stdin,
-                                stdout=subprocess.PIPE,
-                                stderr=subprocess.PIPE,
+                                stdout=pstdin,
+                                stderr=perrin,
                                 preexec_fn=chroot, cwd=root,
                                 env=env)
 
-        while True:
-            (outStr, errStr) = proc.communicate()
-            if outStr:
-                os.write(stdout, outStr)
-                runningLog.write(outStr)
-            if errStr:
-                os.write(stderr, errStr)
-                runningLog.write(errStr)
+        proc.wait()
+        ret = proc.returncode
+
+        #close the input ends of pipes so we get EOF in the tee processes
+        os.close(pstdin)
+        os.close(perrin)
+
+        #wait for the output to be written and destroy them
+        proc_std.join()
+        del proc_std
+
+        proc_err.join()
+        del proc_err
 
-            if proc.returncode is not None:
-                ret = proc.returncode
-                break
     except OSError as e:
         errstr = "Error running %s: %s" % (command, e.strerror)
         log.error(errstr)
         runningLog.write(errstr)
-        closefds()
+        #close the input ends of pipes so we get EOF in the tee processes
+        os.close(pstdin)
+        os.close(perrin)
+        proc_std.join()
+        proc_err.join()
         raise RuntimeError, errstr
 
-    closefds()
     return ret
 
 ## Run an external program and capture standard out.
-- 
1.6.4

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux