Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(686)

Side by Side Diff: third_party/buildbot_7_12/buildbot/status/web/builder.py

Issue 12207158: Bye bye buildbot 0.7.12. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1
2 from twisted.web.error import NoResource
3 from twisted.web import html, static
4 from twisted.web.util import Redirect
5
6 import re, urllib, time
7 from twisted.python import log
8 from buildbot import interfaces
9 from buildbot.status.web.base import HtmlResource, make_row, \
10 make_force_build_form, OneLineMixin, path_to_build, path_to_slave, \
11 path_to_builder, path_to_change, getAndCheckProperties
12 from buildbot.process.base import BuildRequest
13 from buildbot.process.properties import Properties
14 from buildbot.sourcestamp import SourceStamp
15
16 from buildbot.status.web.build import BuildsResource, StatusResourceBuild
17 from buildbot import util
18
19 # /builders/$builder
20 class StatusResourceBuilder(HtmlResource, OneLineMixin):
21 addSlash = True
22
23 def __init__(self, builder_status, builder_control):
24 HtmlResource.__init__(self)
25 self.builder_status = builder_status
26 self.builder_control = builder_control
27
28 def getTitle(self, request):
29 return "Buildbot: %s" % html.escape(self.builder_status.getName())
30
31 def build_line(self, build, req):
32 buildnum = build.getNumber()
33 buildurl = path_to_build(req, build)
34 data = '<a href="%s">#%d</a> ' % (buildurl, buildnum)
35
36 when = build.getETA()
37 if when is not None:
38 when_time = time.strftime("%H:%M:%S",
39 time.localtime(time.time() + when))
40 data += "ETA %ds (%s) " % (when, when_time)
41 step = build.getCurrentStep()
42 if step:
43 data += "[%s]" % step.getName()
44 else:
45 data += "[waiting for Lock]"
46 # TODO: is this necessarily the case?
47
48 if self.builder_control is not None:
49 stopURL = path_to_build(req, build) + '/stop'
50 data += '''
51 <form method="post" action="%s" class="command stopbuild" style="display:inline" >
52 <input type="submit" value="Stop Build" />
53 </form>''' % stopURL
54 return data
55
56 def request_line(self, build_request, req):
57 when = time.strftime("%b %d %H:%M:%S", time.localtime(build_request.getS ubmitTime()))
58 delay = util.formatInterval(util.now() - build_request.getSubmitTime())
59 changes = build_request.source.changes
60 if changes:
61 change_strings = []
62 for c in changes:
63 change_strings.append("<a href=\"%s\">%s</a>" % (path_to_change( req, c), c.who))
64 if len(change_strings) == 1:
65 reason = "change by %s" % change_strings[0]
66 else:
67 reason = "changes by %s" % ", ".join(change_strings)
68 elif build_request.source.revision:
69 reason = build_request.source.revision
70 else:
71 reason = "no changes specified"
72
73 if self.builder_control is not None:
74 cancelURL = path_to_builder(req, self.builder_status) + '/cancelbuil d'
75 cancelButton = '''
76 <form action="%s" class="command cancelbuild" style="display:inline" method="pos t">
77 <input type="hidden" name="id" value="%s" />
78 <input type="submit" value="Cancel Build" />
79 </form>''' % (cancelURL, id(build_request))
80 else:
81 cancelButton = ""
82 return "<font size=\"-1\">(%s, waiting %s)</font>%s%s" % (when, delay, c ancelButton, reason)
83
84 def body(self, req):
85 b = self.builder_status
86 control = self.builder_control
87 status = self.getStatus(req)
88
89 slaves = b.getSlaves()
90 connected_slaves = [s for s in slaves if s.isConnected()]
91
92 projectName = status.getProjectName()
93
94 data = '<a href="%s">%s</a>\n' % (self.path_to_root(req), projectName)
95
96 data += "<h1>Builder: %s</h1>\n" % html.escape(b.getName())
97
98 # the first section shows builds which are currently running, if any.
99
100 current = b.getCurrentBuilds()
101 if current:
102 data += "<h2>Currently Building:</h2>\n"
103 data += "<ul>\n"
104 for build in current:
105 data += " <li>" + self.build_line(build, req) + "</li>\n"
106 data += "</ul>\n"
107 else:
108 data += "<h2>no current builds</h2>\n"
109
110 pending = b.getPendingBuilds()
111 if pending:
112 data += "<h2>Pending Builds:</h2>\n"
113 data += "<ul>\n"
114 for request in pending:
115 data += " <li>" + self.request_line(request, req) + "</li>\n"
116 data += "</ul>\n"
117
118 cancelURL = path_to_builder(req, self.builder_status) + '/cancelbuil d'
119 if self.builder_control is not None:
120 data += '''
121 <form action="%s" class="command cancelbuild" style="display:inline" method="pos t">
122 <input type="hidden" name="id" value="all" />
123 <input type="submit" value="Cancel All" />
124 </form>''' % cancelURL
125 else:
126 data += "<h2>no pending builds</h2>\n"
127
128 # Then a section with the last 5 builds, with the most recent build
129 # distinguished from the rest.
130
131 data += "<h2>Recent Builds:</h2>\n"
132 data += "(<a href=\"%s\">view in waterfall</a>)\n" % (self.path_to_root( req)+"waterfall?show="+html.escape(b.getName()))
133 data += "<ul>\n"
134 numbuilds = int(req.args.get('numbuilds', ['5'])[0])
135 for i,build in enumerate(b.generateFinishedBuilds(num_builds=int(numbuil ds))):
136 data += " <li>" + self.make_line(req, build, False) + "</li>\n"
137 if i == 0:
138 data += "<br />\n" # separator
139 # TODO: or empty list?
140 data += "</ul>\n"
141
142
143 data += "<h2>Buildslaves:</h2>\n"
144 data += "<ol>\n"
145 for slave in slaves:
146 slaveurl = path_to_slave(req, slave)
147 data += "<li><b><a href=\"%s\">%s</a></b>: " % (html.escape(slaveurl ), html.escape(slave.getName()))
148 if slave.isConnected():
149 data += "CONNECTED\n"
150 if slave.getAdmin():
151 data += make_row("Admin:", html.escape(slave.getAdmin()))
152 if slave.getHost():
153 data += "<span class='label'>Host info:</span>\n"
154 data += html.PRE(html.escape(slave.getHost()))
155 else:
156 data += ("NOT CONNECTED\n")
157 data += "</li>\n"
158 data += "</ol>\n"
159
160 if control is not None and connected_slaves:
161 forceURL = path_to_builder(req, b) + '/force'
162 data += make_force_build_form(forceURL, self.isUsingUserPasswd(req))
163 elif control is not None:
164 data += """
165 <p>All buildslaves appear to be offline, so it's not possible
166 to force this build to execute at this time.</p>
167 """
168
169 if control is not None:
170 pingURL = path_to_builder(req, b) + '/ping'
171 data += """
172 <form method="post" action="%s" class='command pingbuilder'>
173 <p>To ping the buildslave(s), push the 'Ping' button</p>
174
175 <input type="submit" value="Ping Builder" />
176 </form>
177 """ % pingURL
178
179 data += self.footer(status, req)
180
181 return data
182
183 def force(self, req):
184 """
185
186 Custom properties can be passed from the web form. To do
187 this, subclass this class, overriding the force() method. You
188 can then determine the properties (usually from form values,
189 by inspecting req.args), then pass them to this superclass
190 force method.
191
192 """
193 name = req.args.get("username", ["<unknown>"])[0]
194 reason = req.args.get("comments", ["<no reason specified>"])[0]
195 branch = req.args.get("branch", [""])[0]
196 revision = req.args.get("revision", [""])[0]
197
198 r = "The web-page 'force build' button was pressed by '%s': %s\n" \
199 % (html.escape(name), html.escape(reason))
200 log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'"
201 " by user '%s'" % (self.builder_status.getName(), branch,
202 revision, name))
203
204 if not self.builder_control:
205 # TODO: tell the web user that their request was denied
206 log.msg("but builder control is disabled")
207 return Redirect("..")
208
209 if self.isUsingUserPasswd(req):
210 if not self.authUser(req):
211 return Redirect("../../authfail")
212
213 # keep weird stuff out of the branch revision, and property strings.
214 # TODO: centralize this somewhere.
215 if not re.match(r'^[\w\.\-\/]*$', branch):
216 log.msg("bad branch '%s'" % branch)
217 return Redirect("..")
218 if not re.match(r'^[\w\.\-\/]*$', revision):
219 log.msg("bad revision '%s'" % revision)
220 return Redirect("..")
221 properties = getAndCheckProperties(req)
222 if properties is None:
223 return Redirect("..")
224 if not branch:
225 branch = None
226 if not revision:
227 revision = None
228
229 # TODO: if we can authenticate that a particular User pushed the
230 # button, use their name instead of None, so they'll be informed of
231 # the results.
232 # TODO2: we can authenticate that a particular User pushed the button
233 # now, so someone can write this support. but it requires a
234 # buildbot.changes.changes.Change instance which is tedious at this
235 # stage to compute
236 s = SourceStamp(branch=branch, revision=revision)
237 req = BuildRequest(r, s, builderName=self.builder_status.getName(),
238 properties=properties)
239 try:
240 self.builder_control.requestBuildSoon(req)
241 except interfaces.NoSlaveError:
242 # TODO: tell the web user that their request could not be
243 # honored
244 pass
245 # send the user back to the builder page
246 return Redirect(".")
247
248 def ping(self, req):
249 log.msg("web ping of builder '%s'" % self.builder_status.getName())
250 self.builder_control.ping() # TODO: there ought to be an ISlaveControl
251 # send the user back to the builder page
252 return Redirect(".")
253
254 def cancel(self, req):
255 try:
256 request_id = req.args.get("id", [None])[0]
257 if request_id == "all":
258 cancel_all = True
259 else:
260 cancel_all = False
261 request_id = int(request_id)
262 except:
263 request_id = None
264 if request_id:
265 for build_req in self.builder_control.getPendingBuilds():
266 if cancel_all or id(build_req.original_request.status) == reques t_id:
267 log.msg("Cancelling %s" % build_req)
268 build_req.cancel()
269 if not cancel_all:
270 break
271 return Redirect(".")
272
273 def getChild(self, path, req):
274 if path == "force":
275 return self.force(req)
276 if path == "ping":
277 return self.ping(req)
278 if path == "events":
279 num = req.postpath.pop(0)
280 req.prepath.append(num)
281 num = int(num)
282 # TODO: is this dead code? .statusbag doesn't exist,right?
283 log.msg("getChild['path']: %s" % req.uri)
284 return NoResource("events are unavailable until code gets fixed")
285 filename = req.postpath.pop(0)
286 req.prepath.append(filename)
287 e = self.builder_status.getEventNumbered(num)
288 if not e:
289 return NoResource("No such event '%d'" % num)
290 file = e.files.get(filename, None)
291 if file == None:
292 return NoResource("No such file '%s'" % filename)
293 if type(file) == type(""):
294 if file[:6] in ("<HTML>", "<html>"):
295 return static.Data(file, "text/html")
296 return static.Data(file, "text/plain")
297 return file
298 if path == "cancelbuild":
299 return self.cancel(req)
300 if path == "builds":
301 return BuildsResource(self.builder_status, self.builder_control)
302
303 return HtmlResource.getChild(self, path, req)
304
305
306 # /builders/_all
307 class StatusResourceAllBuilders(HtmlResource, OneLineMixin):
308
309 def __init__(self, status, control):
310 HtmlResource.__init__(self)
311 self.status = status
312 self.control = control
313
314 def getChild(self, path, req):
315 if path == "force":
316 return self.force(req)
317 if path == "stop":
318 return self.stop(req)
319
320 return HtmlResource.getChild(self, path, req)
321
322 def force(self, req):
323 for bname in self.status.getBuilderNames():
324 builder_status = self.status.getBuilder(bname)
325 builder_control = None
326 c = self.getControl(req)
327 if c:
328 builder_control = c.getBuilder(bname)
329 build = StatusResourceBuilder(builder_status, builder_control)
330 build.force(req)
331 # back to the welcome page
332 return Redirect("../..")
333
334 def stop(self, req):
335 for bname in self.status.getBuilderNames():
336 builder_status = self.status.getBuilder(bname)
337 builder_control = None
338 c = self.getControl(req)
339 if c:
340 builder_control = c.getBuilder(bname)
341 (state, current_builds) = builder_status.getState()
342 if state != "building":
343 continue
344 for b in current_builds:
345 build_status = builder_status.getBuild(b.number)
346 if not build_status:
347 continue
348 if builder_control:
349 build_control = builder_control.getBuild(b.number)
350 else:
351 build_control = None
352 build = StatusResourceBuild(build_status, build_control,
353 builder_control)
354 build.stop(req)
355 # go back to the welcome page
356 return Redirect("../..")
357
358
359 # /builders
360 class BuildersResource(HtmlResource):
361 title = "Builders"
362 addSlash = True
363
364 def body(self, req):
365 s = self.getStatus(req)
366 data = ""
367 data += "<h1>Builders</h1>\n"
368
369 # TODO: this is really basic. It should be expanded to include a
370 # brief one-line summary of the builder (perhaps with whatever the
371 # builder is currently doing)
372 data += "<ol>\n"
373 for bname in s.getBuilderNames():
374 data += (' <li><a href="%s">%s</a></li>\n' %
375 (req.childLink(urllib.quote(bname, safe='')),
376 bname))
377 data += "</ol>\n"
378
379 data += self.footer(s, req)
380
381 return data
382
383 def getChild(self, path, req):
384 s = self.getStatus(req)
385 if path in s.getBuilderNames():
386 builder_status = s.getBuilder(path)
387 builder_control = None
388 c = self.getControl(req)
389 if c:
390 builder_control = c.getBuilder(path)
391 return StatusResourceBuilder(builder_status, builder_control)
392 if path == "_all":
393 return StatusResourceAllBuilders(self.getStatus(req),
394 self.getControl(req))
395
396 return HtmlResource.getChild(self, path, req)
397
OLDNEW
« no previous file with comments | « third_party/buildbot_7_12/buildbot/status/web/build.py ('k') | third_party/buildbot_7_12/buildbot/status/web/buildstatus.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698