|
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 # based on wxPopen.py from boa-constructor |
|
27 # |
|
28 |
|
29 import time |
|
30 from StringIO import StringIO |
|
31 |
|
32 from wxPython.wx import * |
|
33 |
|
34 class ProcessRunnerMix: |
|
35 def __init__(self, input, handler=None): |
|
36 if handler is None: |
|
37 handler = self |
|
38 self.handler = handler |
|
39 EVT_IDLE(handler, self.OnIdle) |
|
40 EVT_END_PROCESS(handler, -1, self.OnProcessEnded) |
|
41 |
|
42 input.reverse() # so we can pop |
|
43 self.input = input |
|
44 |
|
45 self.reset() |
|
46 |
|
47 def reset(self): |
|
48 self.process = None |
|
49 self.pid = -1 |
|
50 self.output = [] |
|
51 self.errors = [] |
|
52 self.inputStream = None |
|
53 self.errorStream = None |
|
54 self.outputStream = None |
|
55 self.outputFunc = None |
|
56 self.errorsFunc = None |
|
57 self.finishedFunc = None |
|
58 self.finished = false |
|
59 self.responded = false |
|
60 |
|
61 def execute(self, cmd): |
|
62 self.process = wxProcess(self.handler) |
|
63 self.process.Redirect() |
|
64 |
|
65 self.pid = wxExecute(cmd, wxEXEC_NOHIDE, self.process) |
|
66 |
|
67 self.inputStream = self.process.GetOutputStream() |
|
68 self.errorStream = self.process.GetErrorStream() |
|
69 self.outputStream = self.process.GetInputStream() |
|
70 |
|
71 #self.OnIdle() |
|
72 wxWakeUpIdle() |
|
73 |
|
74 def setCallbacks(self, output, errors, finished): |
|
75 self.outputFunc = output |
|
76 self.errorsFunc = errors |
|
77 self.finishedFunc = finished |
|
78 |
|
79 def detach(self): |
|
80 if self.process is not None: |
|
81 self.process.CloseOutput() |
|
82 self.process.Detach() |
|
83 self.process = None |
|
84 |
|
85 def kill(self): |
|
86 if self.process is not None: |
|
87 self.process.CloseOutput() |
|
88 if wxProcess_Kill(self.pid, wxSIGTERM) != wxKILL_OK: |
|
89 wxProcess_Kill(self.pid, wxSIGKILL) |
|
90 self.process = None |
|
91 |
|
92 def updateStream(self, stream, data): |
|
93 if stream and stream.CanRead(): |
|
94 if not self.responded: |
|
95 self.responded = true |
|
96 text = stream.read() |
|
97 data.append(text) |
|
98 return text |
|
99 else: |
|
100 return None |
|
101 |
|
102 def updateInpStream(self, stream, input): |
|
103 if stream and input: |
|
104 line = input.pop() |
|
105 stream.write(line) |
|
106 |
|
107 def updateErrStream(self, stream, data): |
|
108 return self.updateStream(stream, data) |
|
109 |
|
110 def updateOutStream(self, stream, data): |
|
111 return self.updateStream(stream, data) |
|
112 |
|
113 def OnIdle(self, event=None): |
|
114 if self.process is not None: |
|
115 self.updateInpStream(self.inputStream, self.input) |
|
116 e = self.updateErrStream(self.errorStream, self.errors) |
|
117 if e is not None and self.errorsFunc is not None: |
|
118 wxCallAfter(self.errorsFunc, e) |
|
119 o = self.updateOutStream(self.outputStream, self.output) |
|
120 if o is not None and self.outputFunc is not None: |
|
121 wxCallAfter(self.outputFunc, o) |
|
122 |
|
123 #wxWakeUpIdle() |
|
124 #time.sleep(0.001) |
|
125 |
|
126 def OnProcessEnded(self, event): |
|
127 self.OnIdle() |
|
128 pid,exitcode = event.GetPid(), event.GetExitCode() |
|
129 if self.process: |
|
130 self.process.Destroy() |
|
131 self.process = None |
|
132 |
|
133 self.finished = true |
|
134 |
|
135 # XXX doesn't work ??? |
|
136 #self.handler.Disconnect(-1, wxEVT_IDLE) |
|
137 |
|
138 if self.finishedFunc: |
|
139 wxCallAfter(self.finishedFunc, pid, exitcode) |
|
140 |
|
141 class ProcessRunner(wxEvtHandler, ProcessRunnerMix): |
|
142 def __init__(self, input): |
|
143 wxEvtHandler.__init__(self) |
|
144 ProcessRunnerMix.__init__(self, input) |
|
145 |
|
146 def wxPopen3(cmd, input, output, errors, finish, handler=None): |
|
147 p = ProcessRunnerMix(input, handler) |
|
148 p.setCallbacks(output, errors, finish) |
|
149 p.execute(cmd) |
|
150 return p |
|
151 |
|
152 |