diff --git a/buildbot/status/web/base.py b/buildbot/status/web/base.py
index 022e16f4072..8b99fb9848c 100644
--- a/buildbot/status/web/base.py
+++ b/buildbot/status/web/base.py
@@ -59,33 +59,6 @@ def getAndCheckProperties(req):
return None
properties.setProperty(pname, pvalue, "Force Build Form")
return properties
-def td(text="", parms={}, **props):
- data = ""
- data += " "
- #if not props.has_key("border"):
- # props["border"] = 1
- props.update(parms)
- comment = props.get("comment", None)
- if comment:
- data += "" % comment
- data += "
"
- if not text:
- text = " "
- if isinstance(text, list):
- data += " ".join(text)
- else:
- data += text
- data += " | \n"
- return data
def build_get_class(b):
"""
@@ -168,8 +141,9 @@ def td(self, **props):
text = self.text
if not text and self.show_idle:
text = ["[idle]"]
- return td(text, props, class_=self.class_)
-
+ props['class'] = self.class_
+ props['text'] = text;
+ return props
class HtmlResource(resource.Resource):
# this is a cheap sort of template thingy
diff --git a/buildbot/status/web/grid.py b/buildbot/status/web/grid.py
index 4e04fa358cf..8add7af14ab 100644
--- a/buildbot/status/web/grid.py
+++ b/buildbot/status/web/grid.py
@@ -8,9 +8,7 @@
from buildbot import util
from buildbot import version
from buildbot.status.web.base import HtmlResource
-#from buildbot.status.web.base import Box, HtmlResource, IBox, ICurrentBox, \
-# ITopBox, td, build_get_class, path_to_build, path_to_step, map_branches
-from buildbot.status.web.base import build_get_class
+from buildbot.status.web.base import build_get_class, path_to_builder, path_to_build
# set grid_css to the full pathname of the css file
if hasattr(sys, "frozen"):
@@ -69,11 +67,10 @@ def build_cxt(self, request, build):
text = [ 'building' ]
name = build.getBuilder().getName()
- number = build.getNumber()
cxt = {}
cxt['name'] = name
- cxt['url'] = "builders/%s/builds/%d" % (name, number)
+ cxt['url'] = path_to_build(request, build)
cxt['text'] = text
cxt['class'] = build_get_class(build)
return cxt
@@ -99,7 +96,7 @@ def builder_cxt(self, request, builder):
# instead. The only times it should show up in "current activity" is
# when the builder is otherwise idle.
- cxt = { 'url': urllib.quote(builder.getName(), safe=''),
+ cxt = { 'url': path_to_builder(request, builder),
'name': builder.getName(),
'state': state,
'n_pending': len(builder.getPendingBuilds()) }
diff --git a/buildbot/status/web/templates/box_macros.html b/buildbot/status/web/templates/box_macros.html
new file mode 100644
index 00000000000..4c3ef54e798
--- /dev/null
+++ b/buildbot/status/web/templates/box_macros.html
@@ -0,0 +1,12 @@
+{% macro box(text=[], comment=None) -%}
+
+{%- if comment -%}{%- endif -%}
+
+ {{- text|join(" ") -}}
+ |
+{% endmacro %}
diff --git a/buildbot/status/web/templates/buildstatus.html b/buildbot/status/web/templates/buildstatus.html
index cc49135e1b9..c917e25f3d3 100644
--- a/buildbot/status/web/templates/buildstatus.html
+++ b/buildbot/status/web/templates/buildstatus.html
@@ -1,11 +1,13 @@
{% extends "layout.html" %}
+{% from "box_macros.html" import box %}
+
{% block content %}
{% for r in rows %}
- {{ r }}
+ {{ box(r) }}
{% endfor %}
- {{ build }}
+ {{ box(build) }}
{% endblock %}
diff --git a/buildbot/status/web/templates/oneboxperbuilder.html b/buildbot/status/web/templates/oneboxperbuilder.html
index 69763bb92cc..9238aad8971 100644
--- a/buildbot/status/web/templates/oneboxperbuilder.html
+++ b/buildbot/status/web/templates/oneboxperbuilder.html
@@ -1,4 +1,5 @@
{% import 'forms.html' as forms %}
+{% from "box_macros.html" import box %}
Latest builds: {{ branches|join(', ')|e }}
@@ -14,7 +15,7 @@ Latest builds: {{ branches|join(', ')|e }}
{% else %}
no build |
{% endif %}
- {{ b.current_box }}
+ {{ box(**b.current_box) }}
{% endfor %}
diff --git a/buildbot/status/web/templates/waterfall.html b/buildbot/status/web/templates/waterfall.html
index 96f5c77abe7..ecb6956e95d 100644
--- a/buildbot/status/web/templates/waterfall.html
+++ b/buildbot/status/web/templates/waterfall.html
@@ -1,4 +1,6 @@
{% extends "layout.html" %}
+{% from "box_macros.html" import box %}
+
{% block head %}
{{ super() }}
@@ -44,7 +46,16 @@
{% endfor %}
-{{ waterfall }}
+{# waterfall contents goes here #}
+{% for i in range(gridlen) -%}
+
+ {% for strip in grid -%}
+ {%- if strip[i] -%}{{ box(**strip[i]) }}
+ {%- elif no_bubble -%}{{ box() }}
+ {%- endif -%}
+ {%- endfor -%}
+
+{% endfor %}
diff --git a/buildbot/status/web/waterfall.py b/buildbot/status/web/waterfall.py
index 1e4ac1e9161..85a22586f40 100644
--- a/buildbot/status/web/waterfall.py
+++ b/buildbot/status/web/waterfall.py
@@ -13,7 +13,7 @@
from buildbot.status import builder
from buildbot.status.web.base import Box, HtmlResource, IBox, ICurrentBox, \
- ITopBox, td, build_get_class, path_to_build, path_to_step, map_branches
+ ITopBox, build_get_class, path_to_build, path_to_step, map_branches
@@ -268,7 +268,7 @@ def content(self, request, cxt):
times.insert(0, (current_reload_time, current_reload_time) )
cxt['times'] = times
- cxt['current_reload_time'] = current_reload_time
+ cxt['current_reload_time'] = current_reload_time
template = request.site.buildbot_service.templates.get_template("waterfallhelp.html")
return template.render(**cxt)
@@ -388,8 +388,8 @@ def content(self, request, ctx):
'status_class': current_box.class_,
})
- ctx['waterfall'] = self.phase2(request, changeNames + builderNames, timestamps, eventGrid,
- sourceEvents)
+ ctx.update(self.phase2(request, changeNames + builderNames, timestamps, eventGrid,
+ sourceEvents))
def with_args(req, remove_args=[], new_args=[], new_path=None):
# sigh, nevow makes this sort of manipulation easier
@@ -579,9 +579,10 @@ def get_event_from(g):
def phase2(self, request, sourceNames, timestamps, eventGrid,
sourceEvents):
- data = ""
+
if not timestamps:
- return data
+ return dict(grid=[], gridlen=0)
+
# first pass: figure out the height of the chunks, populate grid
grid = []
for i in range(1+len(sourceNames)):
@@ -692,21 +693,12 @@ def phase2(self, request, sourceNames, timestamps, eventGrid,
strip[-i+1] = None
else:
strip[-i].parms['rowspan'] = 1
- # third pass: render the HTML table
+
+ # convert to dicts
for i in range(gridlen):
- data += " \n";
for strip in grid:
- b = strip[i]
- if b:
- # convert data to a unicode string, whacking any non-ASCII characters it might contain
- s = b.td()
- if isinstance(s, unicode):
- s = s.encode("utf-8", "replace")
- data += s
- else:
- if noBubble:
- data += td([])
- # Nones are left empty, rowspan should make it all fit
- data += "
\n"
- return data
+ if strip[i]:
+ strip[i] = strip[i].td()
+
+ return dict(grid=grid, gridlen=gridlen, no_bubble=noBubble)
diff --git a/buildbot/test/test_web.py b/buildbot/test/test_web.py
index 486d09b987c..fc9b8eb4d76 100644
--- a/buildbot/test/test_web.py
+++ b/buildbot/test/test_web.py
@@ -226,17 +226,17 @@ def test_waterfall(self):
config1 = base_config + """
from buildbot.changes import mail
c['change_source'] = mail.SyncmailMaildirSource('my-maildir')
-c['status'] = [html.Waterfall(http_port=0, robots_txt=%s)]
-""" % repr(self.robots_txt)
+c['status'] = [html.WebStatus(http_port=0)]
+"""
self.master = m = ConfiguredMaster("test_web4", config1)
m.startService()
- port = self.find_waterfall(m).getPortnum()
+ port = self.find_webstatus(m).getPortnum()
self.port = port
# insert an event
m.change_svc.addChange(Change("user", ["foo.c"], "comments"))
- d = client.getPage("http://localhost:%d/" % port)
+ d = client.getPage("http://localhost:%d/waterfall" % port)
def _check1(page):
self.failUnless(page)
@@ -245,8 +245,7 @@ def _check1(page):
TZ = time.tzname[time.localtime()[-1]]
self.failUnlessIn("(%s)" % TZ, page)
- # phase=0 is really for debugging the waterfall layout
- return client.getPage("http://localhost:%d/?phase=0" % self.port)
+ return client.getPage("http://localhost:%d/waterfall" % self.port)
d.addCallback(_check1)
def _check2(page):
@@ -260,15 +259,8 @@ def _check3(changes):
self.failUnlessIn("Syncmail mailing list in maildir " +
"my-maildir", changes)
- return client.getPage("http://localhost:%d/robots.txt" % self.port)
d.addCallback(_check3)
- def _check4(robotstxt):
- # needed on win32
- robotstxt = robotstxt.replace('\r\n', '\n')
- self.failUnless(robotstxt == self.robots_txt_contents)
- d.addCallback(_check4)
-
return d
test_waterfall.timeout = 10
@@ -298,11 +290,11 @@ def childLink(self, name):
return name
req = FakeRequest()
box = waterfall.IBox(s).getBox(req)
- td = box.td()
+ text = "\n".join(box.td()['text'])
e1 = '[coverage]'
- self.failUnlessSubstring(e1, td)
+ self.failUnlessSubstring(e1, text)
e2 = '[icon]'
- self.failUnlessSubstring(e2, td)
+ self.failUnlessSubstring(e2, text)