etisserant@79: #!/usr/bin/env python etisserant@79: # -*- coding: utf-8 -*- etisserant@79: etisserant@79: #This file is part of Beremiz, a Integrated Development Environment for etisserant@79: #programming IEC 61131-3 automates supporting plcopen standard and CanFestival. etisserant@79: # etisserant@79: #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD etisserant@79: # etisserant@79: #See COPYING file for copyrights details. etisserant@79: # etisserant@79: #This library is free software; you can redistribute it and/or etisserant@79: #modify it under the terms of the GNU General Public etisserant@79: #License as published by the Free Software Foundation; either etisserant@79: #version 2.1 of the License, or (at your option) any later version. etisserant@79: # etisserant@79: #This library is distributed in the hope that it will be useful, etisserant@79: #but WITHOUT ANY WARRANTY; without even the implied warranty of etisserant@79: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU etisserant@79: #General Public License for more details. etisserant@79: # etisserant@79: #You should have received a copy of the GNU General Public etisserant@79: #License along with this library; if not, write to the Free Software etisserant@79: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA etisserant@79: etisserant@79: etisserant@79: import time etisserant@110: import wx etisserant@110: import subprocess, ctypes etisserant@110: import threading etisserant@110: import os etisserant@79: etisserant@110: etisserant@110: class outputThread(threading.Thread): etisserant@110: """ etisserant@110: Thread is used to print the output of a command to the stdout etisserant@110: """ etisserant@110: def __init__(self, Proc, fd, callback=None, endcallback=None): etisserant@110: threading.Thread.__init__(self) etisserant@110: self.killed = False etisserant@110: self.finished = False etisserant@110: self.retval = None etisserant@110: self.Proc = Proc etisserant@110: self.callback = callback etisserant@110: self.endcallback = endcallback etisserant@110: self.fd = fd etisserant@79: etisserant@110: def run(self): etisserant@110: outeof = False etisserant@110: self.retval = self.Proc.poll() etisserant@110: while not self.retval and not self.killed and not outeof: etisserant@110: outchunk = self.fd.readline() etisserant@110: if outchunk == '': outeof = True etisserant@110: if self.callback : etisserant@110: wx.CallAfter(self.callback,outchunk) etisserant@110: self.retval=self.Proc.poll() etisserant@110: if self.endcallback: etisserant@110: err = self.Proc.wait() etisserant@110: self.finished = True etisserant@110: wx.CallAfter(self.endcallback, self.Proc.pid, self.retval) etisserant@79: etisserant@110: class ProcessLogger: etisserant@110: def __init__(self, logger, Command, finish_callback=None, no_stdout=False, no_stderr=False): etisserant@110: self.logger = logger etisserant@110: self.Command = Command etisserant@110: self.finish_callback = finish_callback etisserant@110: self.no_stdout = no_stdout etisserant@110: self.no_stderr = no_stderr etisserant@110: self.errlen = 0 etisserant@110: self.outlen = 0 etisserant@110: self.exitcode = None etisserant@110: self.outdata = "" etisserant@110: self.errdata = "" etisserant@110: self.finished = False etisserant@89: etisserant@110: self.Proc = subprocess.Popen(self.Command, etisserant@110: cwd = os.getcwd(), etisserant@110: stdin = subprocess.PIPE, etisserant@110: stdout = subprocess.PIPE, etisserant@110: stderr = subprocess.STDOUT) etisserant@110: # stderr = subprocess.PIPE) etisserant@79: etisserant@110: self.outt = outputThread( etisserant@110: self.Proc, etisserant@110: self.Proc.stdout, etisserant@110: self.output, etisserant@110: self.finish) etisserant@79: etisserant@110: self.outt.start() etisserant@79: etisserant@110: # self.errt = outputThread( etisserant@110: # self.Proc, etisserant@110: # self.Proc.stderr, etisserant@110: # self.errors) etisserant@110: # etisserant@110: # self.errt.start() etisserant@79: etisserant@110: def output(self,v): etisserant@110: self.outdata += v etisserant@110: self.outlen += 1 etisserant@110: if not self.no_stdout: etisserant@110: self.logger.write(v) etisserant@79: etisserant@110: def errors(self,v): etisserant@110: self.errdata += v etisserant@110: self.errlen += 1 etisserant@110: if not self.no_stderr: etisserant@110: self.logger.write_warning(v) etisserant@79: etisserant@110: def finish(self, pid,ecode): etisserant@110: self.finished = True etisserant@110: self.exitcode = ecode etisserant@110: if self.exitcode != 0: etisserant@110: self.logger.write(self.Command + "\n") etisserant@110: self.logger.write_warning("exited with status %s (pid %s)\n"%(str(ecode),str(pid))) etisserant@110: if self.finish_callback is not None: etisserant@110: self.finish_callback(self,ecode,pid) etisserant@79: etisserant@79: def kill(self): etisserant@110: self.outt.killed = True etisserant@110: # self.errt.killed = True etisserant@110: if wx.Platform == '__WXMSW__': etisserant@110: PROCESS_TERMINATE = 1 etisserant@110: handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.Proc.pid) etisserant@110: ctypes.windll.kernel32.TerminateProcess(handle, -1) etisserant@110: ctypes.windll.kernel32.CloseHandle(handle) etisserant@110: else: etisserant@110: os.kill(self.Proc.pid) etisserant@79: etisserant@110: def spin(self, timeout=None, out_limit=None, err_limit=None, keyword = None, kill_it = True): etisserant@110: count = 0 etisserant@110: while not self.finished: etisserant@110: if err_limit and self.errlen > err_limit: etisserant@110: break etisserant@110: if out_limit and self.outlen > out_limit: etisserant@110: break etisserant@110: if timeout: etisserant@110: if count > timeout: etisserant@110: break etisserant@110: count += 1 etisserant@110: if keyword and self.outdata.find(keyword)!=-1: etisserant@110: break etisserant@89: wx.Yield() etisserant@89: time.sleep(0.01) etisserant@89: etisserant@110: if not self.outt.finished and kill_it: etisserant@110: self.kill() etisserant@89: etisserant@110: return [self.exitcode, self.outdata, self.errdata] etisserant@89: