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

Side by Side Diff: third_party/buildbot_7_12/buildbot/README.chromium

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 URL: http://buildbot.net/trac
2 GIT: git://github.com/nsylvain/buildbot.git in branch "chromium"
3 Sources: http://github.com/nsylvain/buildbot/tree/chromium
4 Version: 0.7.12
5 License: GNU General Public License (GPL) Version 2
6
7 This is a forked copy of buildbot v0.7.12 with the modifications living
8 in github. To list the local modifications, use:
9 git log nsylvain/chromium ^v0.7.12
10
11
12 The following change has been made to fix issues that are now fixed in
13 a newer version of the upstream repository.
14
15 --- buildbot/status/web/console.py (revision 54225)
16 +++ buildbot/status/web/console.py (working copy)
17 @@ -431,11 +431,8 @@
18 builds.append(devBuild)
19
20 # Now break if we have enough builds.
21 - current_revision = self.getChangeForBuild(
22 - builder.getBuild(-1), revision)
23 - if self.comparator.isRevisionEarlier(
24 - devBuild, current_revision):
25 - break
26 + if int(got_rev) < int(revision):
27 + break;
28
29
30 Then made the following embelishment to allow the old behavior for
31 time based comparators.
32
33 --- third_party/buildbot_7_12/buildbot/status/web/console.py (revision 68693)
34 +++ third_party/buildbot_7_12/buildbot/status/web/console.py (working copy)
35 @@ -450,8 +450,15 @@
36 builds.append(devBuild)
37
38 # Now break if we have enough builds.
39 - if int(got_rev) < int(revision):
40 - break;
41 + if self.comparator.getSortingKey() == "when":
42 + current_revision = self.getChangeForBuild(
43 + builder.getBuild(-1), revision)
44 + if self.comparator.isRevisionEarlier(
45 + devBuild, current_revision):
46 + break
47 + else:
48 + if int(got_rev) < int(revision):
49 + break;
50
51
52 build = build.getPreviousBuild()
53
54
55 Ignore invalid utf-8 strings in logs.
56
57 --- third_party/buildbot_7_12/buildbot/status/web/console.py
58 +++ third_party/buildbot_7_12/buildbot/status/web/console.py
59 @@ -891,8 +891,11 @@ class ConsoleStatusResource(HtmlResource):
60 subs["date"] = revision.date
61 comment = revision.comments or ""
62 subs["comments"] = comment.replace('<', '&lt;').replace('>', '&gt;' )
63 - comment_quoted = urllib.quote(subs["comments"].encode("utf-8"))
64 -
65 + try:
66 + comment_quoted = urllib.quote(
67 + subs["comments"].decode("utf-8", "ignore").encode(
68 + "ascii", "xmlcharrefreplace"))
69 + except UnicodeEncodeError:
70 + # TODO(maruel): Figure out what's happening.
71 + comment_quoted = urllib.quote(subs["comments"].encode("utf-8"))
72 json += ( "{'revision': '%s', 'date': '%s', 'comments': '%s',"
73 "'results' : " ) % (subs["revision"], subs["date"],
74 comment_quoted)
75
76
77 The following patch was ported back from upstream adding log names and URLs to
78 the JSON output.
79
80 --- third_party/buildbot_7_12/buildbot/status/builder.py (revision 70505)
81 +++ third_party/buildbot_7_12/buildbot/status/builder.py (working copy)
82 @@ -1132,9 +1132,9 @@
83 result['eta'] = self.getETA()
84 result['urls'] = self.getURLs()
85 result['step_number'] = self.step_number
86 - # TODO(maruel): Move that to a sub-url or just publish the log_url
87 - # instead.
88 - #result['logs'] = self.getLogs()
89 + result['logs'] = [[l.getName(),
90 + self.build.builder.status.getURLForThing(l)]
91 + for l in self.getLogs()]
92 return result
93
94
95 @@ -1565,8 +1565,8 @@
96 result['slave'] = self.getSlavename()
97 # TODO(maruel): Add.
98 #result['test_results'] = self.getTestResults()
99 - # TODO(maruel): Include the url? It's too heavy otherwise.
100 - #result['logs'] = self.getLogs()
101 + result['logs'] = [[l.getName(),
102 + self.builder.status.getURLForThing(l)] for l in self.getLogs()]
103 result['eta'] = self.getETA()
104 result['steps'] = [bss.asDict() for bss in self.steps]
105 if self.getCurrentStep():
106
107
108 The following patch disables rss and atom output.
109
110 --- a/third_party/buildbot_7_12/buildbot/status/web/baseweb.py
111 +++ b/third_party/buildbot_7_12/buildbot/status/web/baseweb.py
112 @@ -594,8 +594,9 @@ class WebStatus(service.MultiService):
113 root.putChild(name, child_resource)
114
115 status = self.getStatus()
116 - root.putChild("rss", Rss20StatusResource(status))
117 - root.putChild("atom", Atom10StatusResource(status))
118 + # Disabled from Chromium.
119 + # root.putChild("rss", Rss20StatusResource(status))
120 + # root.putChild("atom", Atom10StatusResource(status))
121 root.putChild("json", JsonStatusResource(status))
122
123 self.site.resource = root
124
125
126 Fixes c.number is None
127 --- a/master/buildbot/status/web/status_json.py
128 +++ b/master/buildbot/status/web/status_json.py
129 @@ -547,15 +547,13 @@ class ChangesJsonResource(JsonResource):
130 def __init__(self, status, changes):
131 JsonResource.__init__(self, status)
132 for c in changes:
133 - # TODO(maruel): Problem with multiple changes with the same number.
134 - # Probably try server hack specific so we could fix it on this side
135 - # instead. But there is still the problem with multiple pollers fro m
136 - # different repo where the numbers could clash.
137 - number = str(c.number)
138 - while number in self.children:
139 - # TODO(maruel): Do something better?
140 - number = str(int(c.number)+1)
141 - self.putChild(number, ChangeJsonResource(status, c))
142 + # c.number can be None or clash another change if the change was
143 + # generated inside buildbot or if using multiple pollers.
144 + if c.number is not None and str(c.number) not in self.children:
145 + self.putChild(str(c.number), ChangeJsonResource(status, c))
146 + else:
147 + # Temporary hack since it creates information exposure.
148 + self.putChild(str(id(c)), ChangeJsonResource(status, c))
149
150 def asDict(self, request):
151 """Don't throw an exception when there is no child."""
152
153
154 Add extra parameters to HttpStatusPush as a very basic authentication mechanism.
155 --- a/third_party/buildbot_7_12/buildbot/status/status_push.py
156 +++ b/third_party/buildbot_7_12/buildbot/status/status_push.py
157 @@ -321,7 +321,7 @@ class HttpStatusPush(StatusPush):
158
159 def __init__(self, serverUrl, debug=None, maxMemoryItems=None,
160 maxDiskItems=None, chunkSize=200, maxHttpRequestSize=2**20,
161 - **kwargs):
162 + extra_post_params=None, **kwargs):
163 """
164 @serverUrl: Base URL to be used to push events notifications.
165 @maxMemoryItems: Maximum number of items to keep queued in memory.
166 @@ -334,6 +334,7 @@ class HttpStatusPush(StatusPush):
167 """
168 # Parameters.
169 self.serverUrl = serverUrl
170 + self.extra_post_params = extra_post_params or {}
171 self.debug = debug
172 self.chunkSize = chunkSize
173 self.lastPushWasSuccessful = True
174 @@ -371,7 +372,9 @@ class HttpStatusPush(StatusPush):
175 packets = json.dumps(items, indent=2, sort_keys=True)
176 else:
177 packets = json.dumps(items, separators=(',',':'))
178 - data = urllib.urlencode({'packets': packets})
179 + params = {'packets': packets}
180 + params.update(self.extra_post)
181 + data = urllib.urlencode(params)
182 if (not self.maxHttpRequestSize or
183 len(data) < self.maxHttpRequestSize):
184 return (data, items)
185 @@ -389,6 +392,8 @@ class HttpStatusPush(StatusPush):
186 def pushHttp(self):
187 """Do the HTTP POST to the server."""
188 (encoded_packets, items) = self.popChunk()
189 + if not self.serverUrl:
190 + return
191
192 def Success(result):
193 """Queue up next push."""
194
195
196 Add pendingBuilds
197 --- a/third_party/buildbot_7_12/buildbot/status/builder.py
198 +++ b/third_party/buildbot_7_12/buildbot/status/builder.py
199 @@ -2171,10 +2171,7 @@ class BuilderStatus(styles.Versioned):
200 result['cachedBuilds'] = cached_builds
201 result['currentBuilds'] = current_builds
202 result['state'] = self.getState()[0]
203 - # BuildRequestStatus doesn't have a number so display the SourceStamp.
204 - result['pendingBuilds'] = [
205 - b.getSourceStamp().asDict() for b in self.getPendingBuilds()
206 - ]
207 + result['pendingBuilds'] = len(self.getPendingBuilds())
208 return result
209
210
211 diff --git a/third_party/buildbot_7_12/buildbot/status/web/status_json.py b/thir d_party/buildbot_7_12/buildbot/status/web/status_json.
212 index e3aaafe..6c272a6 100644
213 --- a/third_party/buildbot_7_12/buildbot/status/web/status_json.py
214 +++ b/third_party/buildbot_7_12/buildbot/status/web/status_json.py
215 @@ -344,6 +344,20 @@ class HelpResource(HtmlResource):
216 return self.text
217
218
219 +class BuilderPendingBuildsJsonResource(JsonResource):
220 + help = """Describe pending builds for a builder.
221 +"""
222 + title = 'Builder'
223 +
224 + def __init__(self, status, builder_status):
225 + JsonResource.__init__(self, status)
226 + self.builder_status = builder_status
227 +
228 + def asDict(self, request):
229 + # buildbot.status.builder.BuilderStatus
230 + return [b.asDict() for b in self.builder_status.getPendingBuilds()]
231 +
232 +
233 class BuilderJsonResource(JsonResource):
234 help = """Describe a single builder.
235 """
236 @@ -355,6 +369,9 @@ class BuilderJsonResource(JsonResource):
237 self.putChild('builds', BuildsJsonResource(status, builder_status))
238 self.putChild('slaves', BuilderSlavesJsonResources(status,
239 builder_status))
240 + self.putChild(
241 + 'pendingBuilds',
242 + BuilderPendingBuildsJsonResource(status, builder_status))
243
244 def asDict(self, request):
245 # buildbot.status.builder.BuilderStatus
246
247
248 Increase console customization build range:
249
250 --- status/web/console.py (revision 75203)
251 +++ status/web/console.py (working copy)
252 @@ -971,10 +971,10 @@
253 # Keep only the revisions we care about.
254 # By default we process the last 40 revisions.
255 # If a dev name is passed, we look for the changes by this person in th e
256 - # last 80 revisions.
257 + # last 160 revisions.
258 numRevs = 40
259 if devName:
260 - numRevs *= 2
261 + numRevs *= 4
262 numBuilds = numRevs
263
264
265 The following patches add support for ANSI to HTML conversion of logs
266
267 Index: status/web/ansi2html.py
268 ===================================================================
269 --- status/web/ansi2html.py (revision 0)
270 +++ status/web/ansi2html.py (revision 0)
271 @@ -0,0 +1,161 @@
272 +# Copyright (c) 2011 The Chromium Authors. All rights reserved.
273 +# Use of this source code is governed by a BSD-style license that can be
274 +# found in the LICENSE file.
275 +
276 +import cStringIO
277 +import re
278 +
279 +DEFAULTS = {
280 + 'color' : 'white',
281 + 'background-color' : 'black',
282 + 'font-weight' : 'normal',
283 + 'text-decoration' : 'none',
284 +}
285 +
286 +
287 +class Ansi2HTML:
288 + """Class for converting text streams with ANSI codes into html"""
289 +
290 + ANSIEscape = '['
291 +
292 + ANSIAttributes = {
293 + 0 : ['color:' + DEFAULTS['color'],
294 + 'font-weight:' + DEFAULTS['font-weight'],
295 + 'text-decoration:' + DEFAULTS['text-decoration'],
296 + 'background-color:' + DEFAULTS['background-color']], # reset
297 + 1 : ['font-weight:bold'],
298 + 2 : ['font-weight:lighter'],
299 + 4 : ['text-decoration:underline'],
300 + 5 : ['text-decoration:blink'],
301 + 7 : [], # invert attribute?
302 + 8 : [], # invisible attribute?
303 + 30 : ['color:black'],
304 + 31 : ['color:red'],
305 + 32 : ['color:green'],
306 + 33 : ['color:yellow'],
307 + 34 : ['color:blue'],
308 + 35 : ['color:magenta'],
309 + 36 : ['color:cyan'],
310 + 37 : ['color:white'],
311 + 39 : ['color:' + DEFAULTS['color']],
312 + 40 : ['background-color:black'],
313 + 41 : ['background-color:red'],
314 + 42 : ['background-color:green'],
315 + 43 : ['background-color:yellow'],
316 + 44 : ['background-color:blue'],
317 + 45 : ['background-color:magenta'],
318 + 46 : ['background-color:cyan'],
319 + 47 : ['background-color:white'],
320 + 49 : ['background-color:' + DEFAULTS['background-color']],
321 + }
322 +
323 + def __init__(self):
324 + self.ctx = {}
325 + # Send a 0 code, resetting ctx to defaults.
326 + self.attrib('0')
327 + # Prepare a regexp recognizing all ANSI codes.
328 + code_src = '|'.join(self.ANSICodes)
329 + # This captures non-greedy code argument and code itself, both grouped.
330 + self.code_re = re.compile("(.*?)(" + code_src + ")")
331 +
332 + def noop(self, arg):
333 + """Noop code, for ANSI codes that have no html equivalent."""
334 + return ''
335 +
336 + def attrib(self, arg):
337 + """Text atribute code"""
338 + if arg == '':
339 + # Apparently, empty code argument means reset (0).
340 + arg = '0'
341 + for attr in arg.split(";"):
342 + try:
343 + for change in self.ANSIAttributes[int(attr)]:
344 + pieces = change.split(":")
345 + self.ctx[pieces[0]] = pieces[1]
346 + except KeyError:
347 + # Invalid key? Hmmm.
348 + return 'color:red">ANSI code not found: ' + \
349 + arg + '<font style="color:' + self.ctx['color']
350 + return self.printStyle()
351 +
352 + ANSICodes = {
353 + 'H' : noop, # cursor_pos, # ESC[y,xH - Cursor position y,x
354 + 'A' : noop, # cursor_up, # ESC[nA - Cursor Up n lines
355 + 'B' : noop, # cursor_down, # ESC[nB - Cursor Down n lines
356 + 'C' : noop, # cursor_forward, # ESC[nC - Cursor Forward n characters
357 + 'D' : noop, # cursor_backward, # ESC[nD - Cursor Backward n characters
358 + 'f' : noop, # cursor_xy, # ESC[y;xf - Cursor pos y,x (infrequent)
359 + 'R' : noop, # cursor_report, # ESC[y;xR - Cursor position report y,x
360 + 'n' : noop, # device_status, # ESC[6n - Dev status report (cursor pos)
361 + 's' : noop, # save_cursor, # ESC[s - Save cursor position
362 + 'u' : noop, # restore_cursor, # ESC[u - Restore cursor position
363 + 'J' : noop, # clrscr, # ESC[2J - Erase display
364 + 'K' : noop, # erase2eol, # ESC[K - Erase to end of line
365 + 'L' : noop, # insertlines, # ESC[nL - Inserts n blank lines at cursor
366 + 'M' : noop, # deletelines, # ESC[nM - Deletes n lines including cursor
367 + '@' : noop, # insertchars, # ESC[n@ - Inserts n blank chars at cursor
368 + 'P' : noop, # deletechars, # ESC[nP - Deletes n chars including cursor
369 + 'y' : noop, # translate, # ESC[n;ny - Output char translate
370 + 'p' : noop, # key_reassign, #ESC["str"p - Keyboard Key Reassignment
371 + 'm' : attrib, # ESC[n;n;...nm - Set attributes
372 + }
373 +
374 + def printStyle(self, showDefaults=False):
375 + """Returns a text representing the style of the current context."""
376 + style = ''
377 + for attr in DEFAULTS:
378 + if self.ctx[attr] != DEFAULTS[attr] or showDefaults:
379 + style += attr + ':' + self.ctx[attr] + ';'
380 + return style
381 +
382 + def printHtmlHeader(self, title):
383 + text = '<html><head><title>%s</title></head>' % title
384 + text += '<body bgcolor="%s"><pre>' % DEFAULTS['background-color']
385 + return text
386 +
387 + def printHtmlFooter(self):
388 + return '</pre></body></html>'
389 +
390 + def printHeader(self):
391 + """Envelopes everything into defaults <font> tag and opens a stub."""
392 + self.attrib("0") # this means reset to default
393 + return '<font style="%s"><font>' % self.printStyle(showDefaults=True)
394 +
395 + def printFooter(self):
396 + """Closes both stub and envelope font tags."""
397 + return '</font></font>'
398 +
399 + def parseBlock(self, string):
400 + """Takes a block of text and transform into html"""
401 + output = cStringIO.StringIO()
402 + skipfirst = True
403 + # Splitting by ANSIEscape turns the line into following elements:
404 + # arg,code,text
405 + # First two change the context, text is carried.
406 + for block in string.split(self.ANSIEscape):
407 + if not block:
408 + # First block is empty -> the line starts with escape code.
409 + skipfirst = False
410 + continue
411 +
412 + if skipfirst:
413 + # The line doesn't start with escape code -> skip first block.
414 + output.write(block)
415 + skipfirst = False
416 + continue
417 +
418 + match = self.code_re.match(block)
419 + if not match:
420 + # If there's no match, it is the line end. Don't parse it.
421 + output.write(block)
422 + continue
423 +
424 + parseFunc = self.ANSICodes[match.group(2)]
425 + # Replace ANSI codes with </font><font> sequence
426 + output.write('</font><font style="')
427 + output.write(parseFunc(self, match.group(1)))
428 + output.write('">')
429 + # Output the text
430 + output.write(block.split(match.group(2),1)[1])
431 +
432 + return output.getvalue()
433
434
435 Index: status/web/logs.py
436 ===================================================================
437 --- status/web/logs.py (revision 95541)
438 +++ status/web/logs.py (working copy)
439 @@ -9,6 +9,7 @@
440 from buildbot import interfaces
441 from buildbot.status import builder
442 from buildbot.status.web.base import IHTMLLog, HtmlResource
443 +from buildbot.status.web.ansi2html import Ansi2HTML
444
445
446 textlog_stylesheet = """
447 @@ -59,7 +60,7 @@
448 # it, so we can afford to track the request in the Resource.
449 implements(IHTMLLog)
450
451 - asText = False
452 + printAs = "html"
453 subscribed = False
454
455 def __init__(self, original):
456 @@ -67,9 +68,13 @@
457 self.original = original
458
459 def getChild(self, path, req):
460 - if path == "text":
461 - self.asText = True
462 + if path == "ansi":
463 + self.ansiParser = Ansi2HTML()
464 +
465 + if path == "text" or path == "ansi":
466 + self.printAs = path
467 return self
468 +
469 return HtmlResource.getChild(self, path, req)
470
471 def htmlHeader(self, request):
472 @@ -80,6 +85,8 @@
473 data += "<body vlink=\"#800080\">\n"
474 texturl = request.childLink("text")
475 data += '<a href="%s">(view as text)</a><br />\n' % texturl
476 + ansiurl = request.childLink("ansi")
477 + data += '<a href="%s">(view as ansi)</a><br />\n' % ansiurl
478 data += "<pre>\n"
479 return data
480
481 @@ -90,9 +97,12 @@
482 if type >= len(builder.ChunkTypes) or type < 0:
483 # non-std channel, don't display
484 continue
485 - if self.asText:
486 + if self.printAs == "text":
487 if type != builder.HEADER:
488 data += entry
489 + elif self.printAs == "ansi":
490 + if type != builder.HEADER:
491 + data += self.ansiParser.parseBlock(entry)
492 else:
493 data += spanfmt % (builder.ChunkTypes[type],
494 html.escape(entry))
495 @@ -104,7 +114,7 @@
496 return data
497
498 def render_HEAD(self, request):
499 - if self.asText:
500 + if self.printAs == "text":
501 request.setHeader("content-type", "text/plain")
502 else:
503 request.setHeader("content-type", "text/html")
504 @@ -116,13 +126,16 @@
505 def render_GET(self, req):
506 self.req = req
507
508 - if self.asText:
509 + if self.printAs == "text":
510 req.setHeader("content-type", "text/plain")
511 else:
512 req.setHeader("content-type", "text/html")
513
514 - if not self.asText:
515 + if self.printAs == "html":
516 req.write(self.htmlHeader(req))
517 + if self.printAs == "ansi":
518 + req.write(self.ansiParser.printHtmlHeader("Log File Contents"))
519 + req.write(self.ansiParser.printHeader())
520
521 self.original.subscribeConsumer(ChunkConsumer(req, self))
522 return server.NOT_DONE_YET
523 @@ -131,8 +144,11 @@
524 if not self.req:
525 return
526 try:
527 - if not self.asText:
528 + if self.printAs == "html":
529 self.req.write(self.htmlFooter())
530 + if self.printAs == "ansi":
531 + self.req.write(self.ansiParser.printFooter())
532 + self.req.write(self.ansiParser.printHtmlFooter())
533 self.req.finish()
534 except pb.DeadReferenceError:
535 pass
536
537
538
539 Fix chrome-bot mis-syncs.
540
541 Index: buildbot/changes/svnpoller.py
542 ===================================================================
543 --- buildbot/changes/svnpoller.py
544 +++ buildbot/changes/svnpoller.py
545 @@ -367,6 +367,19 @@ class SVNPoller(base.ChangeSource, util.ComparableMixin):
546 break
547 new_logentries.append(el)
548 new_logentries.reverse() # return oldest first
549 +
550 + # If the newest commit's author is chrome-bot, skip this commit. This
551 + # is a guard to ensure that we don't poll on our mirror while it could
552 + # be mid-sync. In that case, the author data could be wrong and would
553 + # look like it was a commit by chrome-bot@google.com. A downside: the
554 + # chrome-bot account may have a legitimate commit. This should not
555 + # happen generally, so we're okay waiting to see it until there's a
556 + # later commit with a non-chrome-bot author.
557 + if len(new_logentries) > 0:
558 + if new_logentries[-1].getAttribute("author") == 'chrome-bot@google.co m':
559 + new_logentries.pop(-1)
560 + mostRecent = int(logentries[1].getAttribute("revision"))
561 +
562 return (mostRecent, new_logentries)
563
564 def get_new_logentries(self, logentries):
OLDNEW
« no previous file with comments | « third_party/buildbot_7_12/buildbot/README ('k') | third_party/buildbot_7_12/buildbot/README.w32 » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698