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, |
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)] |