author | ed |
Fri, 04 Jun 2010 17:36:11 +0200 | |
changeset 564 | 464d470bdbd7 |
parent 424 | 86a7c1d11bbd |
child 686 | e4e1da75d411 |
permissions | -rw-r--r-- |
79 | 1 |
#!/usr/bin/env python |
2 |
# -*- coding: utf-8 -*- |
|
3 |
||
4 |
#This file is part of Beremiz, a Integrated Development Environment for |
|
5 |
#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. |
|
6 |
# |
|
7 |
#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
|
8 |
# |
|
9 |
#See COPYING file for copyrights details. |
|
10 |
# |
|
11 |
#This library is free software; you can redistribute it and/or |
|
12 |
#modify it under the terms of the GNU General Public |
|
13 |
#License as published by the Free Software Foundation; either |
|
14 |
#version 2.1 of the License, or (at your option) any later version. |
|
15 |
# |
|
16 |
#This library is distributed in the hope that it will be useful, |
|
17 |
#but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18 |
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
19 |
#General Public License for more details. |
|
20 |
# |
|
21 |
#You should have received a copy of the GNU General Public |
|
22 |
#License along with this library; if not, write to the Free Software |
|
23 |
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
24 |
||
25 |
||
26 |
import time |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
27 |
import wx |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
28 |
import subprocess, ctypes |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
29 |
import threading |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
30 |
import os |
235 | 31 |
if os.name == 'posix': |
32 |
from signal import SIGTERM, SIGKILL |
|
79 | 33 |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
34 |
|
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
35 |
class outputThread(threading.Thread): |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
36 |
""" |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
37 |
Thread is used to print the output of a command to the stdout |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
38 |
""" |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
39 |
def __init__(self, Proc, fd, callback=None, endcallback=None): |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
40 |
threading.Thread.__init__(self) |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
41 |
self.killed = False |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
42 |
self.finished = False |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
43 |
self.retval = None |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
44 |
self.Proc = Proc |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
45 |
self.callback = callback |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
46 |
self.endcallback = endcallback |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
47 |
self.fd = fd |
79 | 48 |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
49 |
def run(self): |
162
bf3eac08a96b
Try to fix strange wxPopen behavior. Feedback appreciated.
etisserant
parents:
154
diff
changeset
|
50 |
outchunk = None |
149 | 51 |
self.retval = None |
162
bf3eac08a96b
Try to fix strange wxPopen behavior. Feedback appreciated.
etisserant
parents:
154
diff
changeset
|
52 |
while outchunk != '' and not self.killed : |
bf3eac08a96b
Try to fix strange wxPopen behavior. Feedback appreciated.
etisserant
parents:
154
diff
changeset
|
53 |
outchunk = self.fd.readline() |
bf3eac08a96b
Try to fix strange wxPopen behavior. Feedback appreciated.
etisserant
parents:
154
diff
changeset
|
54 |
if self.callback : self.callback(outchunk) |
149 | 55 |
while self.retval is None and not self.killed : |
56 |
self.retval = self.Proc.poll() |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
57 |
outchunk = self.fd.readline() |
162
bf3eac08a96b
Try to fix strange wxPopen behavior. Feedback appreciated.
etisserant
parents:
154
diff
changeset
|
58 |
if self.callback : self.callback(outchunk) |
bf3eac08a96b
Try to fix strange wxPopen behavior. Feedback appreciated.
etisserant
parents:
154
diff
changeset
|
59 |
while outchunk != '' and not self.killed : |
bf3eac08a96b
Try to fix strange wxPopen behavior. Feedback appreciated.
etisserant
parents:
154
diff
changeset
|
60 |
outchunk = self.fd.readline() |
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
61 |
if self.endcallback: |
130
9af34a1d33b7
fixed short process wainting bug. Seems wait() fail when process already finisshed... TO BE CONFIRMED.
greg
parents:
128
diff
changeset
|
62 |
try: |
232 | 63 |
err = self.Proc.wait() |
130
9af34a1d33b7
fixed short process wainting bug. Seems wait() fail when process already finisshed... TO BE CONFIRMED.
greg
parents:
128
diff
changeset
|
64 |
except: |
149 | 65 |
err = self.retval |
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
66 |
self.finished = True |
421 | 67 |
self.endcallback(self.Proc.pid, err) |
68 |
||
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
69 |
class ProcessLogger: |
111
e2e498333fbc
fixed display/hide console when launch external programs
greg
parents:
110
diff
changeset
|
70 |
def __init__(self, logger, Command, finish_callback=None, no_stdout=False, no_stderr=False, no_gui=True): |
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
71 |
self.logger = logger |
424 | 72 |
if not isinstance(Command, list): |
73 |
self.Command_str = Command |
|
74 |
self.Command = [] |
|
75 |
for i,word in enumerate(Command.replace("'",'"').split('"')): |
|
76 |
if i % 2 == 0: |
|
77 |
word = word.strip() |
|
78 |
if len(word) > 0: |
|
79 |
self.Command.extend(word.split()) |
|
80 |
else: |
|
81 |
self.Command.append(word) |
|
82 |
else: |
|
83 |
self.Command = Command |
|
84 |
self.Command_str = subprocess.list2cmdline(self.Command) |
|
85 |
||
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
86 |
self.finish_callback = finish_callback |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
87 |
self.no_stdout = no_stdout |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
88 |
self.no_stderr = no_stderr |
111
e2e498333fbc
fixed display/hide console when launch external programs
greg
parents:
110
diff
changeset
|
89 |
self.startupinfo = None |
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
90 |
self.errlen = 0 |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
91 |
self.outlen = 0 |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
92 |
self.exitcode = None |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
93 |
self.outdata = "" |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
94 |
self.errdata = "" |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
95 |
self.finished = False |
111
e2e498333fbc
fixed display/hide console when launch external programs
greg
parents:
110
diff
changeset
|
96 |
|
128
3db703a78e9c
fixed subprocess launching on linux (avoid use of undefied self.startupinfo and use use Shell=True (bash will split arguments))
greg
parents:
112
diff
changeset
|
97 |
popenargs= { |
3db703a78e9c
fixed subprocess launching on linux (avoid use of undefied self.startupinfo and use use Shell=True (bash will split arguments))
greg
parents:
112
diff
changeset
|
98 |
"cwd":os.getcwd(), |
3db703a78e9c
fixed subprocess launching on linux (avoid use of undefied self.startupinfo and use use Shell=True (bash will split arguments))
greg
parents:
112
diff
changeset
|
99 |
"stdin":subprocess.PIPE, |
3db703a78e9c
fixed subprocess launching on linux (avoid use of undefied self.startupinfo and use use Shell=True (bash will split arguments))
greg
parents:
112
diff
changeset
|
100 |
"stdout":subprocess.PIPE, |
3db703a78e9c
fixed subprocess launching on linux (avoid use of undefied self.startupinfo and use use Shell=True (bash will split arguments))
greg
parents:
112
diff
changeset
|
101 |
"stderr":subprocess.PIPE} |
424 | 102 |
|
111
e2e498333fbc
fixed display/hide console when launch external programs
greg
parents:
110
diff
changeset
|
103 |
if no_gui == True and wx.Platform == '__WXMSW__': |
e2e498333fbc
fixed display/hide console when launch external programs
greg
parents:
110
diff
changeset
|
104 |
self.startupinfo = subprocess.STARTUPINFO() |
e2e498333fbc
fixed display/hide console when launch external programs
greg
parents:
110
diff
changeset
|
105 |
self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW |
128
3db703a78e9c
fixed subprocess launching on linux (avoid use of undefied self.startupinfo and use use Shell=True (bash will split arguments))
greg
parents:
112
diff
changeset
|
106 |
popenargs["startupinfo"] = self.startupinfo |
3db703a78e9c
fixed subprocess launching on linux (avoid use of undefied self.startupinfo and use use Shell=True (bash will split arguments))
greg
parents:
112
diff
changeset
|
107 |
elif wx.Platform == '__WXGTK__': |
154
f3134b2c6d92
Fixed killing app on Linux in wxPopen. Do not use shell anymore. Command line is splitted into args, taking care of double and simple cotes. To be tested on win32.
etisserant
parents:
151
diff
changeset
|
108 |
popenargs["shell"] = False #True |
111
e2e498333fbc
fixed display/hide console when launch external programs
greg
parents:
110
diff
changeset
|
109 |
|
128
3db703a78e9c
fixed subprocess launching on linux (avoid use of undefied self.startupinfo and use use Shell=True (bash will split arguments))
greg
parents:
112
diff
changeset
|
110 |
self.Proc = subprocess.Popen( self.Command, **popenargs ) |
112 | 111 |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
112 |
self.outt = outputThread( |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
113 |
self.Proc, |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
114 |
self.Proc.stdout, |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
115 |
self.output, |
232 | 116 |
self.finish) |
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
117 |
self.outt.start() |
79 | 118 |
|
112 | 119 |
self.errt = outputThread( |
120 |
self.Proc, |
|
121 |
self.Proc.stderr, |
|
122 |
self.errors) |
|
232 | 123 |
self.errt.start() |
79 | 124 |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
125 |
def output(self,v): |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
126 |
self.outdata += v |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
127 |
self.outlen += 1 |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
128 |
if not self.no_stdout: |
421 | 129 |
if wx.GetApp() is None: |
130 |
self.logger.write(v) |
|
131 |
else: |
|
132 |
wx.CallAfter(self.logger.write,v) |
|
133 |
||
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
134 |
def errors(self,v): |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
135 |
self.errdata += v |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
136 |
self.errlen += 1 |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
137 |
if not self.no_stderr: |
421 | 138 |
if wx.GetApp() is None: |
139 |
self.logger.write_warning(v) |
|
140 |
else: |
|
141 |
wx.CallAfter(self.logger.write_warning,v) |
|
79 | 142 |
|
232 | 143 |
def log_the_end(self,ecode,pid): |
144 |
self.logger.write(self.Command_str + "\n") |
|
361 | 145 |
self.logger.write_warning(_("exited with status %s (pid %s)\n")%(str(ecode),str(pid))) |
232 | 146 |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
147 |
def finish(self, pid,ecode): |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
148 |
self.finished = True |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
149 |
self.exitcode = ecode |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
150 |
if self.exitcode != 0: |
421 | 151 |
if wx.GetApp() is None: |
152 |
self.log_the_end(ecode,pid) |
|
153 |
else: |
|
154 |
wx.CallAfter(self.log_the_end,ecode,pid) |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
155 |
if self.finish_callback is not None: |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
156 |
self.finish_callback(self,ecode,pid) |
79 | 157 |
|
235 | 158 |
def kill(self,gently=True): |
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
159 |
self.outt.killed = True |
112 | 160 |
self.errt.killed = True |
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
161 |
if wx.Platform == '__WXMSW__': |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
162 |
PROCESS_TERMINATE = 1 |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
163 |
handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.Proc.pid) |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
164 |
ctypes.windll.kernel32.TerminateProcess(handle, -1) |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
165 |
ctypes.windll.kernel32.CloseHandle(handle) |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
166 |
else: |
235 | 167 |
if gently: |
168 |
sig=SIGTERM |
|
169 |
else: |
|
170 |
sig=SIGKILL |
|
154
f3134b2c6d92
Fixed killing app on Linux in wxPopen. Do not use shell anymore. Command line is splitted into args, taking care of double and simple cotes. To be tested on win32.
etisserant
parents:
151
diff
changeset
|
171 |
try: |
235 | 172 |
os.kill(self.Proc.pid, sig) |
154
f3134b2c6d92
Fixed killing app on Linux in wxPopen. Do not use shell anymore. Command line is splitted into args, taking care of double and simple cotes. To be tested on win32.
etisserant
parents:
151
diff
changeset
|
173 |
except: |
f3134b2c6d92
Fixed killing app on Linux in wxPopen. Do not use shell anymore. Command line is splitted into args, taking care of double and simple cotes. To be tested on win32.
etisserant
parents:
151
diff
changeset
|
174 |
pass |
232 | 175 |
self.outt.join() |
176 |
self.errt.join() |
|
79 | 177 |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
178 |
def spin(self, timeout=None, out_limit=None, err_limit=None, keyword = None, kill_it = True): |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
179 |
count = 0 |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
180 |
while not self.finished: |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
181 |
if err_limit and self.errlen > err_limit: |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
182 |
break |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
183 |
if out_limit and self.outlen > out_limit: |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
184 |
break |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
185 |
if timeout: |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
186 |
if count > timeout: |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
187 |
break |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
188 |
count += 1 |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
189 |
if keyword and self.outdata.find(keyword)!=-1: |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
190 |
break |
421 | 191 |
app = wx.GetApp() |
192 |
if app is not None: |
|
193 |
app.Yield() |
|
89 | 194 |
time.sleep(0.01) |
195 |
||
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
196 |
if not self.outt.finished and kill_it: |
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
197 |
self.kill() |
89 | 198 |
|
110
a05e8b30c024
Fixed way apps are launched in parralel with single log window... Tested in win32 only.
etisserant
parents:
89
diff
changeset
|
199 |
return [self.exitcode, self.outdata, self.errdata] |
89 | 200 |