WebStatus: remove css= argument, all pages use root/buildbot.css
[buildbot.git] / buildbot / status / web / base.py
blob0d54c5417f582115892e4735132d0bfae34a1c0e
2 from zope.interface import Interface
3 from twisted.web import html, resource
4 from buildbot.status import builder
8 class ITopBox(Interface):
9 """I represent a box in the top row of the waterfall display: the one
10 which shows the status of the last build for each builder."""
11 pass
13 class ICurrentBox(Interface):
14 """I represent the 'current activity' box, just above the builder name."""
15 pass
17 class IBox(Interface):
18 """I represent a box in the waterfall display."""
19 pass
21 class IHTMLLog(Interface):
22 pass
24 ROW_TEMPLATE = '''
25 <div class="row">
26 <span class="label">%(label)s</span>
27 <span class="field">%(field)s</span>
28 </div>'''
30 def make_row(label, field):
31 """Create a name/value row for the HTML.
33 `label` is plain text; it will be HTML-encoded.
35 `field` is a bit of HTML structure; it will not be encoded in
36 any way.
37 """
38 label = html.escape(label)
39 return ROW_TEMPLATE % {"label": label, "field": field}
41 colormap = {
42 'green': '#72ff75',
44 def td(text="", parms={}, **props):
45 data = ""
46 data += " "
47 #if not props.has_key("border"):
48 # props["border"] = 1
49 props.update(parms)
50 if props.has_key("bgcolor"):
51 props["bgcolor"] = colormap.get(props["bgcolor"], props["bgcolor"])
52 comment = props.get("comment", None)
53 if comment:
54 data += "<!-- %s -->" % comment
55 data += "<td"
56 class_ = props.get('class_', None)
57 if class_:
58 props["class"] = class_
59 for prop in ("align", "bgcolor", "colspan", "rowspan", "border",
60 "valign", "halign", "class"):
61 p = props.get(prop, None)
62 if p != None:
63 data += " %s=\"%s\"" % (prop, p)
64 data += ">"
65 if not text:
66 text = "&nbsp;"
67 if isinstance(text, list):
68 data += "<br />".join(text)
69 else:
70 data += text
71 data += "</td>\n"
72 return data
74 def build_get_class(b):
75 """
76 Return the class to use for a finished build or buildstep,
77 based on the result.
78 """
79 # FIXME: this getResults duplicity might need to be fixed
80 result = b.getResults()
81 #print "THOMAS: result for b %r: %r" % (b, result)
82 if isinstance(b, builder.BuildStatus):
83 result = b.getResults()
84 elif isinstance(b, builder.BuildStepStatus):
85 result = b.getResults()[0]
86 # after forcing a build, b.getResults() returns ((None, []), []), ugh
87 if isinstance(result, tuple):
88 result = result[0]
89 else:
90 raise TypeError, "%r is not a BuildStatus or BuildStepStatus" % b
92 if result == None:
93 # FIXME: this happens when a buildstep is running ?
94 return "running"
95 return builder.Results[result]
97 class Box:
98 # a Box wraps an Event. The Box has HTML <td> parameters that Events
99 # lack, and it has a base URL to which each File's name is relative.
100 # Events don't know about HTML.
101 spacer = False
102 def __init__(self, text=[], color=None, class_=None, urlbase=None,
103 **parms):
104 self.text = text
105 self.color = color
106 self.class_ = class_
107 self.urlbase = urlbase
108 self.show_idle = 0
109 if parms.has_key('show_idle'):
110 del parms['show_idle']
111 self.show_idle = 1
113 self.parms = parms
114 # parms is a dict of HTML parameters for the <td> element that will
115 # represent this Event in the waterfall display.
117 def td(self, **props):
118 props.update(self.parms)
119 text = self.text
120 if not text and self.show_idle:
121 text = ["[idle]"]
122 return td(text, props, bgcolor=self.color, class_=self.class_)
125 class HtmlResource(resource.Resource):
126 # this is a cheap sort of template thingy
127 contentType = "text/html; charset=UTF-8"
128 title = "Dummy"
130 def render(self, request):
131 data = self.content(request)
132 if isinstance(data, unicode):
133 data = data.encode("utf-8")
134 request.setHeader("content-type", self.contentType)
135 if request.method == "HEAD":
136 request.setHeader("content-length", len(data))
137 return ''
138 return data
140 def getStatus(self, request):
141 return request.site.buildbot_service.getStatus()
142 def getControl(self, request):
143 return request.site.buildbot_service.getControl()
145 def getChangemaster(self, request):
146 return request.site.buildbot_service.parent.change_svc
148 def path_to_root(self, request):
149 return "../" * len(request.prepath)
151 def getTitle(self, request):
152 return self.title
154 def fillTemplate(self, template, request):
155 s = request.site.buildbot_service
156 values = s.template_values.copy()
157 values['root'] = self.path_to_root(request)
158 # e.g. to reference the top-level 'buildbot.css' page, use
159 # "%(root)sbuildbot.css"
160 values['title'] = self.getTitle(request)
161 return template % values
163 def content(self, request):
164 s = request.site.buildbot_service
165 data = ""
166 data += self.fillTemplate(s.header, request)
167 data += "<head>\n"
168 for he in s.head_elements:
169 data += " " + self.fillTemplate(he, request) + "\n"
170 data += "</head>\n\n"
172 data += '<body %s>\n' % " ".join(['%s="%s"' % (k,v)
173 for (k,v) in s.body_attrs.items()])
174 data += self.body(request)
175 data += "</body>\n"
176 data += self.fillTemplate(s.footer, request)
177 return data
179 def body(self, request):
180 return "Dummy\n"
182 class StaticHTML(HtmlResource):
183 def __init__(self, body, title):
184 HtmlResource.__init__(self)
185 self.bodyHTML = body
186 self.title = title
187 def body(self, request):
188 return self.bodyHTML