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

Side by Side Diff: third_party/buildbot_7_12/buildbot/status/web/baseweb.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 import os, sys, urllib, weakref
3 from itertools import count
4
5 from zope.interface import implements
6 from twisted.python import log
7 from twisted.application import strports, service
8 from twisted.web import server, distrib, static, html
9 from twisted.spread import pb
10
11 from buildbot.interfaces import IControl, IStatusReceiver
12
13 from buildbot.status.web.base import HtmlResource, Box, \
14 build_get_class, ICurrentBox, OneLineMixin, map_branches, \
15 make_stop_form, make_force_build_form
16 from buildbot.status.web.feeds import Rss20StatusResource, \
17 Atom10StatusResource
18 from buildbot.status.web.waterfall import WaterfallStatusResource
19 from buildbot.status.web.console import ConsoleStatusResource
20 from buildbot.status.web.grid import GridStatusResource, TransposedGridStatusRes ource
21 from buildbot.status.web.changes import ChangesResource
22 from buildbot.status.web.builder import BuildersResource
23 from buildbot.status.web.buildstatus import BuildStatusStatusResource
24 from buildbot.status.web.slaves import BuildSlavesResource
25 from buildbot.status.web.status_json import JsonStatusResource
26 from buildbot.status.web.xmlrpc import XMLRPCServer
27 from buildbot.status.web.about import AboutBuildbot
28 from buildbot.status.web.auth import IAuth, AuthFailResource
29
30 # this class contains the status services (WebStatus and the older Waterfall)
31 # which can be put in c['status']. It also contains some of the resources
32 # that are attached to the WebStatus at various well-known URLs, which the
33 # admin might wish to attach (using WebStatus.putChild) at other URLs.
34
35
36 class LastBuild(HtmlResource):
37 def body(self, request):
38 return "missing\n"
39
40 def getLastNBuilds(status, numbuilds, builders=[], branches=[]):
41 """Return a list with the last few Builds, sorted by start time.
42 builder_names=None means all builders
43 """
44
45 # TODO: this unsorts the list of builder names, ick
46 builder_names = set(status.getBuilderNames())
47 if builders:
48 builder_names = builder_names.intersection(set(builders))
49
50 # to make sure that we get everything, we must get 'numbuilds' builds
51 # from *each* source, then sort by ending time, then trim to the last
52 # 20. We could be more efficient, but it would require the same
53 # gnarly code that the Waterfall uses to generate one event at a
54 # time. TODO: factor that code out into some useful class.
55 events = []
56 for builder_name in builder_names:
57 builder = status.getBuilder(builder_name)
58 for build_number in count(1):
59 if build_number > numbuilds:
60 break # enough from this builder, move on to another
61 build = builder.getBuild(-build_number)
62 if not build:
63 break # no more builds here, move on to the next builder
64 #if not build.isFinished():
65 # continue
66 (build_start, build_end) = build.getTimes()
67 event = (build_start, builder_name, build)
68 events.append(event)
69 def _sorter(a, b):
70 return cmp( a[:2], b[:2] )
71 events.sort(_sorter)
72 # now only return the actual build, and only return some of them
73 return [e[2] for e in events[-numbuilds:]]
74
75
76 # /one_line_per_build
77 # accepts builder=, branch=, numbuilds=, reload=
78 class OneLinePerBuild(HtmlResource, OneLineMixin):
79 """This shows one line per build, combining all builders together. Useful
80 query arguments:
81
82 numbuilds=: how many lines to display
83 builder=: show only builds for this builder. Multiple builder= arguments
84 can be used to see builds from any builder in the set.
85 reload=: reload the page after this many seconds
86 """
87
88 title = "Recent Builds"
89
90 def __init__(self, numbuilds=20):
91 HtmlResource.__init__(self)
92 self.numbuilds = numbuilds
93
94 def getChild(self, path, req):
95 status = self.getStatus(req)
96 builder = status.getBuilder(path)
97 return OneLinePerBuildOneBuilder(builder, numbuilds=self.numbuilds)
98
99 def get_reload_time(self, request):
100 if "reload" in request.args:
101 try:
102 reload_time = int(request.args["reload"][0])
103 return max(reload_time, 15)
104 except ValueError:
105 pass
106 return None
107
108 def head(self, request):
109 head = ''
110 reload_time = self.get_reload_time(request)
111 if reload_time is not None:
112 head += '<meta http-equiv="refresh" content="%d">\n' % reload_time
113 return head
114
115 def body(self, req):
116 status = self.getStatus(req)
117 control = self.getControl(req)
118 numbuilds = int(req.args.get("numbuilds", [self.numbuilds])[0])
119 builders = req.args.get("builder", [])
120 branches = [b for b in req.args.get("branch", []) if b]
121
122 g = status.generateFinishedBuilds(builders, map_branches(branches),
123 numbuilds, max_search=numbuilds)
124
125 data = ""
126
127 # really this is "up to %d builds"
128 html_branches = map(html.escape, branches)
129 data += "<h1>Last %d finished builds: %s</h1>\n" % \
130 (numbuilds, ", ".join(html_branches))
131 if builders:
132 html_builders = map(html.escape, builders)
133 data += ("<p>of builders: %s</p>\n" % (", ".join(html_builders)))
134 data += "<ul>\n"
135 got = 0
136 building = False
137 online = 0
138 for build in g:
139 got += 1
140 data += " <li>" + self.make_line(req, build) + "</li>\n"
141 builder_status = build.getBuilder().getState()[0]
142 if builder_status == "building":
143 building = True
144 online += 1
145 elif builder_status != "offline":
146 online += 1
147 if not got:
148 data += " <li>No matching builds found</li>\n"
149 data += "</ul>\n"
150
151 if control is not None:
152 if building:
153 stopURL = "builders/_all/stop"
154 data += make_stop_form(stopURL, self.isUsingUserPasswd(req),
155 True, "Builds")
156 if online:
157 forceURL = "builders/_all/force"
158 data += make_force_build_form(forceURL,
159 self.isUsingUserPasswd(req), True)
160
161 return data
162
163
164
165 # /one_line_per_build/$BUILDERNAME
166 # accepts branch=, numbuilds=
167
168 class OneLinePerBuildOneBuilder(HtmlResource, OneLineMixin):
169 def __init__(self, builder, numbuilds=20):
170 HtmlResource.__init__(self)
171 self.builder = builder
172 self.builder_name = builder.getName()
173 self.numbuilds = numbuilds
174 self.title = "Recent Builds of %s" % self.builder_name
175
176 def body(self, req):
177 status = self.getStatus(req)
178 numbuilds = int(req.args.get("numbuilds", [self.numbuilds])[0])
179 branches = [b for b in req.args.get("branch", []) if b]
180
181 # walk backwards through all builds of a single builder
182 g = self.builder.generateFinishedBuilds(map_branches(branches),
183 numbuilds)
184
185 data = ""
186 html_branches = map(html.escape, branches)
187 data += ("<h1>Last %d builds of builder %s: %s</h1>\n" %
188 (numbuilds, self.builder_name, ", ".join(html_branches)))
189 data += "<ul>\n"
190 got = 0
191 for build in g:
192 got += 1
193 data += " <li>" + self.make_line(req, build) + "</li>\n"
194 if not got:
195 data += " <li>No matching builds found</li>\n"
196 data += "</ul>\n"
197
198 return data
199
200 # /one_box_per_builder
201 # accepts builder=, branch=
202 class OneBoxPerBuilder(HtmlResource):
203 """This shows a narrow table with one row per builder. The leftmost column
204 contains the builder name. The next column contains the results of the
205 most recent build. The right-hand column shows the builder's current
206 activity.
207
208 builder=: show only builds for this builder. Multiple builder= arguments
209 can be used to see builds from any builder in the set.
210 """
211
212 title = "Latest Build"
213
214 def body(self, req):
215 status = self.getStatus(req)
216 control = self.getControl(req)
217
218 builders = req.args.get("builder", status.getBuilderNames())
219 branches = [b for b in req.args.get("branch", []) if b]
220
221 data = ""
222
223 html_branches = map(html.escape, branches)
224 data += "<h2>Latest builds: %s</h2>\n" % ", ".join(html_branches)
225 data += "<table>\n"
226
227 building = False
228 online = 0
229 base_builders_url = self.path_to_root(req) + "builders/"
230 for bn in builders:
231 base_builder_url = base_builders_url + urllib.quote(bn, safe='')
232 builder = status.getBuilder(bn)
233 data += "<tr>\n"
234 data += '<td class="box"><a href="%s">%s</a></td>\n' \
235 % (base_builder_url, html.escape(bn))
236 builds = list(builder.generateFinishedBuilds(map_branches(branches),
237 num_builds=1))
238 if builds:
239 b = builds[0]
240 url = (base_builder_url + "/builds/%d" % b.getNumber())
241 try:
242 label = b.getProperty("got_revision")
243 except KeyError:
244 label = None
245 if not label or len(str(label)) > 20:
246 label = "#%d" % b.getNumber()
247 text = ['<a href="%s">%s</a>' % (url, label)]
248 text.extend(b.getText())
249 box = Box(text,
250 class_="LastBuild box %s" % build_get_class(b))
251 data += box.td(align="center")
252 else:
253 data += '<td class="LastBuild box" >no build</td>\n'
254 current_box = ICurrentBox(builder).getBox(status)
255 data += current_box.td(align="center")
256
257 builder_status = builder.getState()[0]
258 if builder_status == "building":
259 building = True
260 online += 1
261 elif builder_status != "offline":
262 online += 1
263
264 data += "</table>\n"
265
266 if control is not None:
267 if building:
268 stopURL = "builders/_all/stop"
269 data += make_stop_form(stopURL, self.isUsingUserPasswd(req),
270 True, "Builds")
271 if online:
272 forceURL = "builders/_all/force"
273 data += make_force_build_form(forceURL,
274 self.isUsingUserPasswd(req), True)
275
276 return data
277
278
279
280 HEADER = '''
281 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
282 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
283
284 <html
285 xmlns="http://www.w3.org/1999/xhtml"
286 lang="en"
287 xml:lang="en">
288 '''
289
290 HEAD_ELEMENTS = [
291 '<title>%(title)s</title>',
292 '<link href="%(root)sbuildbot.css" rel="stylesheet" type="text/css" />',
293 ]
294 BODY_ATTRS = {
295 'vlink': "#800080",
296 }
297
298 FOOTER = '''
299 </html>
300 '''
301
302
303 class WebStatus(service.MultiService):
304 implements(IStatusReceiver)
305 # TODO: IStatusReceiver is really about things which subscribe to hear
306 # about buildbot events. We need a different interface (perhaps a parent
307 # of IStatusReceiver) for status targets that don't subscribe, like the
308 # WebStatus class. buildbot.master.BuildMaster.loadConfig:737 asserts
309 # that everything in c['status'] provides IStatusReceiver, but really it
310 # should check that they provide IStatusTarget instead.
311
312 """
313 The webserver provided by this class has the following resources:
314
315 /waterfall : the big time-oriented 'waterfall' display, with links
316 to individual changes, builders, builds, steps, and logs.
317 A number of query-arguments can be added to influence
318 the display.
319 /rss : a rss feed summarizing all failed builds. The same
320 query-arguments used by 'waterfall' can be added to
321 influence the feed output.
322 /atom : an atom feed summarizing all failed builds. The same
323 query-arguments used by 'waterfall' can be added to
324 influence the feed output.
325 /grid : another summary display that shows a grid of builds, with
326 sourcestamps on the x axis, and builders on the y. Query
327 arguments similar to those for the waterfall can be added.
328 /tgrid : similar to the grid display, but the commits are down the
329 left side, and the build hosts are across the top.
330 /builders/BUILDERNAME: a page summarizing the builder. This includes
331 references to the Schedulers that feed it,
332 any builds currently in the queue, which
333 buildslaves are designated or attached, and a
334 summary of the build process it uses.
335 /builders/BUILDERNAME/builds/NUM: a page describing a single Build
336 /builders/BUILDERNAME/builds/NUM/steps/STEPNAME: describes a single step
337 /builders/BUILDERNAME/builds/NUM/steps/STEPNAME/logs/LOGNAME: a StatusLog
338 /builders/BUILDERNAME/builds/NUM/tests : summarize test results
339 /builders/BUILDERNAME/builds/NUM/tests/TEST.NAME: results of one test
340 /builders/_all/{force,stop}: force a build/stop building on all builders.
341 /changes : summarize all ChangeSources
342 /changes/CHANGENUM: a page describing a single Change
343 /schedulers/SCHEDULERNAME: a page describing a Scheduler, including
344 a description of its behavior, a list of the
345 Builders it triggers, and list of the Changes
346 that are queued awaiting the tree-stable
347 timer, and controls to accelerate the timer.
348 /buildslaves : list all BuildSlaves
349 /buildslaves/SLAVENAME : describe a single BuildSlave
350 /one_line_per_build : summarize the last few builds, one line each
351 /one_line_per_build/BUILDERNAME : same, but only for a single builder
352 /one_box_per_builder : show the latest build and current activity
353 /about : describe this buildmaster (Buildbot and support library versions)
354 /xmlrpc : (not yet implemented) an XMLRPC server with build status
355
356
357 All URLs for pages which are not defined here are used to look
358 for files in PUBLIC_HTML, which defaults to BASEDIR/public_html.
359 This means that /robots.txt or /buildbot.css or /favicon.ico can
360 be placed in that directory.
361
362 If an index file (index.html, index.htm, or index, in that order) is
363 present in PUBLIC_HTML, it will be used for the root resource. If not,
364 the default behavior is to put a redirection to the /waterfall page.
365
366 All of the resources provided by this service use relative URLs to reach
367 each other. The only absolute links are the c['projectURL'] links at the
368 top and bottom of the page, and the buildbot home-page link at the
369 bottom.
370
371 This webserver defines class attributes on elements so they can be styled
372 with CSS stylesheets. All pages pull in PUBLIC_HTML/buildbot.css, and you
373 can cause additional stylesheets to be loaded by adding a suitable <link>
374 to the WebStatus instance's .head_elements attribute.
375
376 Buildbot uses some generic classes to identify the type of object, and
377 some more specific classes for the various kinds of those types. It does
378 this by specifying both in the class attributes where applicable,
379 separated by a space. It is important that in your CSS you declare the
380 more generic class styles above the more specific ones. For example,
381 first define a style for .Event, and below that for .SUCCESS
382
383 The following CSS class names are used:
384 - Activity, Event, BuildStep, LastBuild: general classes
385 - waiting, interlocked, building, offline, idle: Activity states
386 - start, running, success, failure, warnings, skipped, exception:
387 LastBuild and BuildStep states
388 - Change: box with change
389 - Builder: box for builder name (at top)
390 - Project
391 - Time
392
393 """
394
395 # we are not a ComparableMixin, and therefore the webserver will be
396 # rebuilt every time we reconfig. This is because WebStatus.putChild()
397 # makes it too difficult to tell whether two instances are the same or
398 # not (we'd have to do a recursive traversal of all children to discover
399 # all the changes).
400
401 def __init__(self, http_port=None, distrib_port=None, allowForce=False,
402 public_html="public_html", site=None, numbuilds=20,
403 num_events=200, num_events_max=None, auth=None,
404 order_console_by_time=False):
405 """Run a web server that provides Buildbot status.
406
407 @type http_port: int or L{twisted.application.strports} string
408 @param http_port: a strports specification describing which port the
409 buildbot should use for its web server, with the
410 Waterfall display as the root page. For backwards
411 compatibility this can also be an int. Use
412 'tcp:8000' to listen on that port, or
413 'tcp:12345:interface=127.0.0.1' if you only want
414 local processes to connect to it (perhaps because
415 you are using an HTTP reverse proxy to make the
416 buildbot available to the outside world, and do not
417 want to make the raw port visible).
418
419 @type distrib_port: int or L{twisted.application.strports} string
420 @param distrib_port: Use this if you want to publish the Waterfall
421 page using web.distrib instead. The most common
422 case is to provide a string that is an absolute
423 pathname to the unix socket on which the
424 publisher should listen
425 (C{os.path.expanduser(~/.twistd-web-pb)} will
426 match the default settings of a standard
427 twisted.web 'personal web server'). Another
428 possibility is to pass an integer, which means
429 the publisher should listen on a TCP socket,
430 allowing the web server to be on a different
431 machine entirely. Both forms are provided for
432 backwards compatibility; the preferred form is a
433 strports specification like
434 'unix:/home/buildbot/.twistd-web-pb'. Providing
435 a non-absolute pathname will probably confuse
436 the strports parser.
437
438 @param allowForce: boolean, if True then the webserver will allow
439 visitors to trigger and cancel builds
440
441 @param public_html: the path to the public_html directory for this displ ay,
442 either absolute or relative to the basedir. The def ault
443 is 'public_html', which selects BASEDIR/public_html.
444
445 @type site: None or L{twisted.web.server.Site}
446 @param site: Use this if you want to define your own object instead of
447 using the default.`
448
449 @type numbuilds: int
450 @param numbuilds: Default number of entries in lists at the /one_line_pe r_build
451 and /builders/FOO URLs. This default can be overriden both programatica lly ---
452 by passing the equally named argument to constructors of OneLinePerBuild OneBuilder
453 and OneLinePerBuild --- and via the UI, by tacking ?numbuilds=xy onto th e URL.
454
455 @type num_events: int
456 @param num_events: Defaualt number of events to show in the waterfall.
457
458 @type num_events_max: int
459 @param num_events_max: The maximum number of events that are allowed to be
460 shown in the waterfall. The default value of C{None} will disable this
461 check
462
463 @type auth: a L{status.web.auth.IAuth} or C{None}
464 @param auth: an object that performs authentication to restrict access
465 to the C{allowForce} features. Ignored if C{allowForce}
466 is not C{True}. If C{auth} is C{None}, people can force or
467 stop builds without auth.
468
469 @type order_console_by_time: bool
470 @param order_console_by_time: Whether to order changes (commits) in the console
471 view according to the time they were created (for VCS like Git) or
472 according to their integer revision numbers (for VCS like S VN).
473 """
474
475 service.MultiService.__init__(self)
476 if type(http_port) is int:
477 http_port = "tcp:%d" % http_port
478 self.http_port = http_port
479 if distrib_port is not None:
480 if type(distrib_port) is int:
481 distrib_port = "tcp:%d" % distrib_port
482 if distrib_port[0] in "/~.": # pathnames
483 distrib_port = "unix:%s" % distrib_port
484 self.distrib_port = distrib_port
485 self.allowForce = allowForce
486 self.num_events = num_events
487 if num_events_max:
488 assert num_events_max >= num_events
489 self.num_events_max = num_events_max
490 self.public_html = public_html
491
492 if self.allowForce and auth:
493 assert IAuth.providedBy(auth)
494 self.auth = auth
495 else:
496 if auth:
497 log.msg("Warning: Ignoring authentication. allowForce must be"
498 " set to True use this")
499 self.auth = None
500
501 self.orderConsoleByTime = order_console_by_time
502
503 # If we were given a site object, go ahead and use it.
504 if site:
505 self.site = site
506 else:
507 # this will be replaced once we've been attached to a parent (and
508 # thus have a basedir and can reference BASEDIR)
509 root = static.Data("placeholder", "text/plain")
510 self.site = server.Site(root)
511 self.childrenToBeAdded = {}
512
513 self.setupUsualPages(numbuilds=numbuilds, num_events=num_events,
514 num_events_max=num_events_max)
515
516 # the following items are accessed by HtmlResource when it renders
517 # each page.
518 self.site.buildbot_service = self
519 self.header = HEADER
520 self.head_elements = HEAD_ELEMENTS[:]
521 self.body_attrs = BODY_ATTRS.copy()
522 self.footer = FOOTER
523 self.template_values = {}
524
525 # keep track of cached connections so we can break them when we shut
526 # down. See ticket #102 for more details.
527 self.channels = weakref.WeakKeyDictionary()
528
529 if self.http_port is not None:
530 s = strports.service(self.http_port, self.site)
531 s.setServiceParent(self)
532 if self.distrib_port is not None:
533 f = pb.PBServerFactory(distrib.ResourcePublisher(self.site))
534 s = strports.service(self.distrib_port, f)
535 s.setServiceParent(self)
536
537 def setupUsualPages(self, numbuilds, num_events, num_events_max):
538 #self.putChild("", IndexOrWaterfallRedirection())
539 self.putChild("waterfall", WaterfallStatusResource(num_events=num_events ,
540 num_events_max=num_events_max))
541 self.putChild("grid", GridStatusResource())
542 self.putChild("console", ConsoleStatusResource(
543 orderByTime=self.orderConsoleByTime))
544 self.putChild("tgrid", TransposedGridStatusResource())
545 self.putChild("builders", BuildersResource()) # has builds/steps/logs
546 self.putChild("changes", ChangesResource())
547 self.putChild("buildslaves", BuildSlavesResource())
548 self.putChild("buildstatus", BuildStatusStatusResource())
549 #self.putChild("schedulers", SchedulersResource())
550 self.putChild("one_line_per_build",
551 OneLinePerBuild(numbuilds=numbuilds))
552 self.putChild("one_box_per_builder", OneBoxPerBuilder())
553 self.putChild("xmlrpc", XMLRPCServer())
554 self.putChild("about", AboutBuildbot())
555 self.putChild("authfail", AuthFailResource())
556
557 def __repr__(self):
558 if self.http_port is None:
559 return "<WebStatus on path %s at %s>" % (self.distrib_port,
560 hex(id(self)))
561 if self.distrib_port is None:
562 return "<WebStatus on port %s at %s>" % (self.http_port,
563 hex(id(self)))
564 return ("<WebStatus on port %s and path %s at %s>" %
565 (self.http_port, self.distrib_port, hex(id(self))))
566
567 def setServiceParent(self, parent):
568 service.MultiService.setServiceParent(self, parent)
569
570 # this class keeps a *separate* link to the buildmaster, rather than
571 # just using self.parent, so that when we are "disowned" (and thus
572 # parent=None), any remaining HTTP clients of this WebStatus will still
573 # be able to get reasonable results.
574 self.master = parent
575
576 self.setupSite()
577
578 def setupSite(self):
579 # this is responsible for creating the root resource. It isn't done
580 # at __init__ time because we need to reference the parent's basedir.
581 htmldir = os.path.abspath(os.path.join(self.master.basedir, self.public_ html))
582 if os.path.isdir(htmldir):
583 log.msg("WebStatus using (%s)" % htmldir)
584 else:
585 log.msg("WebStatus: warning: %s is missing. Do you need to run"
586 " 'buildbot upgrade-master' on this buildmaster?" % htmldir)
587 # all static pages will get a 404 until upgrade-master is used to
588 # populate this directory. Create the directory, though, since
589 # otherwise we get internal server errors instead of 404s.
590 os.mkdir(htmldir)
591 root = static.File(htmldir)
592
593 for name, child_resource in self.childrenToBeAdded.iteritems():
594 root.putChild(name, child_resource)
595
596 status = self.getStatus()
597 # Disabled from Chromium.
598 # root.putChild("rss", Rss20StatusResource(status))
599 # root.putChild("atom", Atom10StatusResource(status))
600 root.putChild("json", JsonStatusResource(status))
601
602 self.site.resource = root
603
604 def putChild(self, name, child_resource):
605 """This behaves a lot like root.putChild() . """
606 self.childrenToBeAdded[name] = child_resource
607
608 def registerChannel(self, channel):
609 self.channels[channel] = 1 # weakrefs
610
611 def stopService(self):
612 for channel in self.channels:
613 try:
614 channel.transport.loseConnection()
615 except:
616 log.msg("WebStatus.stopService: error while disconnecting"
617 " leftover clients")
618 log.err()
619 return service.MultiService.stopService(self)
620
621 def getStatus(self):
622 return self.master.getStatus()
623
624 def getControl(self):
625 if self.allowForce:
626 return IControl(self.master)
627 return None
628
629 def getChangeSvc(self):
630 return self.master.change_svc
631
632 def getPortnum(self):
633 # this is for the benefit of unit tests
634 s = list(self)[0]
635 return s._port.getHost().port
636
637 def isUsingUserPasswd(self):
638 """Returns boolean to indicate if this WebStatus uses authentication"""
639 if self.auth:
640 return True
641 return False
642
643 def authUser(self, user, passwd):
644 """Check that user/passwd is a valid user/pass tuple and can should be
645 allowed to perform the action. If this WebStatus is not password
646 protected, this function returns False."""
647 if not self.isUsingUserPasswd():
648 return False
649 if self.auth.authenticate(user, passwd):
650 return True
651 log.msg("Authentication failed for '%s': %s" % (user,
652 self.auth.errmsg()))
653 return False
654
655 # resources can get access to the IStatus by calling
656 # request.site.buildbot_service.getStatus()
657
658 # this is the compatibility class for the old waterfall. It is exactly like a
659 # regular WebStatus except that the root resource (e.g. http://buildbot.net/)
660 # always redirects to a WaterfallStatusResource, and the old arguments are
661 # mapped into the new resource-tree approach. In the normal WebStatus, the
662 # root resource either redirects the browser to /waterfall or serves
663 # PUBLIC_HTML/index.html, and favicon/robots.txt are provided by
664 # having the admin write actual files into PUBLIC_HTML/ .
665
666 # note: we don't use a util.Redirect here because HTTP requires that the
667 # Location: header provide an absolute URI, and it's non-trivial to figure
668 # out our absolute URI from here.
669
670 class Waterfall(WebStatus):
671
672 if hasattr(sys, "frozen"):
673 # all 'data' files are in the directory of our executable
674 here = os.path.dirname(sys.executable)
675 buildbot_icon = os.path.abspath(os.path.join(here, "buildbot.png"))
676 buildbot_css = os.path.abspath(os.path.join(here, "classic.css"))
677 else:
678 # running from source
679 # the icon is sibpath(__file__, "../buildbot.png") . This is for
680 # portability.
681 up = os.path.dirname
682 buildbot_icon = os.path.abspath(os.path.join(up(up(up(__file__))),
683 "buildbot.png"))
684 buildbot_css = os.path.abspath(os.path.join(up(__file__),
685 "classic.css"))
686
687 compare_attrs = ["http_port", "distrib_port", "allowForce",
688 "categories", "css", "favicon", "robots_txt"]
689
690 def __init__(self, http_port=None, distrib_port=None, allowForce=True,
691 categories=None, css=buildbot_css, favicon=buildbot_icon,
692 robots_txt=None):
693 import warnings
694 m = ("buildbot.status.html.Waterfall is deprecated as of 0.7.6 "
695 "and will be removed from a future release. "
696 "Please use html.WebStatus instead.")
697 warnings.warn(m, DeprecationWarning)
698
699 WebStatus.__init__(self, http_port, distrib_port, allowForce)
700 self.css = css
701 if css:
702 if os.path.exists(os.path.join("public_html", "buildbot.css")):
703 # they've upgraded, so defer to that copy instead
704 pass
705 else:
706 data = open(css, "rb").read()
707 self.putChild("buildbot.css", static.Data(data, "text/css"))
708 self.favicon = favicon
709 self.robots_txt = robots_txt
710 if favicon:
711 data = open(favicon, "rb").read()
712 self.putChild("favicon.ico", static.Data(data, "image/x-icon"))
713 if robots_txt:
714 data = open(robots_txt, "rb").read()
715 self.putChild("robots.txt", static.Data(data, "text/plain"))
716 self.putChild("", WaterfallStatusResource(categories))
OLDNEW
« no previous file with comments | « third_party/buildbot_7_12/buildbot/status/web/base.py ('k') | third_party/buildbot_7_12/buildbot/status/web/bg_gradient.jpg » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698