Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/buildbot/buildbot/scripts/logwatcher.py
diff options
context:
space:
mode:
Diffstat (limited to 'buildbot/buildbot/scripts/logwatcher.py')
-rw-r--r--buildbot/buildbot/scripts/logwatcher.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/buildbot/buildbot/scripts/logwatcher.py b/buildbot/buildbot/scripts/logwatcher.py
new file mode 100644
index 0000000..e959afb
--- /dev/null
+++ b/buildbot/buildbot/scripts/logwatcher.py
@@ -0,0 +1,97 @@
+
+import os
+from twisted.python.failure import Failure
+from twisted.internet import defer, reactor, protocol, error
+from twisted.protocols.basic import LineOnlyReceiver
+
+class FakeTransport:
+ disconnecting = False
+
+class BuildmasterTimeoutError(Exception):
+ pass
+class BuildslaveTimeoutError(Exception):
+ pass
+class ReconfigError(Exception):
+ pass
+class BuildSlaveDetectedError(Exception):
+ pass
+
+class TailProcess(protocol.ProcessProtocol):
+ def outReceived(self, data):
+ self.lw.dataReceived(data)
+ def errReceived(self, data):
+ print "ERR: '%s'" % (data,)
+
+
+class LogWatcher(LineOnlyReceiver):
+ POLL_INTERVAL = 0.1
+ TIMEOUT_DELAY = 10.0
+ delimiter = os.linesep
+
+ def __init__(self, logfile):
+ self.logfile = logfile
+ self.in_reconfig = False
+ self.transport = FakeTransport()
+ self.pp = TailProcess()
+ self.pp.lw = self
+ self.processtype = "buildmaster"
+ self.timer = None
+
+ def start(self):
+ # return a Deferred that fires when the reconfig process has
+ # finished. It errbacks with TimeoutError if the finish line has not
+ # been seen within 10 seconds, and with ReconfigError if the error
+ # line was seen. If the logfile could not be opened, it errbacks with
+ # an IOError.
+ self.p = reactor.spawnProcess(self.pp, "/usr/bin/tail",
+ ("tail", "-f", "-n", "0", self.logfile),
+ env=os.environ,
+ )
+ self.running = True
+ d = defer.maybeDeferred(self._start)
+ return d
+
+ def _start(self):
+ self.d = defer.Deferred()
+ self.timer = reactor.callLater(self.TIMEOUT_DELAY, self.timeout)
+ return self.d
+
+ def timeout(self):
+ self.timer = None
+ if self.processtype == "buildmaster":
+ e = BuildmasterTimeoutError()
+ else:
+ e = BuildslaveTimeoutError()
+ self.finished(Failure(e))
+
+ def finished(self, results):
+ try:
+ self.p.signalProcess("KILL")
+ except error.ProcessExitedAlready:
+ pass
+ if self.timer:
+ self.timer.cancel()
+ self.timer = None
+ self.running = False
+ self.in_reconfig = False
+ self.d.callback(results)
+
+ def lineReceived(self, line):
+ if not self.running:
+ return
+ if "Log opened." in line:
+ self.in_reconfig = True
+ if "loading configuration from" in line:
+ self.in_reconfig = True
+ if "Creating BuildSlave" in line:
+ self.processtype = "buildslave"
+
+ if self.in_reconfig:
+ print line
+
+ if "message from master: attached" in line:
+ return self.finished("buildslave")
+ if "I will keep using the previous config file" in line:
+ return self.finished(Failure(ReconfigError()))
+ if "configuration update complete" in line:
+ return self.finished("buildmaster")