util/ProcessLogger.py
changeset 1911 c1298e7ffe3a
parent 1581 2295fdc5c271
child 1730 64d8f52bc8c8
equal deleted inserted replaced
1910:a375e31bf312 1911:c1298e7ffe3a
     1 #!/usr/bin/env python
     1 #!/usr/bin/env python
     2 # -*- coding: utf-8 -*-
     2 # -*- coding: utf-8 -*-
     3 
     3 
     4 #This file is part of Beremiz, a Integrated Development Environment for
     4 # This file is part of Beremiz, a Integrated Development Environment for
     5 #programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
     5 # programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
     6 #
     6 #
     7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
     7 # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
     8 #
     8 #
     9 #See COPYING file for copyrights details.
     9 # See COPYING file for copyrights details.
    10 #
    10 #
    11 #This library is free software; you can redistribute it and/or
    11 # This program is free software; you can redistribute it and/or
    12 #modify it under the terms of the GNU General Public
    12 # modify it under the terms of the GNU General Public License
    13 #License as published by the Free Software Foundation; either
    13 # as published by the Free Software Foundation; either version 2
    14 #version 2.1 of the License, or (at your option) any later version.
    14 # of the License, or (at your option) any later version.
    15 #
    15 #
    16 #This library is distributed in the hope that it will be useful,
    16 # This program is distributed in the hope that it will be useful,
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
    17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19 #General Public License for more details.
    19 # GNU General Public License for more details.
    20 #
    20 #
    21 #You should have received a copy of the GNU General Public
    21 # You should have received a copy of the GNU General Public License
    22 #License along with this library; if not, write to the Free Software
    22 # along with this program; if not, write to the Free Software
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    24 
       
    25 
    24 
    26 import time
    25 import time
    27 import wx
    26 import wx
    28 import subprocess, ctypes
    27 import subprocess, ctypes
    29 from threading import Timer, Lock, Thread, Semaphore
    28 from threading import Timer, Lock, Thread, Semaphore
    47         self.fd = fd
    46         self.fd = fd
    48 
    47 
    49     def run(self):
    48     def run(self):
    50         outchunk = None
    49         outchunk = None
    51         self.retval = None
    50         self.retval = None
    52         while outchunk != '' and not self.killed :
       
    53             outchunk = self.fd.readline()
       
    54             if self.callback : self.callback(outchunk)
       
    55         while self.retval is None and not self.killed :
    51         while self.retval is None and not self.killed :
    56             self.retval = self.Proc.poll()
    52             if self.endcallback:
       
    53                 self.retval = self.Proc.poll()
       
    54             else:
       
    55                 self.retval = self.Proc.returncode
       
    56                 
    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.callback : self.callback(outchunk)
   106         self.exitcode = None
   106         self.exitcode = None
   107         self.outdata = []
   107         self.outdata = []
   108         self.errdata = []
   108         self.errdata = []
   109         self.keyword = keyword
   109         self.keyword = keyword
   110         self.kill_it = kill_it
   110         self.kill_it = kill_it
       
   111         self.startsem = Semaphore(0)        
   111         self.finishsem = Semaphore(0)
   112         self.finishsem = Semaphore(0)
   112         self.endlock = Lock()
   113         self.endlock = Lock()
   113 
   114 
   114         popenargs= {
   115         popenargs= {
   115                "cwd":os.getcwd() if cwd is None else cwd,
   116                "cwd":os.getcwd() if cwd is None else cwd,
   122             self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
   123             self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
   123             popenargs["startupinfo"] = self.startupinfo
   124             popenargs["startupinfo"] = self.startupinfo
   124         elif wx.Platform == '__WXGTK__':
   125         elif wx.Platform == '__WXGTK__':
   125             popenargs["shell"] = False
   126             popenargs["shell"] = False
   126 
   127 
       
   128         if timeout:
       
   129             self.timeout = Timer(timeout,self.endlog)
       
   130             self.timeout.start()
       
   131         else:
       
   132             self.timeout = None
       
   133             
   127         self.Proc = subprocess.Popen( self.Command, **popenargs )
   134         self.Proc = subprocess.Popen( self.Command, **popenargs )
   128 
   135 
   129         self.outt = outputThread(
   136         self.outt = outputThread(
   130                       self.Proc,
   137                       self.Proc,
   131                       self.Proc.stdout,
   138                       self.Proc.stdout,
   136         self.errt = outputThread(
   143         self.errt = outputThread(
   137                       self.Proc,
   144                       self.Proc,
   138                       self.Proc.stderr,
   145                       self.Proc.stderr,
   139                       self.errors)
   146                       self.errors)
   140         self.errt.start()
   147         self.errt.start()
   141 
   148         self.startsem.release()
   142         if timeout:
   149 
   143             self.timeout = Timer(timeout,self.endlog)
       
   144             self.timeout.start()
       
   145         else:
       
   146             self.timeout = None
       
   147 
   150 
   148     def output(self,v):
   151     def output(self,v):
   149         self.outdata.append(v)
   152         self.outdata.append(v)
   150         self.outlen += 1
   153         self.outlen += 1
   151         if not self.no_stdout:
   154         if not self.no_stdout:
   161         if self.errlimit and self.errlen > self.errlimit:
   164         if self.errlimit and self.errlen > self.errlimit:
   162             self.endlog()
   165             self.endlog()
   163 
   166 
   164     def log_the_end(self,ecode,pid):
   167     def log_the_end(self,ecode,pid):
   165         self.logger.write(self.Command_str + "\n")
   168         self.logger.write(self.Command_str + "\n")
   166         self.logger.write_warning(_("exited with status %s (pid %s)\n")%(str(ecode),str(pid)))
   169         self.logger.write_warning(_("exited with status {a1} (pid {a2})\n").format(a1 = str(ecode), a2 = str(pid)))
   167 
   170 
   168     def finish(self, pid,ecode):
   171     def finish(self, pid,ecode):
   169         if self.timeout: self.timeout.cancel()
   172         # avoid running function before start is finished        
       
   173         self.startsem.acquire()
       
   174         if self.timeout:
       
   175             self.timeout.cancel()
   170         self.exitcode = ecode
   176         self.exitcode = ecode
   171         if self.exitcode != 0:
   177         if self.exitcode != 0:
   172             self.log_the_end(ecode,pid)
   178             self.log_the_end(ecode,pid)
   173         if self.finish_callback is not None:
   179         if self.finish_callback is not None:
   174             self.finish_callback(self,ecode,pid)
   180             self.finish_callback(self,ecode,pid)
       
   181         self.errt.join()
   175         self.finishsem.release()
   182         self.finishsem.release()
   176 
   183 
   177     def kill(self,gently=True):
   184     def kill(self,gently=True):
       
   185         # avoid running kill before start is finished
       
   186         self.startsem.acquire()
       
   187         self.startsem.release()
       
   188         
   178         self.outt.killed = True
   189         self.outt.killed = True
   179         self.errt.killed = True
   190         self.errt.killed = True
   180         if wx.Platform == '__WXMSW__':
   191         if wx.Platform == '__WXMSW__':
   181             PROCESS_TERMINATE = 1
   192             PROCESS_TERMINATE = 1
   182             handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.Proc.pid)
   193             handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.Proc.pid)
   194         self.outt.join()
   205         self.outt.join()
   195         self.errt.join()
   206         self.errt.join()
   196 
   207 
   197     def endlog(self):
   208     def endlog(self):
   198         if self.endlock.acquire(False):
   209         if self.endlock.acquire(False):
   199             self.finishsem.release()
       
   200             if not self.outt.finished and self.kill_it:
   210             if not self.outt.finished and self.kill_it:
   201                self.kill()
   211                self.kill()
       
   212             self.finishsem.release()
   202 
   213 
   203 
   214 
   204     def spin(self):
   215     def spin(self):
   205         self.finishsem.acquire()
   216         self.finishsem.acquire()
   206         return [self.exitcode, "".join(self.outdata), "".join(self.errdata)]
   217         return [self.exitcode, "".join(self.outdata), "".join(self.errdata)]