[Buildbot-commits] buildbot/buildbot/status/web base.py, 1.1, 1.2 baseweb.py, 1.2, 1.3 build.py, 1.1, 1.2 builder.py, 1.1, 1.2 changes.py, 1.1, 1.2 step.py, 1.1, 1.2 tests.py, 1.1, 1.2 waterfall.py, 1.6, 1.7
Brian Warner
warner at users.sourceforge.net
Wed Aug 1 22:08:28 UTC 2007
Update of /cvsroot/buildbot/buildbot/buildbot/status/web
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv29193/buildbot/status/web
Modified Files:
base.py baseweb.py build.py builder.py changes.py step.py
tests.py waterfall.py
Log Message:
[project @ web-refactoring: finally got the Waterfall rendering again, lots of bad links and incomplete code]
Original author: warner at lothar.com
Date: 2007-07-30 20:06:58+00:00
Index: base.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/base.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- base.py 1 Aug 2007 22:08:11 -0000 1.1
+++ base.py 1 Aug 2007 22:08:26 -0000 1.2
@@ -1,4 +1,10 @@
+from zope.interface import Interface
+from twisted.web import html, resource
+from buildbot.status import builder
+
+
+
class ITopBox(Interface):
"""I represent a box in the top row of the waterfall display: the one
which shows the status of the last build for each builder."""
@@ -58,8 +64,8 @@
data += ">"
if not text:
text = " "
- if type(text) == types.ListType:
- data += string.join(text, "<br />")
+ if isinstance(text, list):
+ data += "<br />".join(text)
else:
data += text
data += "</td>\n"
@@ -116,7 +122,8 @@
return td(text, props, bgcolor=self.color, class_=self.class_)
-class HtmlResource(Resource):
+class HtmlResource(resource.Resource):
+ # this is a cheap sort of template thingy
css = None
contentType = "text/html; charset=UTF-8"
title = "Dummy"
@@ -131,28 +138,43 @@
return ''
return data
+ def getStatus(self, request):
+ return request.site.buildbot_service.getStatus()
+ def getControl(self, request):
+ return request.site.buildbot_service.getControl()
+
+ def getChangemaster(self, request):
+ return request.site.buildbot_service.parent.change_svc
+
+ def path_to_root(self, request):
+ return "../" * len(request.prepath)
+
def getTitle(self, request):
return self.title
+ def fillTemplate(self, template, request):
+ s = request.site.buildbot_service
+ values = s.template_values.copy()
+ values['css_path'] = self.path_to_root(request) + s.css
+ values['title'] = self.getTitle(request)
+ return template % values
+
+ def getCSSlink(self, request):
+ css = request.site.css # might be None
+ if not css:
+ return None
+ url = "/".join([".." * self.depth] + [css])
+ return url
+
def content(self, request):
- data = ('<!DOCTYPE html PUBLIC'
- ' "-//W3C//DTD XHTML 1.0 Transitional//EN"\n'
- '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n'
- '<html'
- ' xmlns="http://www.w3.org/1999/xhtml"'
- ' lang="en"'
- ' xml:lang="en">\n')
- data += "<head>\n"
- data += " <title>" + self.getTitle(request) + "</title>\n"
- if self.css:
- # TODO: use some sort of relative link up to the root page, so
- # this css can be used from child pages too
- data += (' <link href="%s" rel="stylesheet" type="text/css"/>\n'
- % "buildbot.css")
- data += "</head>\n"
+ s = request.site.buildbot_service
+ data = ""
+ data += self.fillTemplate(s.header, request)
+
data += '<body vlink="#800080">\n'
data += self.body(request)
- data += "</body></html>\n"
+ data += "</body>\n"
+ data += s.footer
return data
def body(self, request):
Index: baseweb.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/baseweb.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- baseweb.py 1 Aug 2007 22:08:05 -0000 1.2
+++ baseweb.py 1 Aug 2007 22:08:26 -0000 1.3
@@ -4,159 +4,25 @@
from twisted.python import log
from twisted.application import service, strports
-from twisted.web.resource import Resource
from twisted.web import server, distrib, static
from twisted.spread import pb
from buildbot.interfaces import IStatusReceiver, IControl
from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION
from buildbot.status.web.waterfall import WaterfallStatusResource
+from buildbot.status.web.base import HtmlResource
-class ImprovedWaterfall(WaterfallStatusResource):
- def __init__(self):
- WaterfallStatusResource.__init__(self, css="/buildbot.css")
-
- def getStatus(self, request):
- return request.site.status
- def getControl(self, request):
- return request.site.control
- def getChangemaster(self, request):
- return request.site.changemaster
-
-
-HEADER = '''
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- lang="en"
- xml:lang="en">
-
-'''
-
-FOOTER = '''
-</html>
-'''
-
-class WebStatus(service.MultiService):
- implements(IStatusReceiver)
-
- def __init__(self, http_port=None, distrib_port=None, allowForce=False,
- css=None):
- service.MultiService.__init__(self)
- if type(http_port) is int:
- http_port = "tcp:%d" % http_port
- self.http_port = http_port
- if distrib_port is not None:
- if type(distrib_port) is int:
- distrib_port = "tcp:%d" % distrib_port
- if distrib_port[0] in "/~.": # pathnames
- distrib_port = "unix:%s" % distrib_port
- self.distrib_port = distrib_port
- self.allowForce = allowForce
-
- self.root = static.File("public_html")
- log.msg("WebStatus using (%s)" % self.root.path)
- self.setupUsualPages()
- # once we get enabled, we'll stash a reference to the main IStatus
- # instance in site.status, so all of our childrens' render() methods
- # can access it as request.site.status
- self.site = server.Site(self.root)
- self.site.header = HEADER
- self.site.footer = FOOTER
- self.site.css = css
-
- if self.http_port is not None:
- s = strports.service(self.http_port, self.site)
- s.setServiceParent(self)
- if self.distrib_port is not None:
- f = pb.PBServerFactory(distrib.ResourcePublisher(self.site))
- s = strports.service(self.distrib_port, f)
- s.setServiceParent(self)
-
- def setupUsualPages(self):
- r = static.Data("This tree contains the built-in status pages\n",
- "text/plain")
- self.root.putChild("_buildbot", r)
- r.putChild("waterfall", ImprovedWaterfall())
- r.putChild("one_line_per_build", OneLinePerBuild())
-
- def getStatus(self):
- return self.site.status
-
- def setServiceParent(self, parent):
- """
- @type parent: L{buildbot.master.BuildMaster}
- """
- service.MultiService.setServiceParent(self, parent)
- self.setup()
-
- def setup(self):
- self.site.status = self.parent.getStatus()
- if self.allowForce:
- self.site.control = IControl(self.parent)
- else:
- self.site.control = None
- self.site.changemaster = self.parent.change_svc
- self.site.webstatus = self # TODO: why?
- self.site.basedir = self.parent.basedir # TODO: also why?
- # maybe self.site.head_stuff, to add to <head>
-
-# resources can get access to the site with request.site
-
-
-
-class HtmlResource(Resource):
- # this is a cheap sort of template thingy
- css = None
- contentType = "text/html; charset=UTF-8"
- title = "Dummy"
- depth = None # must be specified
-
- def render(self, request):
- data = self.content(request)
- if isinstance(data, unicode):
- data = data.encode("utf-8")
- request.setHeader("content-type", self.contentType)
- if request.method == "HEAD":
- request.setHeader("content-length", len(data))
- return ''
- return data
+from buildbot.status.web.changes import StatusResourceChanges
+from buildbot.status.web.step import StatusResourceBuildStep
+from buildbot.status.web.build import StatusResourceBuild
+from buildbot.status.web.builder import StatusResourceBuilder
- def getCSSlink(self, request):
- css = request.site.css # might be None
- if not css:
- return None
- url = "/".join([".." * self.depth] + [css])
- link = ' <link href="%s" rel="stylesheet" type="text/css"/>\n' % url
- return url
- def make_head(self, request):
- data = ""
- data += ' <title>%s</title>\n' % self.title
- # TODO: use some sort of relative link up to the root page, so
- # this css can be used from child pages too
- csslink = self.getCSSlink(request)
- if csslink:
- data += csslink
- # TODO: favicon
- return data
+# this class contains the status services (WebStatus and the older Waterfall)
+# which can be put in c['status']. It also contains some of the resources
+# that are attached to the WebStatus at various well-known URLs, which the
+# admin might wish to attach (using WebStatus.putChild) at other URLs.
- def content(self, request):
- data = ""
- data += request.site.header
- data += "<head>\n"
- data += self.make_head(request)
- data += "</head>\n"
- data += '<body vlink="#800080">\n'
- data += self.body(request)
- data += "</body>\n"
- data += request.site.footer
- return data
-
- def body(self, request):
- return "Dummy\n"
class TimelineOfEverything(WaterfallStatusResource):
@@ -316,3 +182,150 @@
return data
+
+HEADER = '''
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html
+ xmlns="http://www.w3.org/1999/xhtml"
+ lang="en"
+ xml:lang="en">
+
+<head>
+ <title>%(title)s</title>
+ <link href="%(css_path)s" rel="stylesheet" type="text/css" />
+</head>
+
+'''
+
+FOOTER = '''
+</html>
+'''
+
+
+class WebStatus(service.MultiService):
+ implements(IStatusReceiver)
+
+ """
+ The webserver provided by this class has the following resources:
+
+ /waterfall : the big time-oriented 'waterfall' display, with links
+ to individual changes, builders, builds, steps, and logs.
+ A number of query-arguments can be added to influence
+ the display.
+ /builders/BUILDERNAME: a page summarizing the builder. This includes
+ references to the Schedulers that feed it,
+ any builds currently in the queue, which
+ buildslaves are designated or attached, and a
+ summary of the build process it uses.
+ /builders/BUILDERNAME/builds/NUM: a page describing a single Build
+ /builders/BUILDERNAME/builds/NUM/steps/STEPNUM: describes a single step
+ /builders/BUILDERNAME/builds/NUM/steps/STEPNUM/logs/LOGNAME: a StatusLog
+ /changes/CHANGENUM: a page describing a single Change
+ /schedulers/SCHEDULERNAME: a page describing a Scheduler, including
+ a description of its behavior, a list of the
+ Builders it triggers, and list of the Changes
+ that are queued awaiting the tree-stable
+ timer, and controls to accelerate the timer.
+ /others...
+
+ All URLs for pages which are not defined here are used to look for files
+ in BASEDIR/public_html/ , which means that /robots.txt or /buildbot.css
+ can be placed in that directory. If an index file (index.html, index.htm,
+ or index, in that order) is present in public_html/, it will be used for
+ the root resource. If not, the default behavior is to put a redirection
+ to the /waterfall page.
+
+ All of the resources provided by this service use relative URLs to reach
+ each other. The only absolute links are the c['projectURL'] links at the
+ top and bottom of the page, and the buildbot home-page link at the
+ bottom.
+ """
+
+ def __init__(self, http_port=None, distrib_port=None,
+ allowForce=False, css="buildbot.css"):
+ """Run a web server that provides Buildbot status.
+
+ @param http_port: an int or strports specification that controls where
+ the web server should listen.
+ @param distrib_port: an int or strports specification or filename
+ that controls where a twisted.web.distrib socket
+ should listen. If distrib_port is a filename,
+ a unix-domain socket will be used.
+ @param allowForce: boolean, if True then the webserver will allow
+ visitors to trigger and cancel builds
+ @param css: a URL. If set, the header of each generated page will
+ include a link to add the given URL as a CSS stylesheet
+ for the page.
+ """
+
+ service.MultiService.__init__(self)
+ if type(http_port) is int:
+ http_port = "tcp:%d" % http_port
+ self.http_port = http_port
+ if distrib_port is not None:
+ if type(distrib_port) is int:
+ distrib_port = "tcp:%d" % distrib_port
+ if distrib_port[0] in "/~.": # pathnames
+ distrib_port = "unix:%s" % distrib_port
+ self.distrib_port = distrib_port
+ self.allowForce = allowForce
+ self.css = css
+
+ self.setupSite()
+
+ if self.http_port is not None:
+ s = strports.service(self.http_port, self.site)
+ s.setServiceParent(self)
+ if self.distrib_port is not None:
+ f = pb.PBServerFactory(distrib.ResourcePublisher(self.site))
+ s = strports.service(self.distrib_port, f)
+ s.setServiceParent(self)
+
+ def setupSite(self):
+ # this is responsible for setting self.root and self.site
+ self.root = static.File("public_html")
+ log.msg("WebStatus using (%s)" % self.root.path)
+ self.setupUsualPages(self.root)
+ # once we get enabled, we'll stash a reference to the main IStatus
+ # instance in site.status, so all of our childrens' render() methods
+ # can access it as request.site.status
+ self.site = server.Site(self.root)
+ self.site.buildbot_service = self
+ self.header = HEADER
+ self.footer = FOOTER
+ self.template_values = {}
+
+ def getStatus(self):
+ return self.parent.getStatus()
+ def getControl(self):
+ if self.allowForce:
+ return IControl(self.parent)
+ return None
+
+ def setupUsualPages(self, root):
+ #root.putChild("", IndexOrWaterfallRedirection())
+ root.putChild("waterfall", WaterfallStatusResource())
+ #root.putChild("builders", BuildersResource())
+ #root.putChild("changes", ChangesResource())
+ #root.putChild("schedulers", SchedulersResource())
+
+ root.putChild("one_line_per_build", OneLinePerBuild())
+
+ def putChild(self, name, child_resource):
+ self.root.putChild(name, child_resource)
+
+# resources can get access to the IStatus by calling
+# request.site.buildbot_service.getStatus()
+
+# this is the compatibility class for the old waterfall. It is exactly like a
+# regular WebStatus except that the root resource (e.g. http://buildbot.net/)
+# is a WaterfallStatusResource. In the normal WebStatus, the waterfall is at
+# e.g. http://builbot.net/waterfall, and the root resource either redirects
+# the browser to that or serves BASEDIR/public_html/index.html .
+class Waterfall(WebStatus):
+ def setupSite(self):
+ WebStatus.setupSite(self)
+ self.root.putChild("", WaterfallStatusResource())
+
Index: build.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/build.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- build.py 1 Aug 2007 22:08:11 -0000 1.1
+++ build.py 1 Aug 2007 22:08:26 -0000 1.2
@@ -1,4 +1,18 @@
+from zope.interface import implements
+from twisted.web.error import NoResource
+from twisted.web import html
+from twisted.web.util import Redirect, DeferredResource
+from twisted.internet import defer, reactor
+
+import urllib
+from twisted.python import components, log
+from buildbot.status import builder
+from buildbot.status.web.base import HtmlResource, Box, IBox, \
+ build_get_class, make_row
+
+from buildbot.status.web.tests import StatusResourceTestResults
+from buildbot.status.web.step import StatusResourceBuildStep
# $builder/builds/NN
class StatusResourceBuild(HtmlResource):
Index: builder.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/builder.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- builder.py 1 Aug 2007 22:08:11 -0000 1.1
+++ builder.py 1 Aug 2007 22:08:26 -0000 1.2
@@ -1,4 +1,20 @@
+from zope.interface import implements
+from twisted.web.error import NoResource
+from twisted.web import html, static
+from twisted.web.util import Redirect
+
+import re, time, urllib
+from twisted.python import components, log
+from buildbot import util, interfaces
+from buildbot.status import builder
+from buildbot.status.web.base import HtmlResource, Box, IBox, \
+ build_get_class, make_row, ICurrentBox, ITopBox
+from buildbot.process.base import BuildRequest
+from buildbot.status.web.build import StatusResourceBuild
+
+from buildbot.sourcestamp import SourceStamp
+
# $builder
class StatusResourceBuilder(HtmlResource):
Index: changes.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/changes.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- changes.py 1 Aug 2007 22:08:11 -0000 1.1
+++ changes.py 1 Aug 2007 22:08:26 -0000 1.2
@@ -1,4 +1,12 @@
+from zope.interface import implements
+from twisted.python import components
+from twisted.web.error import NoResource
+from twisted.web import html
+
+from buildbot.changes.changes import Change
+from buildbot.status.web.base import HtmlResource, StaticHTML, IBox, Box
+
# $changes/NN
class StatusResourceChanges(HtmlResource):
def __init__(self, status, changemaster):
@@ -32,4 +40,4 @@
url = "changes/%d" % self.original.number
text = '<a href="%s">%s</a>' % (url, html.escape(self.original.who))
return Box([text], color="white", class_="Change")
-components.registerAdapter(ChangeBox, changes.Change, IBox)
+components.registerAdapter(ChangeBox, Change, IBox)
Index: step.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/step.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- step.py 1 Aug 2007 22:08:11 -0000 1.1
+++ step.py 1 Aug 2007 22:08:26 -0000 1.2
@@ -1,4 +1,14 @@
+from zope.interface import implements
+from twisted.web.error import NoResource
+from twisted.web import html
+
+import urllib
+from twisted.python import components, log
+from buildbot import interfaces
+from buildbot.status import builder
+from buildbot.status.web.base import HtmlResource, Box, IBox, IHTMLLog, \
+ build_get_class
# $builder/builds/NN/stepname
class StatusResourceBuildStep(HtmlResource):
Index: tests.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/tests.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- tests.py 1 Aug 2007 22:08:11 -0000 1.1
+++ tests.py 1 Aug 2007 22:08:26 -0000 1.2
@@ -1,4 +1,9 @@
+from twisted.web.error import NoResource
+from twisted.web import html
+
+from buildbot.status.web.base import HtmlResource
+
# $builder/builds/NN/tests/TESTNAME
class StatusResourceTestResult(HtmlResource):
title = "Test Logs"
Index: waterfall.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/waterfall.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- waterfall.py 1 Aug 2007 22:08:21 -0000 1.6
+++ waterfall.py 1 Aug 2007 22:08:26 -0000 1.7
@@ -1,33 +1,17 @@
# -*- test-case-name: buildbot.test.test_web -*-
-from __future__ import generators
-
+from zope.interface import implements
from twisted.python import log, components
-import urllib, re
-
-from twisted.internet import defer, reactor
-from twisted.web.resource import Resource
-from twisted.web import static, html, server, distrib
-from twisted.web.error import NoResource
-from twisted.web.util import Redirect, DeferredResource
-from twisted.application import strports
-from twisted.spread import pb
-from zope.interface import Interface, implements
+import urllib
-import sys, string, types, time, os.path
+import time
from buildbot import interfaces, util
from buildbot import version
-from buildbot.sourcestamp import SourceStamp
-from buildbot.status import builder, base
-from buildbot.changes import changes
-from buildbot.process.base import BuildRequest
-
-from buildbot.status.web.changes import StatusResourceChanges
-from buildbot.status.web.builder import StatusResourceBuilder
-from buildbot.status.web.build import StatusResourceBuild
-from buildbot.status.web.step import StatusResourceBuildStep
+from buildbot.status import builder
+from buildbot.status.web.base import Box, HtmlResource, IBox, ICurrentBox, \
+ ITopBox, td
class EventBox(components.Adapter):
@@ -112,12 +96,9 @@
else:
return "BuildBot"
- def getStatus(self, request):
- return self.status
- def getControl(self, request):
- return self.control
def getChangemaster(self, request):
- return self.changemaster
+ # TODO: this wants to go away, access it through IStatus
+ return request.site.buildbot_service.parent.change_svc
def body(self, request):
"This method builds the main waterfall display."
More information about the Commits
mailing list