wxPopen.py
changeset 704 5993b16fe2d0
parent 686 e4e1da75d411
equal deleted inserted replaced
703:2f7b3d1de278 704:5993b16fe2d0
    24 
    24 
    25 
    25 
    26 import time
    26 import time
    27 import wx
    27 import wx
    28 import subprocess, ctypes
    28 import subprocess, ctypes
    29 import threading
    29 from threading import Timer, Lock, Thread, Semaphore
    30 import os
    30 import os
    31 if os.name == 'posix':
    31 if os.name == 'posix':
    32     from signal import SIGTERM, SIGKILL
    32     from signal import SIGTERM, SIGKILL
    33 
    33 
    34     
    34     
    35 class outputThread(threading.Thread):
    35 class outputThread(Thread):
    36     """
    36     """
    37     Thread is used to print the output of a command to the stdout
    37     Thread is used to print the output of a command to the stdout
    38     """
    38     """
    39     def __init__(self, Proc, fd, callback=None, endcallback=None):
    39     def __init__(self, Proc, fd, callback=None, endcallback=None):
    40         threading.Thread.__init__(self)
    40         Thread.__init__(self)
    41         self.killed = False
    41         self.killed = False
    42         self.finished = False
    42         self.finished = False
    43         self.retval = None
    43         self.retval = None
    44         self.Proc = Proc
    44         self.Proc = Proc
    45         self.callback = callback
    45         self.callback = callback
    56             self.retval = self.Proc.poll()
    56             self.retval = self.Proc.poll()
    57             outchunk = self.fd.readline()
    57             outchunk = self.fd.readline()
    58             if self.callback : self.callback(outchunk)
    58             if self.callback : self.callback(outchunk)
    59         while outchunk != '' and not self.killed :
    59         while outchunk != '' and not self.killed :
    60             outchunk = self.fd.readline()
    60             outchunk = self.fd.readline()
       
    61             if self.callback : self.callback(outchunk)
    61         if self.endcallback:
    62         if self.endcallback:
    62             try:
    63             try:
    63                 err = self.Proc.wait()
    64                 err = self.Proc.wait()
    64             except:
    65             except:
    65                 err = self.retval
    66                 err = self.retval
    66             self.finished = True
    67             self.finished = True
    67             self.endcallback(self.Proc.pid, err)
    68             self.endcallback(self.Proc.pid, err)
    68         
    69         
    69 class ProcessLogger:
    70 class ProcessLogger:
    70     def __init__(self, logger, Command, finish_callback=None, no_stdout=False, no_stderr=False, no_gui=True):
    71     def __init__(self, logger, Command, finish_callback = None, 
       
    72                  no_stdout = False, no_stderr = False, no_gui = True, 
       
    73                  timeout = None, outlimit = None, errlimit = None,
       
    74                  endlog = None, keyword = None, kill_it = False):
    71         self.logger = logger
    75         self.logger = logger
    72         if not isinstance(Command, list):
    76         if not isinstance(Command, list):
    73             self.Command_str = Command
    77             self.Command_str = Command
    74             self.Command = []
    78             self.Command = []
    75             for i,word in enumerate(Command.replace("'",'"').split('"')):
    79             for i,word in enumerate(Command.replace("'",'"').split('"')):
    87         self.no_stdout = no_stdout
    91         self.no_stdout = no_stdout
    88         self.no_stderr = no_stderr
    92         self.no_stderr = no_stderr
    89         self.startupinfo = None
    93         self.startupinfo = None
    90         self.errlen = 0
    94         self.errlen = 0
    91         self.outlen = 0
    95         self.outlen = 0
       
    96         self.errlimit = errlimit
       
    97         self.outlimit = outlimit
    92         self.exitcode = None
    98         self.exitcode = None
    93         self.outdata = ""
    99         self.outdata = []
    94         self.errdata = ""
   100         self.errdata = []
    95         self.finished = False
   101         self.keyword = keyword
       
   102         self.kill_it = kill_it
       
   103         self.finishsem = Semaphore(0)
       
   104         self.endlock = Lock()
    96         
   105         
    97         popenargs= {
   106         popenargs= {
    98                "cwd":os.getcwd(),
   107                "cwd":os.getcwd(),
    99                "stdin":subprocess.PIPE, 
   108                "stdin":subprocess.PIPE, 
   100                "stdout":subprocess.PIPE, 
   109                "stdout":subprocess.PIPE, 
   103         if no_gui == True and wx.Platform == '__WXMSW__':
   112         if no_gui == True and wx.Platform == '__WXMSW__':
   104             self.startupinfo = subprocess.STARTUPINFO()
   113             self.startupinfo = subprocess.STARTUPINFO()
   105             self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
   114             self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
   106             popenargs["startupinfo"] = self.startupinfo
   115             popenargs["startupinfo"] = self.startupinfo
   107         elif wx.Platform == '__WXGTK__':
   116         elif wx.Platform == '__WXGTK__':
   108             popenargs["shell"] = False  #True
   117             popenargs["shell"] = False
   109         
   118         
   110         self.Proc = subprocess.Popen( self.Command, **popenargs )
   119         self.Proc = subprocess.Popen( self.Command, **popenargs )
   111 
   120 
   112         self.outt = outputThread(
   121         self.outt = outputThread(
   113                       self.Proc,
   122                       self.Proc,
   120                       self.Proc,
   129                       self.Proc,
   121                       self.Proc.stderr,
   130                       self.Proc.stderr,
   122                       self.errors)
   131                       self.errors)
   123         self.errt.start()
   132         self.errt.start()
   124 
   133 
       
   134         Timer(timeout,self.endlog).start()
       
   135 
   125     def output(self,v):
   136     def output(self,v):
   126         self.outdata += v
   137         self.outdata.append(v)
   127         self.outlen += 1
   138         self.outlen += 1
   128         if not self.no_stdout:
   139         if not self.no_stdout:
   129             self.logger.write(v)
   140             self.logger.write(v)
       
   141         if (self.keyword and v.find(self.keyword)!=-1) or (self.outlimit and self.outlen > self.outlimit):
       
   142             self.endlog()
   130             
   143             
   131     def errors(self,v):
   144     def errors(self,v):
   132         self.errdata += v
   145         self.errdata.append(v)
   133         self.errlen += 1
   146         self.errlen += 1
   134         if not self.no_stderr:
   147         if not self.no_stderr:
   135             self.logger.write_warning(v)
   148             self.logger.write_warning(v)
       
   149         if self.errlimit and self.errlen > self.errlimit:
       
   150             self.endlog()
   136 
   151 
   137     def log_the_end(self,ecode,pid):
   152     def log_the_end(self,ecode,pid):
   138         self.logger.write(self.Command_str + "\n")
   153         self.logger.write(self.Command_str + "\n")
   139         self.logger.write_warning(_("exited with status %s (pid %s)\n")%(str(ecode),str(pid)))
   154         self.logger.write_warning(_("exited with status %s (pid %s)\n")%(str(ecode),str(pid)))
   140 
   155 
   141     def finish(self, pid,ecode):
   156     def finish(self, pid,ecode):
   142         self.finished = True
       
   143         self.exitcode = ecode
   157         self.exitcode = ecode
   144         if self.exitcode != 0:
   158         if self.exitcode != 0:
   145             self.log_the_end(ecode,pid)
   159             self.log_the_end(ecode,pid)
   146         if self.finish_callback is not None:
   160         if self.finish_callback is not None:
   147             self.finish_callback(self,ecode,pid)
   161             self.finish_callback(self,ecode,pid)
       
   162         self.finishsem.release()
   148 
   163 
   149     def kill(self,gently=True):
   164     def kill(self,gently=True):
   150         self.outt.killed = True
   165         self.outt.killed = True
   151         self.errt.killed = True
   166         self.errt.killed = True
   152         if wx.Platform == '__WXMSW__':
   167         if wx.Platform == '__WXMSW__':
   164             except:
   179             except:
   165                 pass
   180                 pass
   166         self.outt.join()
   181         self.outt.join()
   167         self.errt.join()
   182         self.errt.join()
   168 
   183 
   169     def spin(self, timeout=None, out_limit=None, err_limit=None, keyword = None, kill_it = True):
   184     def endlog(self):
   170         count = 0
   185         if self.endlock.acquire(False):
   171         while not self.finished:
   186             self.finishsem.release()
   172             if err_limit and self.errlen > err_limit:
   187             if not self.outt.finished and self.kill_it:
   173                 break
   188                self.kill()
   174             if out_limit and self.outlen > out_limit:
       
   175                 break
       
   176             if timeout:
       
   177                 if count > timeout:
       
   178                     break
       
   179                 count += 1
       
   180             if keyword and self.outdata.find(keyword)!=-1:
       
   181                     break
       
   182             app = wx.GetApp()
       
   183             if app is not None:
       
   184                 app.Yield()
       
   185             time.sleep(0.01)
       
   186 
   189 
   187         if not self.outt.finished and kill_it:
   190         
   188             self.kill()
   191     def spin(self):
       
   192         self.finishsem.acquire()
       
   193         return [self.exitcode, "".join(self.outdata), "".join(self.errdata)]
   189 
   194 
   190         return [self.exitcode, self.outdata, self.errdata]
       
   191