Index: third_party/buildbot_7_12/buildbot/README.chromium |
diff --git a/third_party/buildbot_7_12/buildbot/README.chromium b/third_party/buildbot_7_12/buildbot/README.chromium |
deleted file mode 100644 |
index df1eff88b16d71f4382dc9117138da70605120e0..0000000000000000000000000000000000000000 |
--- a/third_party/buildbot_7_12/buildbot/README.chromium |
+++ /dev/null |
@@ -1,564 +0,0 @@ |
-URL: http://buildbot.net/trac |
-GIT: git://github.com/nsylvain/buildbot.git in branch "chromium" |
-Sources: http://github.com/nsylvain/buildbot/tree/chromium |
-Version: 0.7.12 |
-License: GNU General Public License (GPL) Version 2 |
- |
-This is a forked copy of buildbot v0.7.12 with the modifications living |
-in github. To list the local modifications, use: |
- git log nsylvain/chromium ^v0.7.12 |
- |
- |
-The following change has been made to fix issues that are now fixed in |
-a newer version of the upstream repository. |
- |
---- buildbot/status/web/console.py (revision 54225) |
-+++ buildbot/status/web/console.py (working copy) |
-@@ -431,11 +431,8 @@ |
- builds.append(devBuild) |
- |
- # Now break if we have enough builds. |
-- current_revision = self.getChangeForBuild( |
-- builder.getBuild(-1), revision) |
-- if self.comparator.isRevisionEarlier( |
-- devBuild, current_revision): |
-- break |
-+ if int(got_rev) < int(revision): |
-+ break; |
- |
- |
-Then made the following embelishment to allow the old behavior for |
-time based comparators. |
- |
---- third_party/buildbot_7_12/buildbot/status/web/console.py (revision 68693) |
-+++ third_party/buildbot_7_12/buildbot/status/web/console.py (working copy) |
-@@ -450,8 +450,15 @@ |
- builds.append(devBuild) |
- |
- # Now break if we have enough builds. |
-- if int(got_rev) < int(revision): |
-- break; |
-+ if self.comparator.getSortingKey() == "when": |
-+ current_revision = self.getChangeForBuild( |
-+ builder.getBuild(-1), revision) |
-+ if self.comparator.isRevisionEarlier( |
-+ devBuild, current_revision): |
-+ break |
-+ else: |
-+ if int(got_rev) < int(revision): |
-+ break; |
- |
- |
- build = build.getPreviousBuild() |
- |
- |
-Ignore invalid utf-8 strings in logs. |
- |
---- third_party/buildbot_7_12/buildbot/status/web/console.py |
-+++ third_party/buildbot_7_12/buildbot/status/web/console.py |
-@@ -891,8 +891,11 @@ class ConsoleStatusResource(HtmlResource): |
- subs["date"] = revision.date |
- comment = revision.comments or "" |
- subs["comments"] = comment.replace('<', '<').replace('>', '>') |
-- comment_quoted = urllib.quote(subs["comments"].encode("utf-8")) |
-- |
-+ try: |
-+ comment_quoted = urllib.quote( |
-+ subs["comments"].decode("utf-8", "ignore").encode( |
-+ "ascii", "xmlcharrefreplace")) |
-+ except UnicodeEncodeError: |
-+ # TODO(maruel): Figure out what's happening. |
-+ comment_quoted = urllib.quote(subs["comments"].encode("utf-8")) |
- json += ( "{'revision': '%s', 'date': '%s', 'comments': '%s'," |
- "'results' : " ) % (subs["revision"], subs["date"], |
- comment_quoted) |
- |
- |
-The following patch was ported back from upstream adding log names and URLs to |
-the JSON output. |
- |
---- third_party/buildbot_7_12/buildbot/status/builder.py (revision 70505) |
-+++ third_party/buildbot_7_12/buildbot/status/builder.py (working copy) |
-@@ -1132,9 +1132,9 @@ |
- result['eta'] = self.getETA() |
- result['urls'] = self.getURLs() |
- result['step_number'] = self.step_number |
-- # TODO(maruel): Move that to a sub-url or just publish the log_url |
-- # instead. |
-- #result['logs'] = self.getLogs() |
-+ result['logs'] = [[l.getName(), |
-+ self.build.builder.status.getURLForThing(l)] |
-+ for l in self.getLogs()] |
- return result |
- |
- |
-@@ -1565,8 +1565,8 @@ |
- result['slave'] = self.getSlavename() |
- # TODO(maruel): Add. |
- #result['test_results'] = self.getTestResults() |
-- # TODO(maruel): Include the url? It's too heavy otherwise. |
-- #result['logs'] = self.getLogs() |
-+ result['logs'] = [[l.getName(), |
-+ self.builder.status.getURLForThing(l)] for l in self.getLogs()] |
- result['eta'] = self.getETA() |
- result['steps'] = [bss.asDict() for bss in self.steps] |
- if self.getCurrentStep(): |
- |
- |
-The following patch disables rss and atom output. |
- |
---- a/third_party/buildbot_7_12/buildbot/status/web/baseweb.py |
-+++ b/third_party/buildbot_7_12/buildbot/status/web/baseweb.py |
-@@ -594,8 +594,9 @@ class WebStatus(service.MultiService): |
- root.putChild(name, child_resource) |
- |
- status = self.getStatus() |
-- root.putChild("rss", Rss20StatusResource(status)) |
-- root.putChild("atom", Atom10StatusResource(status)) |
-+ # Disabled from Chromium. |
-+ # root.putChild("rss", Rss20StatusResource(status)) |
-+ # root.putChild("atom", Atom10StatusResource(status)) |
- root.putChild("json", JsonStatusResource(status)) |
- |
- self.site.resource = root |
- |
- |
-Fixes c.number is None |
---- a/master/buildbot/status/web/status_json.py |
-+++ b/master/buildbot/status/web/status_json.py |
-@@ -547,15 +547,13 @@ class ChangesJsonResource(JsonResource): |
- def __init__(self, status, changes): |
- JsonResource.__init__(self, status) |
- for c in changes: |
-- # TODO(maruel): Problem with multiple changes with the same number. |
-- # Probably try server hack specific so we could fix it on this side |
-- # instead. But there is still the problem with multiple pollers from |
-- # different repo where the numbers could clash. |
-- number = str(c.number) |
-- while number in self.children: |
-- # TODO(maruel): Do something better? |
-- number = str(int(c.number)+1) |
-- self.putChild(number, ChangeJsonResource(status, c)) |
-+ # c.number can be None or clash another change if the change was |
-+ # generated inside buildbot or if using multiple pollers. |
-+ if c.number is not None and str(c.number) not in self.children: |
-+ self.putChild(str(c.number), ChangeJsonResource(status, c)) |
-+ else: |
-+ # Temporary hack since it creates information exposure. |
-+ self.putChild(str(id(c)), ChangeJsonResource(status, c)) |
- |
- def asDict(self, request): |
- """Don't throw an exception when there is no child.""" |
- |
- |
-Add extra parameters to HttpStatusPush as a very basic authentication mechanism. |
---- a/third_party/buildbot_7_12/buildbot/status/status_push.py |
-+++ b/third_party/buildbot_7_12/buildbot/status/status_push.py |
-@@ -321,7 +321,7 @@ class HttpStatusPush(StatusPush): |
- |
- def __init__(self, serverUrl, debug=None, maxMemoryItems=None, |
- maxDiskItems=None, chunkSize=200, maxHttpRequestSize=2**20, |
-- **kwargs): |
-+ extra_post_params=None, **kwargs): |
- """ |
- @serverUrl: Base URL to be used to push events notifications. |
- @maxMemoryItems: Maximum number of items to keep queued in memory. |
-@@ -334,6 +334,7 @@ class HttpStatusPush(StatusPush): |
- """ |
- # Parameters. |
- self.serverUrl = serverUrl |
-+ self.extra_post_params = extra_post_params or {} |
- self.debug = debug |
- self.chunkSize = chunkSize |
- self.lastPushWasSuccessful = True |
-@@ -371,7 +372,9 @@ class HttpStatusPush(StatusPush): |
- packets = json.dumps(items, indent=2, sort_keys=True) |
- else: |
- packets = json.dumps(items, separators=(',',':')) |
-- data = urllib.urlencode({'packets': packets}) |
-+ params = {'packets': packets} |
-+ params.update(self.extra_post) |
-+ data = urllib.urlencode(params) |
- if (not self.maxHttpRequestSize or |
- len(data) < self.maxHttpRequestSize): |
- return (data, items) |
-@@ -389,6 +392,8 @@ class HttpStatusPush(StatusPush): |
- def pushHttp(self): |
- """Do the HTTP POST to the server.""" |
- (encoded_packets, items) = self.popChunk() |
-+ if not self.serverUrl: |
-+ return |
- |
- def Success(result): |
- """Queue up next push.""" |
- |
- |
-Add pendingBuilds |
---- a/third_party/buildbot_7_12/buildbot/status/builder.py |
-+++ b/third_party/buildbot_7_12/buildbot/status/builder.py |
-@@ -2171,10 +2171,7 @@ class BuilderStatus(styles.Versioned): |
- result['cachedBuilds'] = cached_builds |
- result['currentBuilds'] = current_builds |
- result['state'] = self.getState()[0] |
-- # BuildRequestStatus doesn't have a number so display the SourceStamp. |
-- result['pendingBuilds'] = [ |
-- b.getSourceStamp().asDict() for b in self.getPendingBuilds() |
-- ] |
-+ result['pendingBuilds'] = len(self.getPendingBuilds()) |
- return result |
- |
- |
-diff --git a/third_party/buildbot_7_12/buildbot/status/web/status_json.py b/third_party/buildbot_7_12/buildbot/status/web/status_json. |
-index e3aaafe..6c272a6 100644 |
---- a/third_party/buildbot_7_12/buildbot/status/web/status_json.py |
-+++ b/third_party/buildbot_7_12/buildbot/status/web/status_json.py |
-@@ -344,6 +344,20 @@ class HelpResource(HtmlResource): |
- return self.text |
- |
- |
-+class BuilderPendingBuildsJsonResource(JsonResource): |
-+ help = """Describe pending builds for a builder. |
-+""" |
-+ title = 'Builder' |
-+ |
-+ def __init__(self, status, builder_status): |
-+ JsonResource.__init__(self, status) |
-+ self.builder_status = builder_status |
-+ |
-+ def asDict(self, request): |
-+ # buildbot.status.builder.BuilderStatus |
-+ return [b.asDict() for b in self.builder_status.getPendingBuilds()] |
-+ |
-+ |
- class BuilderJsonResource(JsonResource): |
- help = """Describe a single builder. |
- """ |
-@@ -355,6 +369,9 @@ class BuilderJsonResource(JsonResource): |
- self.putChild('builds', BuildsJsonResource(status, builder_status)) |
- self.putChild('slaves', BuilderSlavesJsonResources(status, |
- builder_status)) |
-+ self.putChild( |
-+ 'pendingBuilds', |
-+ BuilderPendingBuildsJsonResource(status, builder_status)) |
- |
- def asDict(self, request): |
- # buildbot.status.builder.BuilderStatus |
- |
- |
-Increase console customization build range: |
- |
---- status/web/console.py (revision 75203) |
-+++ status/web/console.py (working copy) |
-@@ -971,10 +971,10 @@ |
- # Keep only the revisions we care about. |
- # By default we process the last 40 revisions. |
- # If a dev name is passed, we look for the changes by this person in the |
-- # last 80 revisions. |
-+ # last 160 revisions. |
- numRevs = 40 |
- if devName: |
-- numRevs *= 2 |
-+ numRevs *= 4 |
- numBuilds = numRevs |
- |
- |
-The following patches add support for ANSI to HTML conversion of logs |
- |
-Index: status/web/ansi2html.py |
-=================================================================== |
---- status/web/ansi2html.py (revision 0) |
-+++ status/web/ansi2html.py (revision 0) |
-@@ -0,0 +1,161 @@ |
-+# Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-+# Use of this source code is governed by a BSD-style license that can be |
-+# found in the LICENSE file. |
-+ |
-+import cStringIO |
-+import re |
-+ |
-+DEFAULTS = { |
-+ 'color' : 'white', |
-+ 'background-color' : 'black', |
-+ 'font-weight' : 'normal', |
-+ 'text-decoration' : 'none', |
-+} |
-+ |
-+ |
-+class Ansi2HTML: |
-+ """Class for converting text streams with ANSI codes into html""" |
-+ |
-+ ANSIEscape = '[' |
-+ |
-+ ANSIAttributes = { |
-+ 0 : ['color:' + DEFAULTS['color'], |
-+ 'font-weight:' + DEFAULTS['font-weight'], |
-+ 'text-decoration:' + DEFAULTS['text-decoration'], |
-+ 'background-color:' + DEFAULTS['background-color']], # reset |
-+ 1 : ['font-weight:bold'], |
-+ 2 : ['font-weight:lighter'], |
-+ 4 : ['text-decoration:underline'], |
-+ 5 : ['text-decoration:blink'], |
-+ 7 : [], # invert attribute? |
-+ 8 : [], # invisible attribute? |
-+ 30 : ['color:black'], |
-+ 31 : ['color:red'], |
-+ 32 : ['color:green'], |
-+ 33 : ['color:yellow'], |
-+ 34 : ['color:blue'], |
-+ 35 : ['color:magenta'], |
-+ 36 : ['color:cyan'], |
-+ 37 : ['color:white'], |
-+ 39 : ['color:' + DEFAULTS['color']], |
-+ 40 : ['background-color:black'], |
-+ 41 : ['background-color:red'], |
-+ 42 : ['background-color:green'], |
-+ 43 : ['background-color:yellow'], |
-+ 44 : ['background-color:blue'], |
-+ 45 : ['background-color:magenta'], |
-+ 46 : ['background-color:cyan'], |
-+ 47 : ['background-color:white'], |
-+ 49 : ['background-color:' + DEFAULTS['background-color']], |
-+ } |
-+ |
-+ def __init__(self): |
-+ self.ctx = {} |
-+ # Send a 0 code, resetting ctx to defaults. |
-+ self.attrib('0') |
-+ # Prepare a regexp recognizing all ANSI codes. |
-+ code_src = '|'.join(self.ANSICodes) |
-+ # This captures non-greedy code argument and code itself, both grouped. |
-+ self.code_re = re.compile("(.*?)(" + code_src + ")") |
-+ |
-+ def noop(self, arg): |
-+ """Noop code, for ANSI codes that have no html equivalent.""" |
-+ return '' |
-+ |
-+ def attrib(self, arg): |
-+ """Text atribute code""" |
-+ if arg == '': |
-+ # Apparently, empty code argument means reset (0). |
-+ arg = '0' |
-+ for attr in arg.split(";"): |
-+ try: |
-+ for change in self.ANSIAttributes[int(attr)]: |
-+ pieces = change.split(":") |
-+ self.ctx[pieces[0]] = pieces[1] |
-+ except KeyError: |
-+ # Invalid key? Hmmm. |
-+ return 'color:red">ANSI code not found: ' + \ |
-+ arg + '<font style="color:' + self.ctx['color'] |
-+ return self.printStyle() |
-+ |
-+ ANSICodes = { |
-+ 'H' : noop, # cursor_pos, # ESC[y,xH - Cursor position y,x |
-+ 'A' : noop, # cursor_up, # ESC[nA - Cursor Up n lines |
-+ 'B' : noop, # cursor_down, # ESC[nB - Cursor Down n lines |
-+ 'C' : noop, # cursor_forward, # ESC[nC - Cursor Forward n characters |
-+ 'D' : noop, # cursor_backward, # ESC[nD - Cursor Backward n characters |
-+ 'f' : noop, # cursor_xy, # ESC[y;xf - Cursor pos y,x (infrequent) |
-+ 'R' : noop, # cursor_report, # ESC[y;xR - Cursor position report y,x |
-+ 'n' : noop, # device_status, # ESC[6n - Dev status report (cursor pos) |
-+ 's' : noop, # save_cursor, # ESC[s - Save cursor position |
-+ 'u' : noop, # restore_cursor, # ESC[u - Restore cursor position |
-+ 'J' : noop, # clrscr, # ESC[2J - Erase display |
-+ 'K' : noop, # erase2eol, # ESC[K - Erase to end of line |
-+ 'L' : noop, # insertlines, # ESC[nL - Inserts n blank lines at cursor |
-+ 'M' : noop, # deletelines, # ESC[nM - Deletes n lines including cursor |
-+ '@' : noop, # insertchars, # ESC[n@ - Inserts n blank chars at cursor |
-+ 'P' : noop, # deletechars, # ESC[nP - Deletes n chars including cursor |
-+ 'y' : noop, # translate, # ESC[n;ny - Output char translate |
-+ 'p' : noop, # key_reassign, #ESC["str"p - Keyboard Key Reassignment |
-+ 'm' : attrib, # ESC[n;n;...nm - Set attributes |
-+ } |
-+ |
-+ def printStyle(self, showDefaults=False): |
-+ """Returns a text representing the style of the current context.""" |
-+ style = '' |
-+ for attr in DEFAULTS: |
-+ if self.ctx[attr] != DEFAULTS[attr] or showDefaults: |
-+ style += attr + ':' + self.ctx[attr] + ';' |
-+ return style |
-+ |
-+ def printHtmlHeader(self, title): |
-+ text = '<html><head><title>%s</title></head>' % title |
-+ text += '<body bgcolor="%s"><pre>' % DEFAULTS['background-color'] |
-+ return text |
-+ |
-+ def printHtmlFooter(self): |
-+ return '</pre></body></html>' |
-+ |
-+ def printHeader(self): |
-+ """Envelopes everything into defaults <font> tag and opens a stub.""" |
-+ self.attrib("0") # this means reset to default |
-+ return '<font style="%s"><font>' % self.printStyle(showDefaults=True) |
-+ |
-+ def printFooter(self): |
-+ """Closes both stub and envelope font tags.""" |
-+ return '</font></font>' |
-+ |
-+ def parseBlock(self, string): |
-+ """Takes a block of text and transform into html""" |
-+ output = cStringIO.StringIO() |
-+ skipfirst = True |
-+ # Splitting by ANSIEscape turns the line into following elements: |
-+ # arg,code,text |
-+ # First two change the context, text is carried. |
-+ for block in string.split(self.ANSIEscape): |
-+ if not block: |
-+ # First block is empty -> the line starts with escape code. |
-+ skipfirst = False |
-+ continue |
-+ |
-+ if skipfirst: |
-+ # The line doesn't start with escape code -> skip first block. |
-+ output.write(block) |
-+ skipfirst = False |
-+ continue |
-+ |
-+ match = self.code_re.match(block) |
-+ if not match: |
-+ # If there's no match, it is the line end. Don't parse it. |
-+ output.write(block) |
-+ continue |
-+ |
-+ parseFunc = self.ANSICodes[match.group(2)] |
-+ # Replace ANSI codes with </font><font> sequence |
-+ output.write('</font><font style="') |
-+ output.write(parseFunc(self, match.group(1))) |
-+ output.write('">') |
-+ # Output the text |
-+ output.write(block.split(match.group(2),1)[1]) |
-+ |
-+ return output.getvalue() |
- |
- |
-Index: status/web/logs.py |
-=================================================================== |
---- status/web/logs.py (revision 95541) |
-+++ status/web/logs.py (working copy) |
-@@ -9,6 +9,7 @@ |
- from buildbot import interfaces |
- from buildbot.status import builder |
- from buildbot.status.web.base import IHTMLLog, HtmlResource |
-+from buildbot.status.web.ansi2html import Ansi2HTML |
- |
- |
- textlog_stylesheet = """ |
-@@ -59,7 +60,7 @@ |
- # it, so we can afford to track the request in the Resource. |
- implements(IHTMLLog) |
- |
-- asText = False |
-+ printAs = "html" |
- subscribed = False |
- |
- def __init__(self, original): |
-@@ -67,9 +68,13 @@ |
- self.original = original |
- |
- def getChild(self, path, req): |
-- if path == "text": |
-- self.asText = True |
-+ if path == "ansi": |
-+ self.ansiParser = Ansi2HTML() |
-+ |
-+ if path == "text" or path == "ansi": |
-+ self.printAs = path |
- return self |
-+ |
- return HtmlResource.getChild(self, path, req) |
- |
- def htmlHeader(self, request): |
-@@ -80,6 +85,8 @@ |
- data += "<body vlink=\"#800080\">\n" |
- texturl = request.childLink("text") |
- data += '<a href="%s">(view as text)</a><br />\n' % texturl |
-+ ansiurl = request.childLink("ansi") |
-+ data += '<a href="%s">(view as ansi)</a><br />\n' % ansiurl |
- data += "<pre>\n" |
- return data |
- |
-@@ -90,9 +97,12 @@ |
- if type >= len(builder.ChunkTypes) or type < 0: |
- # non-std channel, don't display |
- continue |
-- if self.asText: |
-+ if self.printAs == "text": |
- if type != builder.HEADER: |
- data += entry |
-+ elif self.printAs == "ansi": |
-+ if type != builder.HEADER: |
-+ data += self.ansiParser.parseBlock(entry) |
- else: |
- data += spanfmt % (builder.ChunkTypes[type], |
- html.escape(entry)) |
-@@ -104,7 +114,7 @@ |
- return data |
- |
- def render_HEAD(self, request): |
-- if self.asText: |
-+ if self.printAs == "text": |
- request.setHeader("content-type", "text/plain") |
- else: |
- request.setHeader("content-type", "text/html") |
-@@ -116,13 +126,16 @@ |
- def render_GET(self, req): |
- self.req = req |
- |
-- if self.asText: |
-+ if self.printAs == "text": |
- req.setHeader("content-type", "text/plain") |
- else: |
- req.setHeader("content-type", "text/html") |
- |
-- if not self.asText: |
-+ if self.printAs == "html": |
- req.write(self.htmlHeader(req)) |
-+ if self.printAs == "ansi": |
-+ req.write(self.ansiParser.printHtmlHeader("Log File Contents")) |
-+ req.write(self.ansiParser.printHeader()) |
- |
- self.original.subscribeConsumer(ChunkConsumer(req, self)) |
- return server.NOT_DONE_YET |
-@@ -131,8 +144,11 @@ |
- if not self.req: |
- return |
- try: |
-- if not self.asText: |
-+ if self.printAs == "html": |
- self.req.write(self.htmlFooter()) |
-+ if self.printAs == "ansi": |
-+ self.req.write(self.ansiParser.printFooter()) |
-+ self.req.write(self.ansiParser.printHtmlFooter()) |
- self.req.finish() |
- except pb.DeadReferenceError: |
- pass |
- |
- |
- |
-Fix chrome-bot mis-syncs. |
- |
-Index: buildbot/changes/svnpoller.py |
-=================================================================== |
---- buildbot/changes/svnpoller.py |
-+++ buildbot/changes/svnpoller.py |
-@@ -367,6 +367,19 @@ class SVNPoller(base.ChangeSource, util.ComparableMixin): |
- break |
- new_logentries.append(el) |
- new_logentries.reverse() # return oldest first |
-+ |
-+ # If the newest commit's author is chrome-bot, skip this commit. This |
-+ # is a guard to ensure that we don't poll on our mirror while it could |
-+ # be mid-sync. In that case, the author data could be wrong and would |
-+ # look like it was a commit by chrome-bot@google.com. A downside: the |
-+ # chrome-bot account may have a legitimate commit. This should not |
-+ # happen generally, so we're okay waiting to see it until there's a |
-+ # later commit with a non-chrome-bot author. |
-+ if len(new_logentries) > 0: |
-+ if new_logentries[-1].getAttribute("author") == 'chrome-bot@google.com': |
-+ new_logentries.pop(-1) |
-+ mostRecent = int(logentries[1].getAttribute("revision")) |
-+ |
- return (mostRecent, new_logentries) |
- |
- def get_new_logentries(self, logentries): |