OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.conch.test.test_manhole -*- | |
2 # Copyright (c) 2001-2007 Twisted Matrix Laboratories. | |
3 # See LICENSE for details. | |
4 | |
5 """ | |
6 Asynchronous local terminal input handling | |
7 | |
8 @author: U{Jp Calderone<mailto:exarkun@twistedmatrix.com>} | |
9 """ | |
10 | |
11 import os, tty, sys, termios | |
12 | |
13 from twisted.internet import reactor, stdio, protocol, defer | |
14 from twisted.python import failure, reflect, log | |
15 | |
16 from twisted.conch.insults.insults import ServerProtocol | |
17 from twisted.conch.manhole import ColoredManhole | |
18 | |
19 class UnexpectedOutputError(Exception): | |
20 pass | |
21 | |
22 class TerminalProcessProtocol(protocol.ProcessProtocol): | |
23 def __init__(self, proto): | |
24 self.proto = proto | |
25 self.onConnection = defer.Deferred() | |
26 | |
27 def connectionMade(self): | |
28 self.proto.makeConnection(self) | |
29 self.onConnection.callback(None) | |
30 self.onConnection = None | |
31 | |
32 def write(self, bytes): | |
33 self.transport.write(bytes) | |
34 | |
35 def outReceived(self, bytes): | |
36 self.proto.dataReceived(bytes) | |
37 | |
38 def errReceived(self, bytes): | |
39 self.transport.loseConnection() | |
40 if self.proto is not None: | |
41 self.proto.connectionLost(failure.Failure(UnexpectedOutputError(byte
s))) | |
42 self.proto = None | |
43 | |
44 def childConnectionLost(self, childFD): | |
45 if self.proto is not None: | |
46 self.proto.childConnectionLost(childFD) | |
47 | |
48 def processEnded(self, reason): | |
49 if self.proto is not None: | |
50 self.proto.connectionLost(reason) | |
51 self.proto = None | |
52 | |
53 | |
54 | |
55 class ConsoleManhole(ColoredManhole): | |
56 """ | |
57 A manhole protocol specifically for use with L{stdio.StandardIO}. | |
58 """ | |
59 def connectionLost(self, reason): | |
60 """ | |
61 When the connection is lost, there is nothing more to do. Stop the | |
62 reactor so that the process can exit. | |
63 """ | |
64 reactor.stop() | |
65 | |
66 | |
67 | |
68 def runWithProtocol(klass): | |
69 fd = sys.__stdin__.fileno() | |
70 oldSettings = termios.tcgetattr(fd) | |
71 tty.setraw(fd) | |
72 try: | |
73 p = ServerProtocol(klass) | |
74 stdio.StandardIO(p) | |
75 reactor.run() | |
76 finally: | |
77 termios.tcsetattr(fd, termios.TCSANOW, oldSettings) | |
78 os.write(fd, "\r\x1bc\r") | |
79 | |
80 | |
81 | |
82 def main(argv=None): | |
83 log.startLogging(file('child.log', 'w')) | |
84 | |
85 if argv is None: | |
86 argv = sys.argv[1:] | |
87 if argv: | |
88 klass = reflect.namedClass(argv[0]) | |
89 else: | |
90 klass = ConsoleManhole | |
91 runWithProtocol(klass) | |
92 | |
93 | |
94 if __name__ == '__main__': | |
95 main() | |
OLD | NEW |