wxPopen.py
changeset 704 5993b16fe2d0
parent 686 e4e1da75d411
--- a/wxPopen.py	Sun Mar 18 23:50:51 2012 +0100
+++ b/wxPopen.py	Wed Mar 28 21:08:31 2012 +0200
@@ -26,18 +26,18 @@
 import time
 import wx
 import subprocess, ctypes
-import threading
+from threading import Timer, Lock, Thread, Semaphore
 import os
 if os.name == 'posix':
     from signal import SIGTERM, SIGKILL
 
     
-class outputThread(threading.Thread):
+class outputThread(Thread):
     """
     Thread is used to print the output of a command to the stdout
     """
     def __init__(self, Proc, fd, callback=None, endcallback=None):
-        threading.Thread.__init__(self)
+        Thread.__init__(self)
         self.killed = False
         self.finished = False
         self.retval = None
@@ -58,6 +58,7 @@
             if self.callback : self.callback(outchunk)
         while outchunk != '' and not self.killed :
             outchunk = self.fd.readline()
+            if self.callback : self.callback(outchunk)
         if self.endcallback:
             try:
                 err = self.Proc.wait()
@@ -67,7 +68,10 @@
             self.endcallback(self.Proc.pid, err)
         
 class ProcessLogger:
-    def __init__(self, logger, Command, finish_callback=None, no_stdout=False, no_stderr=False, no_gui=True):
+    def __init__(self, logger, Command, finish_callback = None, 
+                 no_stdout = False, no_stderr = False, no_gui = True, 
+                 timeout = None, outlimit = None, errlimit = None,
+                 endlog = None, keyword = None, kill_it = False):
         self.logger = logger
         if not isinstance(Command, list):
             self.Command_str = Command
@@ -89,10 +93,15 @@
         self.startupinfo = None
         self.errlen = 0
         self.outlen = 0
+        self.errlimit = errlimit
+        self.outlimit = outlimit
         self.exitcode = None
-        self.outdata = ""
-        self.errdata = ""
-        self.finished = False
+        self.outdata = []
+        self.errdata = []
+        self.keyword = keyword
+        self.kill_it = kill_it
+        self.finishsem = Semaphore(0)
+        self.endlock = Lock()
         
         popenargs= {
                "cwd":os.getcwd(),
@@ -105,7 +114,7 @@
             self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
             popenargs["startupinfo"] = self.startupinfo
         elif wx.Platform == '__WXGTK__':
-            popenargs["shell"] = False  #True
+            popenargs["shell"] = False
         
         self.Proc = subprocess.Popen( self.Command, **popenargs )
 
@@ -122,29 +131,35 @@
                       self.errors)
         self.errt.start()
 
+        Timer(timeout,self.endlog).start()
+
     def output(self,v):
-        self.outdata += v
+        self.outdata.append(v)
         self.outlen += 1
         if not self.no_stdout:
             self.logger.write(v)
+        if (self.keyword and v.find(self.keyword)!=-1) or (self.outlimit and self.outlen > self.outlimit):
+            self.endlog()
             
     def errors(self,v):
-        self.errdata += v
+        self.errdata.append(v)
         self.errlen += 1
         if not self.no_stderr:
             self.logger.write_warning(v)
+        if self.errlimit and self.errlen > self.errlimit:
+            self.endlog()
 
     def log_the_end(self,ecode,pid):
         self.logger.write(self.Command_str + "\n")
         self.logger.write_warning(_("exited with status %s (pid %s)\n")%(str(ecode),str(pid)))
 
     def finish(self, pid,ecode):
-        self.finished = True
         self.exitcode = ecode
         if self.exitcode != 0:
             self.log_the_end(ecode,pid)
         if self.finish_callback is not None:
             self.finish_callback(self,ecode,pid)
+        self.finishsem.release()
 
     def kill(self,gently=True):
         self.outt.killed = True
@@ -166,26 +181,14 @@
         self.outt.join()
         self.errt.join()
 
-    def spin(self, timeout=None, out_limit=None, err_limit=None, keyword = None, kill_it = True):
-        count = 0
-        while not self.finished:
-            if err_limit and self.errlen > err_limit:
-                break
-            if out_limit and self.outlen > out_limit:
-                break
-            if timeout:
-                if count > timeout:
-                    break
-                count += 1
-            if keyword and self.outdata.find(keyword)!=-1:
-                    break
-            app = wx.GetApp()
-            if app is not None:
-                app.Yield()
-            time.sleep(0.01)
+    def endlog(self):
+        if self.endlock.acquire(False):
+            self.finishsem.release()
+            if not self.outt.finished and self.kill_it:
+               self.kill()
 
-        if not self.outt.finished and kill_it:
-            self.kill()
+        
+    def spin(self):
+        self.finishsem.acquire()
+        return [self.exitcode, "".join(self.outdata), "".join(self.errdata)]
 
-        return [self.exitcode, self.outdata, self.errdata]
-