[Buildbot-commits] buildbot/buildbot/status html.py,1.44,1.45 builder.py,1.44,1.45
Brian Warner
warner at users.sourceforge.net
Wed Nov 24 02:41:24 UTC 2004
Update of /cvsroot/buildbot/buildbot/buildbot/status
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8495/buildbot/status
Modified Files:
html.py builder.py
Log Message:
* buildbot/status/html.py (TextLog): split render() up into
render_HEAD and render_GET. Use a Producer when sending log
chunks, to reduce memory requirements and avoid sending huge
non-Banana-able strings over web.distrib connections. Requires
peeking under the covers of IStatusLog.
* buildbot/status/builder.py (HTMLLogFile.waitUntilFinished): oops,
use defer.succeed, not the non-existent defer.success
(LogFile.waitUntilFinished): same
(LogFile.subscribe): don't add watchers to a finished logfile
Index: builder.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- builder.py 23 Nov 2004 10:51:03 -0000 1.44
+++ builder.py 24 Nov 2004 02:41:22 -0000 1.45
@@ -98,7 +98,7 @@
return self.finished
def waitUntilFinished(self):
if self.finished:
- d = defer.success(self)
+ d = defer.succeed(self)
else:
d = defer.Deferred()
self.finishedWatchers.append(d)
@@ -113,6 +113,8 @@
return self.entries + self.runEntries
def subscribe(self, receiver, catchup):
+ if self.finished:
+ return
self.watchers.append(receiver)
if catchup:
for channel, text in self.entries + self.runEntries:
@@ -213,7 +215,7 @@
def isFinished(self):
return True
def waitUntilFinished(self):
- return defer.success(self)
+ return defer.succeed(self)
def getText(self):
return self.html # looks kinda like text
Index: html.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/html.py,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- html.py 23 Nov 2004 03:58:15 -0000 1.44
+++ html.py 24 Nov 2004 02:41:21 -0000 1.45
@@ -456,12 +456,13 @@
"""
class TextLog(Resource):
+ # a new instance of this Resource is created for each client who views
+ # it, so we can afford to track the request in the Resource.
__implements__ = IHTMLLog,
def __init__(self, original):
Resource.__init__(self)
self.original = original
- self.watchers = []
def htmlHeader(self, request):
title = "Log File contents"
@@ -491,70 +492,72 @@
data += "</body></html>\n"
return data
- def render(self, request):
+ def render_HEAD(self, request):
asText = request.args.get("text", None)
-
if asText:
request.setHeader("content-type", "text/plain")
else:
request.setHeader("content-type", "text/html")
- if request.method == "HEAD":
- # vague approximation, ignores markup
- request.setHeader("content-length", self.original.length)
- return ''
-
- data = ""
- if not asText:
- data += self.htmlHeader(request)
- data += self.content(self.original.getChunks(), asText)
+ # vague approximation, ignores markup
+ request.setHeader("content-length", self.original.length)
+ return ''
- # TODO: to implement a producer for this:
- # Create an object that knows about the LogFile. That object's
- # .resumeProducing method should pull text from the LogFile's
- # .entries, convert them to HTML, then send them to request.write .
- # (remember that .entries may be added while the request is being
- # served). When all .entries are consumed, send everything in
- # .runEntries (oh and do those all before they get merged into a
- # new .entries item). Then attach the request to our .watchers
- # method and make sure the LogFile knows about us.
+ def resumeProducing(self):
+ if self.chunkNumber < len(self.original.entries):
+ chunk = self.original.entries[self.chunkNumber]
+ self.chunkNumber += 1
+ self.req.write(self.content([chunk], self.asText))
+ return
+ # now send all of .runEntries in a batch
+ data = self.content(self.original.runEntries, self.asText)
+ self.req.write(data)
+ self.req.unregisterProducer()
+ # then see if there is more to come
+ self.original.subscribe(self, False)
+ d = self.original.waitUntilFinished()
+ d.addCallback(self.finished)
- if self.original.finished:
- if not asText:
- data += self.htmlFooter()
- return data # all done
+ def render_GET(self, req):
+ self.req = req
+ self.asText = self.req.args.get("text", None)
- try:
- request.write(data)
- except pb.DeadReferenceError:
- # master server died awfully early
- return "you're never going to hear this, are you"
+ if self.asText:
+ req.setHeader("content-type", "text/plain")
+ else:
+ req.setHeader("content-type", "text/html")
- self.watchers.append((request, asText))
- self.original.subscribe(self, False)
- self.original.waitUntilFinished().addCallback(self.finished)
+ if not self.asText:
+ req.write(self.htmlHeader(req))
- d = request.notifyFinish()
- d.addErrback(lambda why: self.watchers.remove((request, asText)))
+ self.chunkNumber = 0
+ req.registerProducer(self, False)
+ d = req.notifyFinish()
+ d.addErrback(self.stop)
return server.NOT_DONE_YET
+ def stop(self, why):
+ self.original.unsubscribe(self)
+ self.req.unregisterProducer()
+ # our .finished callback may still be fired
+ self.req = None
+
def logChunk(self, build, step, log, channel, text):
- for request, asText in self.watchers[:]:
- output = self.content([(channel, text)], asText)
- try:
- request.write(output)
- except pb.DeadReferenceError:
- self.watchers.remove((request, asText))
+ output = self.content([(channel, text)], self.asText)
+ try:
+ self.req.write(output)
+ except pb.DeadReferenceError:
+ log.unsubscribe(self)
def finished(self, log):
- for request, asText in self.watchers:
- try:
- if not asText:
- request.write(self.htmlFooter())
- request.finish()
- except pb.DeadReferenceError:
- pass
- self.watchers = []
+ if not self.req:
+ return
+ try:
+ if not self.asText:
+ self.req.write(self.htmlFooter())
+ self.req.finish()
+ except pb.DeadReferenceError:
+ pass
components.registerAdapter(TextLog, interfaces.IStatusLog, IHTMLLog)
More information about the Commits
mailing list