diff -r f27ca37b6e7a -r a05e8b30c024 wxPopen.py --- a/wxPopen.py Fri Feb 22 19:04:01 2008 +0100 +++ b/wxPopen.py Sun Feb 24 02:06:42 2008 +0100 @@ -22,168 +22,128 @@ #License along with this library; if not, write to the Free Software #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# based on wxPopen.py from boa-constructor -# import time -from StringIO import StringIO +import wx +import subprocess, ctypes +import threading +import os -import wx + +class outputThread(threading.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) + self.killed = False + self.finished = False + self.retval = None + self.Proc = Proc + self.callback = callback + self.endcallback = endcallback + self.fd = fd -class ProcessRunnerMix: + def run(self): + outeof = False + self.retval = self.Proc.poll() + while not self.retval and not self.killed and not outeof: + outchunk = self.fd.readline() + if outchunk == '': outeof = True + if self.callback : + wx.CallAfter(self.callback,outchunk) + self.retval=self.Proc.poll() + if self.endcallback: + err = self.Proc.wait() + self.finished = True + wx.CallAfter(self.endcallback, self.Proc.pid, self.retval) - if wx.VERSION < (2, 6, 0): - def Bind(self, event, function, id = None): - if id is not None: - event(self, id, function) - else: - event(self, function) - - def __init__(self, input, handler=None): - if handler is None: - handler = self - self.handler = handler - handler.Bind(wx.EVT_IDLE, self.OnIdle) - handler.Bind(wx.EVT_END_PROCESS, self.OnProcessEnded) +class ProcessLogger: + def __init__(self, logger, Command, finish_callback=None, no_stdout=False, no_stderr=False): + self.logger = logger + self.Command = Command + self.finish_callback = finish_callback + self.no_stdout = no_stdout + self.no_stderr = no_stderr + self.errlen = 0 + self.outlen = 0 + self.exitcode = None + self.outdata = "" + self.errdata = "" + self.finished = False - input.reverse() # so we can pop - self.input = input - - self.reset() + self.Proc = subprocess.Popen(self.Command, + cwd = os.getcwd(), + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.STDOUT) +# stderr = subprocess.PIPE) - def reset(self): - self.process = None - self.pid = -1 - self.output = [] - self.errors = [] - self.inputStream = None - self.errorStream = None - self.outputStream = None - self.outputFunc = None - self.errorsFunc = None - self.finishedFunc = None - self.finished = False - self.responded = False + self.outt = outputThread( + self.Proc, + self.Proc.stdout, + self.output, + self.finish) - def execute(self, cmd): - self.process = wx.Process(self.handler) - self.process.Redirect() + self.outt.start() - self.pid = wx.Execute(cmd, wx.EXEC_ASYNC, self.process) +# self.errt = outputThread( +# self.Proc, +# self.Proc.stderr, +# self.errors) +# +# self.errt.start() - self.inputStream = self.process.GetOutputStream() - self.errorStream = self.process.GetErrorStream() - self.outputStream = self.process.GetInputStream() + def output(self,v): + self.outdata += v + self.outlen += 1 + if not self.no_stdout: + self.logger.write(v) - #self.OnIdle() - wx.WakeUpIdle() - - def setCallbacks(self, output, errors, finished): - self.outputFunc = output - self.errorsFunc = errors - self.finishedFunc = finished + def errors(self,v): + self.errdata += v + self.errlen += 1 + if not self.no_stderr: + self.logger.write_warning(v) - def detach(self): - if self.process is not None: - self.process.CloseOutput() - self.process.Detach() - self.process = None + def finish(self, pid,ecode): + self.finished = True + self.exitcode = ecode + if self.exitcode != 0: + self.logger.write(self.Command + "\n") + self.logger.write_warning("exited with status %s (pid %s)\n"%(str(ecode),str(pid))) + if self.finish_callback is not None: + self.finish_callback(self,ecode,pid) def kill(self): - if self.process is not None: - self.process.CloseOutput() - if wx.Process.Kill(self.pid, wx.SIGTERM) != wx.KILL_OK: - wx.Process.Kill(self.pid, wx.SIGKILL) - self.process = None + self.outt.killed = True +# self.errt.killed = True + if wx.Platform == '__WXMSW__': + PROCESS_TERMINATE = 1 + handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.Proc.pid) + ctypes.windll.kernel32.TerminateProcess(handle, -1) + ctypes.windll.kernel32.CloseHandle(handle) + else: + os.kill(self.Proc.pid) - def updateStream(self, stream, data): - if stream and stream.CanRead(): - if not self.responded: - self.responded = True - text = stream.read() - data.append(text) - return text - else: - return None - - def updateInpStream(self, stream, input): - if stream and input: - line = input.pop() - stream.write(line) - - def updateErrStream(self, stream, data): - return self.updateStream(stream, data) - - def updateOutStream(self, stream, data): - return self.updateStream(stream, data) - - def OnIdle(self, event=None): - if self.process is not None: - self.updateInpStream(self.inputStream, self.input) - e = self.updateErrStream(self.errorStream, self.errors) - if e is not None and self.errorsFunc is not None: - wx.CallAfter(self.errorsFunc, e) - o = self.updateOutStream(self.outputStream, self.output) - if o is not None and self.outputFunc is not None: - wx.CallAfter(self.outputFunc, o) - - #wx.WakeUpIdle() - #time.sleep(0.001) - - def OnProcessEnded(self, event): - self.OnIdle() - pid,exitcode = event.GetPid(), event.GetExitCode() - if self.process: - self.process.Destroy() - self.process = None - - self.finished = True - - # XXX doesn't work ??? - #self.handler.Disconnect(-1, wx.EVT_IDLE) - - if self.finishedFunc: - wx.CallAfter(self.finishedFunc, pid, exitcode) - -class ProcessRunner(wx.EvtHandler, ProcessRunnerMix): - def __init__(self, input): - wx.EvtHandler.__init__(self) - ProcessRunnerMix.__init__(self, input) - -def wxPopen3(cmd, input, output, errors, finish, handler=None): - p = ProcessRunnerMix(input, handler) - p.setCallbacks(output, errors, finish) - p.execute(cmd) - return p - -def _test(): - app = wx.PySimpleApp() - f = wx.Frame(None, -1, 'asd')#, style=0) - f.Show() - - def output(v): - print 'OUTPUT:', v - def errors(v): - print 'ERRORS:', v - def fin(): - p.Close() - f.Close() - print 'FINISHED' - - - def spin(p): - while not p.finished: + 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 wx.Yield() time.sleep(0.01) - def evt(self, event): - input = [] - p = wxPopen3('''c:\\python23\\python.exe -c "print '*'*5000"''', - input, output, errors, fin, f) - print p.pid + if not self.outt.finished and kill_it: + self.kill() - app.MainLoop() + return [self.exitcode, self.outdata, self.errdata] -if __name__ == '__main__': - _test()