[Buildbot-commits] buildbot/buildbot/status/web base.py, 1.12, 1.13 baseweb.py, 1.21, 1.22 build.py, 1.11, 1.12 builder.py, 1.9, 1.10 changes.py, 1.3, 1.4 logs.py, 1.5, 1.6 slaves.py, 1.2, 1.3 step.py, 1.5, 1.6 tests.py, 1.3, 1.4 waterfall.py, 1.20, 1.21
Brian Warner
warner at users.sourceforge.net
Fri Sep 28 09:33:33 UTC 2007
Update of /cvsroot/buildbot/buildbot/buildbot/status/web
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv11817/buildbot/status/web
Modified Files:
base.py baseweb.py build.py builder.py changes.py logs.py
slaves.py step.py tests.py waterfall.py
Log Message:
[project @ web: big cleanup of URL generation, to use relative links everywhere]
Original author: warner at lothar.com
Date: 2007-09-28 09:08:11+00:00
Index: base.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/base.py,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- base.py 27 Sep 2007 22:51:10 -0000 1.12
+++ base.py 28 Sep 2007 09:33:31 -0000 1.13
@@ -1,5 +1,5 @@
-import urlparse
+import urlparse, urllib
from zope.interface import Interface
from twisted.web import html, resource
from buildbot.status import builder
@@ -9,15 +9,22 @@
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."""
- pass
+ def getBox(self, request):
+ """Return a Box instance, which can produce a <td> cell.
+ """
class ICurrentBox(Interface):
"""I represent the 'current activity' box, just above the builder name."""
- pass
+ def getBox(self, status):
+ """Return a Box instance, which can produce a <td> cell.
+ """
class IBox(Interface):
"""I represent a box in the waterfall display."""
- pass
+ def getBox(self, request):
+ """Return a Box instance, which wraps an Event and can produce a <td>
+ cell.
+ """
class IHTMLLog(Interface):
pass
@@ -102,6 +109,31 @@
return "running"
return builder.Results[result]
+def path_to_root(request):
+ # /waterfall : ['waterfall'] -> ''
+ # /somewhere/lower : ['somewhere', 'lower'] -> '../'
+ # /somewhere/indexy/ : ['somewhere', 'indexy', ''] -> '../../'
+ # / : [] -> ''
+ if request.prepath:
+ segs = len(request.prepath) - 1
+ else:
+ segs = 0
+ root = "../" * segs
+ return root
+
+def path_to_builder(request, builderstatus):
+ return (path_to_root(request) +
+ "builders/" +
+ urllib.quote(builderstatus.getName(), safe=''))
+
+def path_to_build(request, buildstatus):
+ return (path_to_builder(request, buildstatus.getBuilder()) +
+ "/builds/%d" % buildstatus.getNumber())
+
+def path_to_step(request, stepstatus):
+ return (path_to_build(request, stepstatus.getBuild()) +
+ "/steps/%s" % urllib.quote(stepstatus.getName(), safe=''))
+
class Box:
# a Box wraps an Event. The Box has HTML <td> parameters that Events
# lack, and it has a base URL to which each File's name is relative.
@@ -142,10 +174,23 @@
return resource.Resource.getChild(self, path, request)
def render(self, request):
- if self.addSlash and request.prepath[-1] != '':
+
+ # Our pages no longer require that their URL end in a slash. Instead,
+ # they all use request.childLink() or some equivalent which takes the
+ # last path component into account. This clause is left here for
+ # historical and educational purposes.
+ if False and self.addSlash and request.prepath[-1] != '':
# this is intended to behave like request.URLPath().child('')
# but we need a relative URL, since we might be living behind a
# reverse proxy
+ #
+ # note that the Location: header (as used in redirects) are
+ # required to have absolute URIs, and my attempt to handle
+ # reverse-proxies gracefully violates rfc2616. This frequently
+ # works, but single-component paths sometimes break. The best
+ # strategy is to avoid these redirects whenever possible by using
+ # HREFs with trailing slashes, and only use the redirects for
+ # manually entered URLs.
url = request.prePathURL()
scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
new_url = request.prepath[-1] + "/"
@@ -172,16 +217,7 @@
return request.site.buildbot_service.parent.change_svc
def path_to_root(self, request):
- # /waterfall : ['waterfall'] -> ''
- # /somewhere/lower : ['somewhere', 'lower'] -> '../'
- # /somewhere/indexy/ : ['somewhere', 'indexy', ''] -> '../../'
- # / : [] -> ''
- if request.prepath:
- segs = len(request.prepath) - 1
- else:
- segs = 0
- root = "../" * segs
- return root
+ return path_to_root(request)
def getTitle(self, request):
return self.title
Index: baseweb.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/baseweb.py,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- baseweb.py 26 Sep 2007 09:57:30 -0000 1.21
+++ baseweb.py 28 Sep 2007 09:33:31 -0000 1.22
@@ -292,7 +292,14 @@
Builders it triggers, and list of the Changes
that are queued awaiting the tree-stable
timer, and controls to accelerate the timer.
- /others...
+ /buildslaves : list all BuildSlaves
+ /buildslaves/SLAVENAME : describe a single BuildSlave
+ /one_line_per_build : summarize the last few builds, one line each
+ /one_line_per_build/BUILDERNAME : same, but only for a single builder
+ /one_box_per_builder : show the latest build and current activity
+ /about : describe this buildmaster (Buildbot and support library versions)
+ /xmlrpc : (not yet implemented) an XMLRPC server with build status
+
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
@@ -411,7 +418,7 @@
def setupUsualPages(self):
#self.putChild("", IndexOrWaterfallRedirection())
self.putChild("waterfall", WaterfallStatusResource())
- self.putChild("builders", BuildersResource())
+ self.putChild("builders", BuildersResource()) # has builds/steps/logs
self.putChild("changes", ChangesResource())
self.putChild("buildslaves", BuildSlavesResource())
#self.putChild("schedulers", SchedulersResource())
Index: build.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/build.py,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- build.py 27 Sep 2007 22:51:23 -0000 1.11
+++ build.py 28 Sep 2007 09:33:31 -0000 1.12
@@ -5,12 +5,13 @@
import urllib, time
from twisted.python import log
-from buildbot.status.web.base import HtmlResource, make_row, css_classes
+from buildbot.status.web.base import HtmlResource, make_row, css_classes, \
+ path_to_builder
from buildbot.status.web.tests import TestsResource
from buildbot.status.web.step import StepsResource
-# builders/$builder/builds/$buildnum
+# /builders/$builder/builds/$buildnum
class StatusResourceBuild(HtmlResource):
addSlash = True
@@ -29,12 +30,13 @@
b = self.build_status
status = self.getStatus(req)
projectName = status.getProjectName()
- data = ('<div class="title"><a href="../../../..">%s</a></div>\n'
- % projectName)
+ data = ('<div class="title"><a href="%s">%s</a></div>\n'
+ % (self.path_to_root(req), projectName))
# the color in the following line gives python-mode trouble
builder_name = b.getBuilder().getName()
- data += ("<h1><a href=\"../..\">Builder %s</a>: Build #%d</h1>\n"
- % (builder_name, b.getNumber()))
+ data += ("<h1><a href=\"%s\">Builder %s</a>: Build #%d</h1>\n"
+ % (path_to_builder(req, b.getBuilder()),
+ builder_name, b.getNumber()))
if not b.isFinished():
data += "<h2>Build In Progress</h2>"
@@ -99,6 +101,12 @@
data += "<h2>Reason:</h2>\n%s\n" % html.escape(b.getReason())
data += "<h2>Steps and Logfiles:</h2>\n"
+ # TODO:
+# urls = self.original.getURLs()
+# ex_url_class = "BuildStep external"
+# for name, target in urls.items():
+# text.append('[<a href="%s" class="%s">%s</a>]' %
+# (target, ex_url_class, html.escape(name)))
if b.getLogs():
data += "<ol>\n"
for s in b.getSteps():
@@ -232,6 +240,7 @@
return HtmlResource.getChild(self, path, req)
+# /builders/$builder/builds
class BuildsResource(HtmlResource):
addSlash = True
Index: builder.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/builder.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- builder.py 27 Sep 2007 22:51:23 -0000 1.9
+++ builder.py 28 Sep 2007 09:33:31 -0000 1.10
@@ -12,7 +12,7 @@
from buildbot.status.web.build import BuildsResource
-# builders/$builder
+# /builders/$builder
class StatusResourceBuilder(HtmlResource):
addSlash = True
@@ -26,7 +26,7 @@
def build_line(self, build, req):
buildnum = build.getNumber()
- buildurl = "builds/%d" % buildnum
+ buildurl = req.childLink("builds/%d" % buildnum)
data = '<a href="%s">#%d</a> ' % (buildurl, buildnum)
when = build.getETA()
if when is not None:
@@ -38,7 +38,7 @@
def build_finished_line(self, build, req):
buildnum = build.getNumber()
- buildurl = "builds/%d" % buildnum
+ buildurl = req.childLink("builds/%d" % buildnum)
results = build.getResults()
text = " ".join(build.getText())
data = '<a href="%s">#%d</a> ' % (buildurl, buildnum)
@@ -55,7 +55,7 @@
projectName = status.getProjectName()
- data = '<a href="../..">%s</a>\n' % projectName
+ data = '<a href="%s">%s</a>\n' % (self.path_to_root(req), projectName)
data += "<h1>Builder: %s</h1>\n" % html.escape(b.getName())
@@ -215,9 +215,28 @@
return HtmlResource.getChild(self, path, req)
+# /builders
class BuildersResource(HtmlResource):
+ title = "Builders"
addSlash = True
+ def body(self, req):
+ s = self.getStatus(req)
+ data = ""
+ data += "<h1>Builders</h1>\n"
+
+ # TODO: this is really basic. It should be expanded to include a
+ # brief one-line summary of the builder (perhaps with whatever the
+ # builder is currently doing)
+ data += "<ol>\n"
+ for bname in s.getBuilderNames():
+ data += (' <li><a href="%s">%s</a></li>\n' %
+ (req.childLink(urllib.quote(bname, safe='')),
+ urllib.quote(bname, safe='')))
+ data += "</ol>\n"
+
+ return data
+
def getChild(self, path, req):
s = self.getStatus(req)
if path in s.getBuilderNames():
Index: changes.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/changes.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- changes.py 1 Aug 2007 22:08:32 -0000 1.3
+++ changes.py 28 Sep 2007 09:33:31 -0000 1.4
@@ -6,7 +6,7 @@
from buildbot.changes.changes import Change
from buildbot.status.web.base import HtmlResource, StaticHTML, IBox, Box
-# $changes/NN
+# /changes/NN
class ChangesResource(HtmlResource):
def body(self, req):
@@ -33,8 +33,8 @@
class ChangeBox(components.Adapter):
implements(IBox)
- def getBox(self):
- url = "changes/%d" % self.original.number
+ def getBox(self, req):
+ url = req.childLink("../changes/%d" % self.original.number)
text = self.original.get_HTML_box(url)
return Box([text], color="white", class_="Change")
components.registerAdapter(ChangeBox, Change, IBox)
Index: logs.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/logs.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- logs.py 1 Aug 2007 23:30:14 -0000 1.5
+++ logs.py 28 Sep 2007 09:33:31 -0000 1.6
@@ -50,6 +50,8 @@
def finish(self):
self.textlog.finished()
+
+# /builders/$builder/builds/$buildnum/steps/$stepname/logs/$logname
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.
Index: slaves.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/slaves.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- slaves.py 25 Sep 2007 22:50:36 -0000 1.2
+++ slaves.py 28 Sep 2007 09:33:31 -0000 1.3
@@ -2,11 +2,11 @@
import time
from buildbot.status.web.base import HtmlResource, abbreviate_age
-# buildslaves/$slavename
+# /buildslaves/$slavename
class OneBuildSlaveResource(HtmlResource):
- pass
+ pass # TODO
-# buildslaves/
+# /buildslaves/
class BuildSlavesResource(HtmlResource):
title = "BuildSlaves"
addSlash = True
@@ -30,10 +30,12 @@
slave = s.getSlave(name)
data += " <li>%s:\n" % name
data += " <ul>\n"
- builder_links = ['<a href="../builders/%s">%s</a>' % (bname, bname)
+ builder_links = ['<a href="%s">%s</a>'
+ % (req.childLink("../builders/%s" % bname),bname)
for bname in used_by_builder.get(name, [])]
if builder_links:
- data += " <li>Used by: %s</li>\n" % ", ".join(builder_links)
+ data += (" <li>Used by Builders: %s</li>\n" %
+ ", ".join(builder_links))
else:
data += " <li>Not used by any Builders</li>\n"
if slave.isConnected():
Index: step.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/step.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- step.py 1 Aug 2007 23:30:14 -0000 1.5
+++ step.py 28 Sep 2007 09:33:31 -0000 1.6
@@ -2,10 +2,11 @@
from twisted.web import html
import urllib
-from buildbot.status.web.base import HtmlResource
+from buildbot.status.web.base import HtmlResource, path_to_builder, \
+ path_to_build
from buildbot.status.web.logs import LogsResource
-# builders/$builder/builds/$buildnum/steps/$stepname
+# /builders/$builder/builds/$buildnum/steps/$stepname
class StatusResourceBuildStep(HtmlResource):
title = "Build Step"
addSlash = True
@@ -21,9 +22,9 @@
builder_name = b.getBuilder().getName()
build_num = b.getNumber()
data = ""
- data += ("<h1>BuildStep <a href=\"../../../../%s\">%s</a>:" %
- (urllib.quote(builder_name), builder_name))
- data += "<a href=\"../../%d\">#%d</a>" % (build_num, build_num)
+ data += ('<h1>BuildStep <a href="%s">%s</a>:' %
+ (path_to_builder(req, b.getBuilder()), builder_name))
+ data += '<a href="%s">#%d</a>' % (path_to_build(req, b), build_num)
data += ":%s</h1>\n" % s.getName()
if s.isFinished():
@@ -69,6 +70,7 @@
+# /builders/$builder/builds/$buildnum/steps
class StepsResource(HtmlResource):
addSlash = True
Index: tests.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/tests.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- tests.py 1 Aug 2007 22:08:32 -0000 1.3
+++ tests.py 28 Sep 2007 09:33:31 -0000 1.4
@@ -4,7 +4,7 @@
from buildbot.status.web.base import HtmlResource
-# $builder/builds/NN/tests/TESTNAME
+# /builders/$builder/builds/$buildnum/tests/$testname
class TestResult(HtmlResource):
title = "Test Logs"
@@ -26,7 +26,7 @@
return data
-# $builder/builds/NN/tests
+# /builders/$builder/builds/$buildnum/tests
class TestsResource(HtmlResource):
title = "Test Results"
Index: waterfall.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/waterfall.py,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- waterfall.py 25 Sep 2007 23:04:29 -0000 1.20
+++ waterfall.py 28 Sep 2007 09:33:31 -0000 1.21
@@ -12,7 +12,7 @@
from buildbot.status import builder
from buildbot.status.web.base import Box, HtmlResource, IBox, ICurrentBox, \
- ITopBox, td, build_get_class
+ ITopBox, td, build_get_class, path_to_build, path_to_step
@@ -97,14 +97,14 @@
# showing the results of the most recent build
implements(IBox)
- def getBox(self):
+ def getBox(self, req):
assert interfaces.IBuilderStatus(self.original)
b = self.original.getLastFinishedBuild()
if not b:
return Box(["none"], "white", class_="LastBuild")
name = b.getBuilder().getName()
number = b.getNumber()
- url = "%s/builds/%d" % (name, number)
+ url = path_to_build(req, b)
text = b.getText()
# TODO: add logs?
# TODO: add link to the per-build page at 'url'
@@ -117,11 +117,10 @@
# this provides the yellow "starting line" box for each build
implements(IBox)
- def getBox(self):
+ def getBox(self, req):
b = self.original
- name = b.getBuilder().getName()
number = b.getNumber()
- url = "builders/%s/builds/%d" % (urllib.quote(name, safe=''), number)
+ url = path_to_build(req, b)
reason = b.getReason()
text = ('<a title="Reason: %s" href="%s">Build %d</a>'
% (html.escape(reason), url, number))
@@ -139,12 +138,8 @@
class StepBox(components.Adapter):
implements(IBox)
- def getBox(self):
- b = self.original.getBuild()
- urlbase = "builders/%s/builds/%d/steps/%s" % (
- urllib.quote(b.getBuilder().getName(), safe=''),
- b.getNumber(),
- urllib.quote(self.original.getName(), safe=''))
+ def getBox(self, req):
+ urlbase = path_to_step(req, self.original)
text = self.original.getText()
if text is None:
log.msg("getText() gave None", urlbase)
@@ -172,7 +167,7 @@
class EventBox(components.Adapter):
implements(IBox)
- def getBox(self):
+ def getBox(self, req):
text = self.original.getText()
color = self.original.getColor()
class_ = "Event"
@@ -199,7 +194,7 @@
class SpacerBox(components.Adapter):
implements(IBox)
- def getBox(self):
+ def getBox(self, req):
#b = Box(["spacer"], "white")
b = Box([])
b.spacer = True
@@ -483,14 +478,14 @@
if projectName and projectURL:
# TODO: this is going to look really ugly
- topleft = "<a href=\"%s\">%s</a><br />last build" % \
+ topleft = '<a href="%s">%s</a><br />last build' % \
(projectURL, projectName)
else:
topleft = "last build"
data += ' <tr class="LastBuild">\n'
data += td(topleft, align="right", colspan=2, class_="Project")
for b in builders:
- box = ITopBox(b).getBox()
+ box = ITopBox(b).getBox(request)
data += box.td(align="center")
data += " </tr>\n"
@@ -504,14 +499,13 @@
data += " <tr>\n"
TZ = time.tzname[time.daylight]
data += td("time (%s)" % TZ, align="center", class_="Time")
- name = changeNames[0]
- data += td(
- "<a href=\"%s\">%s</a>" % (urllib.quote(name, safe=''), name),
- align="center", class_="Change")
+ data += td('<a href="%s">changes</a>' % request.childLink("../changes"),
+ align="center", class_="Change")
for name in builderNames:
safename = urllib.quote(name, safe='')
- data += td( "<a href=\"builders/%s\">%s</a>" % (safename, name),
- align="center", class_="Builder")
+ data += td('<a href="%s">%s</a>' %
+ (request.childLink("../builders/%s" % safename), name),
+ align="center", class_="Builder")
data += " </tr>\n"
if phase == 1:
@@ -572,11 +566,11 @@
bburl = "http://buildbot.net/?bb-ver=%s" % urllib.quote(version)
- data += "<a href=\"%s\">Buildbot-%s</a> " % (bburl, version)
+ data += '<a href="%s">Buildbot-%s</a> ' % (bburl, version)
if projectName:
data += "working for the "
if projectURL:
- data += "<a href=\"%s\">%s</a> project." % (projectURL,
+ data += '<a href="%s">%s</a> project.' % (projectURL,
projectName)
else:
data += "%s project." % projectName
@@ -592,8 +586,7 @@
# build the waterfall display
data = ""
data += "<h2>Basic display</h2>\n"
- data += "<p>See <a href=\"%s\">here</a>" % \
- urllib.quote(request.childLink("waterfall"))
+ data += '<p>See <a href="%s">here</a>' % request.childLink("../waterfall")
data += " for the waterfall display</p>\n"
data += '<table border="0" cellspacing="0">\n'
@@ -618,9 +611,9 @@
data += td("Time", align="center")
data += td("Changes", align="center")
for name in names:
- data += td(
- "<a href=\"%s\">%s</a>" % (urllib.quote(request.childLink(name)), name),
- align="center")
+ data += td('<a href="%s">%s</a>' %
+ (request.childLink("../" + urllib.quote(name)), name),
+ align="center")
data += " </tr>\n"
# all further rows involve timestamps, commit events, and build events
@@ -834,7 +827,7 @@
data += td("")
else:
e = block[i-offset]
- box = IBox(e).getBox()
+ box = IBox(e).getBox(request)
box.parms["show_idle"] = 1
data += box.td(valign="top", align="center")
data += " </tr>\n"
@@ -894,7 +887,7 @@
grid[c+1].append(None)
for i in range(len(block)):
# so the events are bottom-justified
- b = IBox(block[i]).getBox()
+ b = IBox(block[i]).getBox(request)
b.parms['valign'] = "top"
b.parms['align'] = "center"
grid[c+1].append(b)
@@ -906,7 +899,7 @@
assert(len(strip) == gridlen)
if strip[-1] == None:
if sourceEvents[i-1]:
- filler = IBox(sourceEvents[i-1]).getBox()
+ filler = IBox(sourceEvents[i-1]).getBox(request)
else:
# this can happen if you delete part of the build history
filler = Box(text=["?"], align="center")
More information about the Commits
mailing list