runner: increase start/stop timeout to 10 seconds, for #68
[buildbot.git] / buildbot / scripts / logwatcher.py
blob4e84095d5c614f85704ed394770de61fc3c11faf
2 import os
3 from twisted.python.failure import Failure
4 from twisted.internet import task, defer, reactor
5 from twisted.protocols.basic import LineOnlyReceiver
7 class FakeTransport:
8 disconnecting = False
10 class BuildmasterTimeoutError(Exception):
11 pass
12 class BuildslaveTimeoutError(Exception):
13 pass
14 class ReconfigError(Exception):
15 pass
16 class BuildSlaveDetectedError(Exception):
17 pass
19 class LogWatcher(LineOnlyReceiver):
20 POLL_INTERVAL = 0.1
21 TIMEOUT_DELAY = 10.0
22 delimiter = os.linesep
24 def __init__(self, logfile):
25 self.logfile = logfile
26 self.in_reconfig = False
27 self.transport = FakeTransport()
28 self.f = None
29 self.processtype = "buildmaster"
31 def start(self):
32 # return a Deferred that fires when the reconfig process has
33 # finished. It errbacks with TimeoutError if the finish line has not
34 # been seen within 10 seconds, and with ReconfigError if the error
35 # line was seen. If the logfile could not be opened, it errbacks with
36 # an IOError.
37 self.running = True
38 d = defer.maybeDeferred(self._start)
39 return d
41 def _start(self):
42 self.d = defer.Deferred()
43 try:
44 self.f = open(self.logfile, "rb")
45 self.f.seek(0, 2) # start watching from the end
46 except IOError:
47 pass
48 reactor.callLater(self.TIMEOUT_DELAY, self.timeout)
49 self.poller = task.LoopingCall(self.poll)
50 self.poller.start(self.POLL_INTERVAL)
51 return self.d
53 def timeout(self):
54 if self.processtype == "buildmaster":
55 self.d.errback(BuildmasterTimeoutError())
56 else:
57 self.d.errback(BuildslaveTimeoutError())
59 def finished(self, results):
60 self.running = False
61 self.in_reconfig = False
62 self.d.callback(results)
64 def lineReceived(self, line):
65 if not self.running:
66 return
67 if "Log opened." in line:
68 self.in_reconfig = True
69 if "loading configuration from" in line:
70 self.in_reconfig = True
71 if "Creating BuildSlave" in line:
72 self.processtype = "buildslave"
74 if self.in_reconfig:
75 print line
77 if "message from master: attached" in line:
78 return self.finished("buildslave")
79 if "I will keep using the previous config file" in line:
80 return self.finished(Failure(ReconfigError()))
81 if "configuration update complete" in line:
82 return self.finished("buildmaster")
84 def poll(self):
85 if not self.f:
86 try:
87 self.f = open(self.logfile, "rb")
88 except IOError:
89 return
90 while True:
91 data = self.f.read(1000)
92 if not data:
93 return
94 self.dataReceived(data)