Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: third_party/twisted_8_1/twisted/internet/_dumbwin32proc.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.test.test_process -*-
2 # Copyright (c) 2001-2008 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 http://isometric.sixsided.org/_/gates_in_the_head/
7 """
8
9 import os
10
11 # Win32 imports
12 import win32api
13 import win32con
14 import win32event
15 import win32file
16 import win32pipe
17 import win32process
18 import win32security
19
20 import pywintypes
21
22 # security attributes for pipes
23 PIPE_ATTRS_INHERITABLE = win32security.SECURITY_ATTRIBUTES()
24 PIPE_ATTRS_INHERITABLE.bInheritHandle = 1
25
26 from zope.interface import implements
27 from twisted.internet.interfaces import IProcessTransport, IConsumer, IProducer
28
29 from twisted.python.win32 import quoteArguments
30
31 from twisted.internet import error
32 from twisted.python import failure
33
34 from twisted.internet import _pollingfile
35
36 def debug(msg):
37 import sys
38 print msg
39 sys.stdout.flush()
40
41 class _Reaper(_pollingfile._PollableResource):
42
43 def __init__(self, proc):
44 self.proc = proc
45
46 def checkWork(self):
47 if win32event.WaitForSingleObject(self.proc.hProcess, 0) != win32event.W AIT_OBJECT_0:
48 return 0
49 exitCode = win32process.GetExitCodeProcess(self.proc.hProcess)
50 self.deactivate()
51 self.proc.processEnded(exitCode)
52 return 0
53
54
55 def _findShebang(filename):
56 """
57 Look for a #! line, and return the value following the #! if one exists, or
58 None if this file is not a script.
59
60 I don't know if there are any conventions for quoting in Windows shebang
61 lines, so this doesn't support any; therefore, you may not pass any
62 arguments to scripts invoked as filters. That's probably wrong, so if
63 somebody knows more about the cultural expectations on Windows, please feel
64 free to fix.
65
66 This shebang line support was added in support of the CGI tests;
67 appropriately enough, I determined that shebang lines are culturally
68 accepted in the Windows world through this page:
69
70 http://www.cgi101.com/learn/connect/winxp.html
71
72 @param filename: str representing a filename
73
74 @return: a str representing another filename.
75 """
76 f = file(filename, 'ru')
77 if f.read(2) == '#!':
78 exe = f.readline(1024).strip('\n')
79 return exe
80
81 def _invalidWin32App(pywinerr):
82 """
83 Determine if a pywintypes.error is telling us that the given process is
84 'not a valid win32 application', i.e. not a PE format executable.
85
86 @param pywinerr: a pywintypes.error instance raised by CreateProcess
87
88 @return: a boolean
89 """
90
91 # Let's do this better in the future, but I have no idea what this error
92 # is; MSDN doesn't mention it, and there is no symbolic constant in
93 # win32process module that represents 193.
94
95 return pywinerr.args[0] == 193
96
97 class Process(_pollingfile._PollingTimer):
98 """A process that integrates with the Twisted event loop.
99
100 If your subprocess is a python program, you need to:
101
102 - Run python.exe with the '-u' command line option - this turns on
103 unbuffered I/O. Buffering stdout/err/in can cause problems, see e.g.
104 http://support.microsoft.com/default.aspx?scid=kb;EN-US;q1903
105
106 - If you don't want Windows messing with data passed over
107 stdin/out/err, set the pipes to be in binary mode::
108
109 import os, sys, mscvrt
110 msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
111 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
112 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
113
114 """
115 implements(IProcessTransport, IConsumer, IProducer)
116
117 buffer = ''
118 pid = None
119
120 def __init__(self, reactor, protocol, command, args, environment, path):
121 _pollingfile._PollingTimer.__init__(self, reactor)
122 self.protocol = protocol
123
124 # security attributes for pipes
125 sAttrs = win32security.SECURITY_ATTRIBUTES()
126 sAttrs.bInheritHandle = 1
127
128 # create the pipes which will connect to the secondary process
129 self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0)
130 self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0)
131 hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0)
132
133 win32pipe.SetNamedPipeHandleState(self.hStdinW,
134 win32pipe.PIPE_NOWAIT,
135 None,
136 None)
137
138 # set the info structure for the new process.
139 StartupInfo = win32process.STARTUPINFO()
140 StartupInfo.hStdOutput = hStdoutW
141 StartupInfo.hStdError = hStderrW
142 StartupInfo.hStdInput = hStdinR
143 StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES
144
145 # Create new handles whose inheritance property is false
146 currentPid = win32api.GetCurrentProcess()
147
148 tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0,
149 win32con.DUPLICATE_SAME_ACCESS)
150 win32file.CloseHandle(self.hStdoutR)
151 self.hStdoutR = tmp
152
153 tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0,
154 win32con.DUPLICATE_SAME_ACCESS)
155 win32file.CloseHandle(self.hStderrR)
156 self.hStderrR = tmp
157
158 tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0,
159 win32con.DUPLICATE_SAME_ACCESS)
160 win32file.CloseHandle(self.hStdinW)
161 self.hStdinW = tmp
162
163 # Add the specified environment to the current environment - this is
164 # necessary because certain operations are only supported on Windows
165 # if certain environment variables are present.
166
167 env = os.environ.copy()
168 env.update(environment or {})
169
170 cmdline = quoteArguments(args)
171 # TODO: error detection here.
172 def doCreate():
173 self.hProcess, self.hThread, self.pid, dwTid = win32process.CreatePr ocess(
174 command, cmdline, None, None, 1, 0, env, path, StartupInfo)
175 try:
176 doCreate()
177 except pywintypes.error, pwte:
178 if not _invalidWin32App(pwte):
179 # This behavior isn't _really_ documented, but let's make it
180 # consistent with the behavior that is documented.
181 raise OSError(pwte)
182 else:
183 # look for a shebang line. Insert the original 'command'
184 # (actually a script) into the new arguments list.
185 sheb = _findShebang(command)
186 if sheb is None:
187 raise OSError(
188 "%r is neither a Windows executable, "
189 "nor a script with a shebang line" % command)
190 else:
191 args = list(args)
192 args.insert(0, command)
193 cmdline = quoteArguments(args)
194 origcmd = command
195 command = sheb
196 try:
197 # Let's try again.
198 doCreate()
199 except pywintypes.error, pwte2:
200 # d'oh, failed again!
201 if _invalidWin32App(pwte2):
202 raise OSError(
203 "%r has an invalid shebang line: "
204 "%r is not a valid executable" % (
205 origcmd, sheb))
206 raise OSError(pwte2)
207
208 win32file.CloseHandle(self.hThread)
209
210 # close handles which only the child will use
211 win32file.CloseHandle(hStderrW)
212 win32file.CloseHandle(hStdoutW)
213 win32file.CloseHandle(hStdinR)
214
215 self.closed = 0
216 self.closedNotifies = 0
217
218 # set up everything
219 self.stdout = _pollingfile._PollableReadPipe(
220 self.hStdoutR,
221 lambda data: self.protocol.childDataReceived(1, data),
222 self.outConnectionLost)
223
224 self.stderr = _pollingfile._PollableReadPipe(
225 self.hStderrR,
226 lambda data: self.protocol.childDataReceived(2, data),
227 self.errConnectionLost)
228
229 self.stdin = _pollingfile._PollableWritePipe(
230 self.hStdinW, self.inConnectionLost)
231
232 for pipewatcher in self.stdout, self.stderr, self.stdin:
233 self._addPollableResource(pipewatcher)
234
235
236 # notify protocol
237 self.protocol.makeConnection(self)
238
239 # (maybe?) a good idea in win32er, otherwise not
240 # self.reactor.addEvent(self.hProcess, self, 'inConnectionLost')
241
242
243 def signalProcess(self, signalID):
244 if self.pid is None:
245 raise error.ProcessExitedAlready()
246 if signalID in ("INT", "TERM", "KILL"):
247 os.popen('taskkill /T /F /PID %s' % self.pid)
248
249 def processEnded(self, status):
250 """
251 This is called when the child terminates.
252 """
253 self.pid = None
254 if status == 0:
255 err = error.ProcessDone(status)
256 else:
257 err = error.ProcessTerminated(status)
258 self.protocol.processEnded(failure.Failure(err))
259
260
261 def write(self, data):
262 """Write data to the process' stdin."""
263 self.stdin.write(data)
264
265 def writeSequence(self, seq):
266 """Write data to the process' stdin."""
267 self.stdin.writeSequence(seq)
268
269 def closeChildFD(self, fd):
270 if fd == 0:
271 self.closeStdin()
272 elif fd == 1:
273 self.closeStdout()
274 elif fd == 2:
275 self.closeStderr()
276 else:
277 raise NotImplementedError("Only standard-IO file descriptors availab le on win32")
278
279 def closeStdin(self):
280 """Close the process' stdin.
281 """
282 self.stdin.close()
283
284 def closeStderr(self):
285 self.stderr.close()
286
287 def closeStdout(self):
288 self.stdout.close()
289
290 def loseConnection(self):
291 """Close the process' stdout, in and err."""
292 self.closeStdin()
293 self.closeStdout()
294 self.closeStderr()
295
296 def outConnectionLost(self):
297 self.protocol.childConnectionLost(1)
298 self.connectionLostNotify()
299
300 def errConnectionLost(self):
301 self.protocol.childConnectionLost(2)
302 self.connectionLostNotify()
303
304 def inConnectionLost(self):
305 self.protocol.childConnectionLost(0)
306 self.connectionLostNotify()
307
308 def connectionLostNotify(self):
309 """Will be called 3 times, by stdout/err threads and process handle."""
310 self.closedNotifies = self.closedNotifies + 1
311 if self.closedNotifies == 3:
312 self.closed = 1
313 self._addPollableResource(_Reaper(self))
314
315 # IConsumer
316 def registerProducer(self, producer, streaming):
317 self.stdin.registerProducer(producer, streaming)
318
319 def unregisterProducer(self):
320 self.stdin.unregisterProducer()
321
322 # IProducer
323 def pauseProducing(self):
324 self._pause()
325
326 def resumeProducing(self):
327 self._unpause()
328
329 def stopProducing(self):
330 self.loseConnection()
331
332
333 def __repr__(self):
334 """
335 Return a string representation of the process.
336 """
337 return "<%s pid=%s>" % (self.__class__.__name__, self.pid)
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/internet/__init__.py ('k') | third_party/twisted_8_1/twisted/internet/_dumbwin32proc_orig.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698