24 |
24 |
25 |
25 |
26 import time |
26 import time |
27 import wx |
27 import wx |
28 import subprocess, ctypes |
28 import subprocess, ctypes |
29 import threading |
29 from threading import Timer, Lock, Thread, Semaphore |
30 import os |
30 import os |
31 if os.name == 'posix': |
31 if os.name == 'posix': |
32 from signal import SIGTERM, SIGKILL |
32 from signal import SIGTERM, SIGKILL |
33 |
33 |
34 |
34 |
35 class outputThread(threading.Thread): |
35 class outputThread(Thread): |
36 """ |
36 """ |
37 Thread is used to print the output of a command to the stdout |
37 Thread is used to print the output of a command to the stdout |
38 """ |
38 """ |
39 def __init__(self, Proc, fd, callback=None, endcallback=None): |
39 def __init__(self, Proc, fd, callback=None, endcallback=None): |
40 threading.Thread.__init__(self) |
40 Thread.__init__(self) |
41 self.killed = False |
41 self.killed = False |
42 self.finished = False |
42 self.finished = False |
43 self.retval = None |
43 self.retval = None |
44 self.Proc = Proc |
44 self.Proc = Proc |
45 self.callback = callback |
45 self.callback = callback |
56 self.retval = self.Proc.poll() |
56 self.retval = self.Proc.poll() |
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.endcallback: |
62 if self.endcallback: |
62 try: |
63 try: |
63 err = self.Proc.wait() |
64 err = self.Proc.wait() |
64 except: |
65 except: |
65 err = self.retval |
66 err = self.retval |
66 self.finished = True |
67 self.finished = True |
67 self.endcallback(self.Proc.pid, err) |
68 self.endcallback(self.Proc.pid, err) |
68 |
69 |
69 class ProcessLogger: |
70 class ProcessLogger: |
70 def __init__(self, logger, Command, finish_callback=None, no_stdout=False, no_stderr=False, no_gui=True): |
71 def __init__(self, logger, Command, finish_callback = None, |
|
72 no_stdout = False, no_stderr = False, no_gui = True, |
|
73 timeout = None, outlimit = None, errlimit = None, |
|
74 endlog = None, keyword = None, kill_it = False): |
71 self.logger = logger |
75 self.logger = logger |
72 if not isinstance(Command, list): |
76 if not isinstance(Command, list): |
73 self.Command_str = Command |
77 self.Command_str = Command |
74 self.Command = [] |
78 self.Command = [] |
75 for i,word in enumerate(Command.replace("'",'"').split('"')): |
79 for i,word in enumerate(Command.replace("'",'"').split('"')): |
87 self.no_stdout = no_stdout |
91 self.no_stdout = no_stdout |
88 self.no_stderr = no_stderr |
92 self.no_stderr = no_stderr |
89 self.startupinfo = None |
93 self.startupinfo = None |
90 self.errlen = 0 |
94 self.errlen = 0 |
91 self.outlen = 0 |
95 self.outlen = 0 |
|
96 self.errlimit = errlimit |
|
97 self.outlimit = outlimit |
92 self.exitcode = None |
98 self.exitcode = None |
93 self.outdata = "" |
99 self.outdata = [] |
94 self.errdata = "" |
100 self.errdata = [] |
95 self.finished = False |
101 self.keyword = keyword |
|
102 self.kill_it = kill_it |
|
103 self.finishsem = Semaphore(0) |
|
104 self.endlock = Lock() |
96 |
105 |
97 popenargs= { |
106 popenargs= { |
98 "cwd":os.getcwd(), |
107 "cwd":os.getcwd(), |
99 "stdin":subprocess.PIPE, |
108 "stdin":subprocess.PIPE, |
100 "stdout":subprocess.PIPE, |
109 "stdout":subprocess.PIPE, |
103 if no_gui == True and wx.Platform == '__WXMSW__': |
112 if no_gui == True and wx.Platform == '__WXMSW__': |
104 self.startupinfo = subprocess.STARTUPINFO() |
113 self.startupinfo = subprocess.STARTUPINFO() |
105 self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW |
114 self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW |
106 popenargs["startupinfo"] = self.startupinfo |
115 popenargs["startupinfo"] = self.startupinfo |
107 elif wx.Platform == '__WXGTK__': |
116 elif wx.Platform == '__WXGTK__': |
108 popenargs["shell"] = False #True |
117 popenargs["shell"] = False |
109 |
118 |
110 self.Proc = subprocess.Popen( self.Command, **popenargs ) |
119 self.Proc = subprocess.Popen( self.Command, **popenargs ) |
111 |
120 |
112 self.outt = outputThread( |
121 self.outt = outputThread( |
113 self.Proc, |
122 self.Proc, |
120 self.Proc, |
129 self.Proc, |
121 self.Proc.stderr, |
130 self.Proc.stderr, |
122 self.errors) |
131 self.errors) |
123 self.errt.start() |
132 self.errt.start() |
124 |
133 |
|
134 Timer(timeout,self.endlog).start() |
|
135 |
125 def output(self,v): |
136 def output(self,v): |
126 self.outdata += v |
137 self.outdata.append(v) |
127 self.outlen += 1 |
138 self.outlen += 1 |
128 if not self.no_stdout: |
139 if not self.no_stdout: |
129 self.logger.write(v) |
140 self.logger.write(v) |
|
141 if (self.keyword and v.find(self.keyword)!=-1) or (self.outlimit and self.outlen > self.outlimit): |
|
142 self.endlog() |
130 |
143 |
131 def errors(self,v): |
144 def errors(self,v): |
132 self.errdata += v |
145 self.errdata.append(v) |
133 self.errlen += 1 |
146 self.errlen += 1 |
134 if not self.no_stderr: |
147 if not self.no_stderr: |
135 self.logger.write_warning(v) |
148 self.logger.write_warning(v) |
|
149 if self.errlimit and self.errlen > self.errlimit: |
|
150 self.endlog() |
136 |
151 |
137 def log_the_end(self,ecode,pid): |
152 def log_the_end(self,ecode,pid): |
138 self.logger.write(self.Command_str + "\n") |
153 self.logger.write(self.Command_str + "\n") |
139 self.logger.write_warning(_("exited with status %s (pid %s)\n")%(str(ecode),str(pid))) |
154 self.logger.write_warning(_("exited with status %s (pid %s)\n")%(str(ecode),str(pid))) |
140 |
155 |
141 def finish(self, pid,ecode): |
156 def finish(self, pid,ecode): |
142 self.finished = True |
|
143 self.exitcode = ecode |
157 self.exitcode = ecode |
144 if self.exitcode != 0: |
158 if self.exitcode != 0: |
145 self.log_the_end(ecode,pid) |
159 self.log_the_end(ecode,pid) |
146 if self.finish_callback is not None: |
160 if self.finish_callback is not None: |
147 self.finish_callback(self,ecode,pid) |
161 self.finish_callback(self,ecode,pid) |
|
162 self.finishsem.release() |
148 |
163 |
149 def kill(self,gently=True): |
164 def kill(self,gently=True): |
150 self.outt.killed = True |
165 self.outt.killed = True |
151 self.errt.killed = True |
166 self.errt.killed = True |
152 if wx.Platform == '__WXMSW__': |
167 if wx.Platform == '__WXMSW__': |
164 except: |
179 except: |
165 pass |
180 pass |
166 self.outt.join() |
181 self.outt.join() |
167 self.errt.join() |
182 self.errt.join() |
168 |
183 |
169 def spin(self, timeout=None, out_limit=None, err_limit=None, keyword = None, kill_it = True): |
184 def endlog(self): |
170 count = 0 |
185 if self.endlock.acquire(False): |
171 while not self.finished: |
186 self.finishsem.release() |
172 if err_limit and self.errlen > err_limit: |
187 if not self.outt.finished and self.kill_it: |
173 break |
188 self.kill() |
174 if out_limit and self.outlen > out_limit: |
|
175 break |
|
176 if timeout: |
|
177 if count > timeout: |
|
178 break |
|
179 count += 1 |
|
180 if keyword and self.outdata.find(keyword)!=-1: |
|
181 break |
|
182 app = wx.GetApp() |
|
183 if app is not None: |
|
184 app.Yield() |
|
185 time.sleep(0.01) |
|
186 |
189 |
187 if not self.outt.finished and kill_it: |
190 |
188 self.kill() |
191 def spin(self): |
|
192 self.finishsem.acquire() |
|
193 return [self.exitcode, "".join(self.outdata), "".join(self.errdata)] |
189 |
194 |
190 return [self.exitcode, self.outdata, self.errdata] |
|
191 |
|