| Index: tools/compare_codereview.py
|
| diff --git a/tools/compare_codereview.py b/tools/compare_codereview.py
|
| index b39bfe2942bb7b687b07ba32a3689c77a3cf1284..a58b3c697bf2f105bbc70cd564bf6909b7d288ef 100755
|
| --- a/tools/compare_codereview.py
|
| +++ b/tools/compare_codereview.py
|
| @@ -23,373 +23,392 @@ import HTMLParser
|
|
|
|
|
| class CodeReviewHTMLParser(HTMLParser.HTMLParser):
|
| - """Parses CodeReview web page.
|
| + """Parses CodeReview web page.
|
|
|
| - Use the CodeReviewHTMLParser.parse static function to make use of
|
| - this class.
|
| + Use the CodeReviewHTMLParser.parse static function to make use of
|
| + this class.
|
|
|
| - This uses the HTMLParser class because it's the best thing in
|
| - Python's standard library. We need a little more power than a
|
| - regex. [Search for "You can't parse [X]HTML with regex." for more
|
| - information.
|
| + This uses the HTMLParser class because it's the best thing in
|
| + Python's standard library. We need a little more power than a
|
| + regex. [Search for "You can't parse [X]HTML with regex." for more
|
| + information.
|
| + """
|
| + # pylint: disable=I0011,R0904
|
| + @staticmethod
|
| + def parse(url):
|
| + """Parses a CodeReview web pages.
|
| +
|
| + Args:
|
| + url (string), a codereview URL like this:
|
| + 'https://codereview.chromium.org/?????????'.
|
| +
|
| + Returns:
|
| + A dictionary; the keys are bot_name strings, the values
|
| + are CodeReviewHTMLParser.Status objects
|
| + """
|
| + parser = CodeReviewHTMLParser()
|
| + try:
|
| + parser.feed(urllib2.urlopen(url).read())
|
| + except (urllib2.URLError,):
|
| + print >> sys.stderr, 'Error getting', url
|
| + return None
|
| + parser.close()
|
| + return parser.statuses
|
| +
|
| + # namedtuples are like lightweight structs in Python. The low
|
| + # overhead of a tuple, but the ease of use of an object.
|
| + Status = collections.namedtuple('Status', ['status', 'url'])
|
| +
|
| + def __init__(self):
|
| + HTMLParser.HTMLParser.__init__(self)
|
| + self._id = None
|
| + self._status = None
|
| + self._href = None
|
| + self._anchor_data = ''
|
| + self._currently_parsing_trybotdiv = False
|
| + # statuses is a dictionary of CodeReviewHTMLParser.Status
|
| + self.statuses = {}
|
| +
|
| + def handle_starttag(self, tag, attrs):
|
| + """Overrides the HTMLParser method to implement functionality.
|
| +
|
| + [[begin standard library documentation]]
|
| + This method is called to handle the start of a tag
|
| + (e.g. <div id="main">).
|
| +
|
| + The tag argument is the name of the tag converted to lower
|
| + case. The attrs argument is a list of (name, value) pairs
|
| + containing the attributes found inside the tag's <>
|
| + brackets. The name will be translated to lower case, and
|
| + quotes in the value have been removed, and character and
|
| + entity references have been replaced.
|
| +
|
| + For instance, for the tag <A HREF="http://www.cwi.nl/">, this
|
| + method would be called as handle_starttag('a', [('href',
|
| + 'http://www.cwi.nl/')]).
|
| + [[end standard library documentation]]
|
| """
|
| - # pylint: disable=I0011,R0904
|
| - @staticmethod
|
| - def parse(url):
|
| - """Parses a CodeReview web pages.
|
| -
|
| - Args:
|
| - url (string), a codereview URL like this:
|
| - 'https://codereview.chromium.org/?????????'.
|
| -
|
| - Returns:
|
| - A dictionary; the keys are bot_name strings, the values
|
| - are CodeReviewHTMLParser.Status objects
|
| - """
|
| - parser = CodeReviewHTMLParser()
|
| - try:
|
| - parser.feed(urllib2.urlopen(url).read())
|
| - except (urllib2.URLError,):
|
| - print >> sys.stderr, 'Error getting', url
|
| - return None
|
| - parser.close()
|
| - return parser.statuses
|
| -
|
| - # namedtuples are like lightweight structs in Python. The low
|
| - # overhead of a tuple, but the ease of use of an object.
|
| - Status = collections.namedtuple('Status', ['status', 'url'])
|
| -
|
| - def __init__(self):
|
| - HTMLParser.HTMLParser.__init__(self)
|
| - self._id = None
|
| - self._status = None
|
| - self._href = None
|
| - self._anchor_data = ''
|
| - self._currently_parsing_trybotdiv = False
|
| - # statuses is a dictionary of CodeReviewHTMLParser.Status
|
| - self.statuses = {}
|
| -
|
| - def handle_starttag(self, tag, attrs):
|
| - """Overrides the HTMLParser method to implement functionality.
|
| -
|
| - [[begin standard library documentation]]
|
| - This method is called to handle the start of a tag
|
| - (e.g. <div id="main">).
|
| -
|
| - The tag argument is the name of the tag converted to lower
|
| - case. The attrs argument is a list of (name, value) pairs
|
| - containing the attributes found inside the tag's <>
|
| - brackets. The name will be translated to lower case, and
|
| - quotes in the value have been removed, and character and
|
| - entity references have been replaced.
|
| -
|
| - For instance, for the tag <A HREF="http://www.cwi.nl/">, this
|
| - method would be called as handle_starttag('a', [('href',
|
| - 'http://www.cwi.nl/')]).
|
| - [[end standard library documentation]]
|
| - """
|
| - attrs = dict(attrs)
|
| - if tag == 'div':
|
| - # We are looking for <div id="tryjobdiv*">.
|
| - id_attr = attrs.get('id','')
|
| - if id_attr.startswith('tryjobdiv'):
|
| - self._id = id_attr
|
| - if (self._id and tag == 'a'
|
| - and 'build-result' in attrs.get('class', '').split()):
|
| - # If we are already inside a <div id="tryjobdiv*">, we
|
| - # look for a link if the form
|
| - # <a class="build-result" href="*">. Then we save the
|
| - # (non-standard) status attribute and the URL.
|
| - self._status = attrs.get('status')
|
| - self._href = attrs.get('href')
|
| - self._currently_parsing_trybotdiv = True
|
| - # Start saving anchor data.
|
| -
|
| - def handle_data(self, data):
|
| - """Overrides the HTMLParser method to implement functionality.
|
| -
|
| - [[begin standard library documentation]]
|
| - This method is called to process arbitrary data (e.g. text
|
| - nodes and the content of <script>...</script> and
|
| - <style>...</style>).
|
| - [[end standard library documentation]]
|
| - """
|
| - # Save the text inside the <a></a> tags. Assume <a> tags
|
| - # aren't nested.
|
| - if self._currently_parsing_trybotdiv:
|
| - self._anchor_data += data
|
| -
|
| - def handle_endtag(self, tag):
|
| - """Overrides the HTMLParser method to implement functionality.
|
| -
|
| - [[begin standard library documentation]]
|
| - This method is called to handle the end tag of an element
|
| - (e.g. </div>). The tag argument is the name of the tag
|
| - converted to lower case.
|
| - [[end standard library documentation]]
|
| - """
|
| - if tag == 'a' and self._status:
|
| - # We take the accumulated self._anchor_data and save it as
|
| - # the bot name.
|
| - bot = self._anchor_data.strip()
|
| - stat = CodeReviewHTMLParser.Status(status=self._status,
|
| - url=self._href)
|
| - if bot:
|
| - # Add to accumulating dictionary.
|
| - self.statuses[bot] = stat
|
| - # Reset state to search for the next bot.
|
| - self._currently_parsing_trybotdiv = False
|
| - self._anchor_data = ''
|
| - self._status = None
|
| - self._href = None
|
| + attrs = dict(attrs)
|
| + if tag == 'div':
|
| + # We are looking for <div id="tryjobdiv*">.
|
| + id_attr = attrs.get('id','')
|
| + if id_attr.startswith('tryjobdiv'):
|
| + self._id = id_attr
|
| + if (self._id and tag == 'a'
|
| + and 'build-result' in attrs.get('class', '').split()):
|
| + # If we are already inside a <div id="tryjobdiv*">, we
|
| + # look for a link if the form
|
| + # <a class="build-result" href="*">. Then we save the
|
| + # (non-standard) status attribute and the URL.
|
| + self._status = attrs.get('status')
|
| + self._href = attrs.get('href')
|
| + self._currently_parsing_trybotdiv = True
|
| + # Start saving anchor data.
|
| +
|
| + def handle_data(self, data):
|
| + """Overrides the HTMLParser method to implement functionality.
|
| +
|
| + [[begin standard library documentation]]
|
| + This method is called to process arbitrary data (e.g. text
|
| + nodes and the content of <script>...</script> and
|
| + <style>...</style>).
|
| + [[end standard library documentation]]
|
| + """
|
| + # Save the text inside the <a></a> tags. Assume <a> tags
|
| + # aren't nested.
|
| + if self._currently_parsing_trybotdiv:
|
| + self._anchor_data += data
|
| +
|
| + def handle_endtag(self, tag):
|
| + """Overrides the HTMLParser method to implement functionality.
|
| +
|
| + [[begin standard library documentation]]
|
| + This method is called to handle the end tag of an element
|
| + (e.g. </div>). The tag argument is the name of the tag
|
| + converted to lower case.
|
| + [[end standard library documentation]]
|
| + """
|
| + if tag == 'a' and self._status:
|
| + # We take the accumulated self._anchor_data and save it as
|
| + # the bot name.
|
| + bot = self._anchor_data.strip()
|
| + stat = CodeReviewHTMLParser.Status(status=self._status,
|
| + url=self._href)
|
| + if bot:
|
| + # Add to accumulating dictionary.
|
| + self.statuses[bot] = stat
|
| + # Reset state to search for the next bot.
|
| + self._currently_parsing_trybotdiv = False
|
| + self._anchor_data = ''
|
| + self._status = None
|
| + self._href = None
|
|
|
|
|
| class BuilderHTMLParser(HTMLParser.HTMLParser):
|
| - """parses Trybot web pages.
|
| + """parses Trybot web pages.
|
|
|
| - Use the BuilderHTMLParser.parse static function to make use of
|
| - this class.
|
| -
|
| - This uses the HTMLParser class because it's the best thing in
|
| - Python's standard library. We need a little more power than a
|
| - regex. [Search for "You can't parse [X]HTML with regex." for more
|
| - information.
|
| - """
|
| - # pylint: disable=I0011,R0904
|
| - @staticmethod
|
| - def parse(url):
|
| - """Parses a Trybot web page.
|
| -
|
| - Args:
|
| - url (string), a trybot result URL.
|
| -
|
| - Returns:
|
| - An array of BuilderHTMLParser.Results, each a description
|
| - of failure results, along with an optional url
|
| - """
|
| - parser = BuilderHTMLParser()
|
| - try:
|
| - parser.feed(urllib2.urlopen(url).read())
|
| - except (urllib2.URLError,):
|
| - print >> sys.stderr, 'Error getting', url
|
| - return []
|
| - parser.close()
|
| - return parser.failure_results
|
| -
|
| - Result = collections.namedtuple('Result', ['text', 'url'])
|
| -
|
| - def __init__(self):
|
| - HTMLParser.HTMLParser.__init__(self)
|
| - self.failure_results = []
|
| - self._current_failure_result = None
|
| - self._divlevel = None
|
| - self._li_level = 0
|
| - self._li_data = ''
|
| - self._current_failure = False
|
| - self._failure_results_url = ''
|
| + Use the BuilderHTMLParser.parse static function to make use of
|
| + this class.
|
|
|
| - def handle_starttag(self, tag, attrs):
|
| - """Overrides the HTMLParser method to implement functionality.
|
| -
|
| - [[begin standard library documentation]]
|
| - This method is called to handle the start of a tag
|
| - (e.g. <div id="main">).
|
| -
|
| - The tag argument is the name of the tag converted to lower
|
| - case. The attrs argument is a list of (name, value) pairs
|
| - containing the attributes found inside the tag's <>
|
| - brackets. The name will be translated to lower case, and
|
| - quotes in the value have been removed, and character and
|
| - entity references have been replaced.
|
| -
|
| - For instance, for the tag <A HREF="http://www.cwi.nl/">, this
|
| - method would be called as handle_starttag('a', [('href',
|
| - 'http://www.cwi.nl/')]).
|
| - [[end standard library documentation]]
|
| - """
|
| - attrs = dict(attrs)
|
| - if tag == 'li':
|
| - # <li> tags can be nested. So we have to count the
|
| - # nest-level for backing out.
|
| - self._li_level += 1
|
| - return
|
| - if tag == 'div' and attrs.get('class') == 'failure result':
|
| - # We care about this sort of thing:
|
| - # <li>
|
| - # <li>
|
| - # <li>
|
| - # <div class="failure result">...</div>
|
| - # </li>
|
| - # </li>
|
| - # We want this text here.
|
| - # </li>
|
| - if self._li_level > 0:
|
| - self._current_failure = True # Tells us to keep text.
|
| - return
|
| -
|
| - if tag == 'a' and self._current_failure:
|
| - href = attrs.get('href')
|
| - # Sometimes we want to keep the stdio url. We always
|
| - # return it, just in case.
|
| - if href.endswith('/logs/stdio'):
|
| - self._failure_results_url = href
|
| -
|
| - def handle_data(self, data):
|
| - """Overrides the HTMLParser method to implement functionality.
|
| -
|
| - [[begin standard library documentation]]
|
| - This method is called to process arbitrary data (e.g. text
|
| - nodes and the content of <script>...</script> and
|
| - <style>...</style>).
|
| - [[end standard library documentation]]
|
| - """
|
| - if self._current_failure:
|
| - self._li_data += data
|
| -
|
| - def handle_endtag(self, tag):
|
| - """Overrides the HTMLParser method to implement functionality.
|
| -
|
| - [[begin standard library documentation]]
|
| - This method is called to handle the end tag of an element
|
| - (e.g. </div>). The tag argument is the name of the tag
|
| - converted to lower case.
|
| - [[end standard library documentation]]
|
| - """
|
| - if tag == 'li':
|
| - self._li_level -= 1
|
| - if 0 == self._li_level:
|
| - if self._current_failure:
|
| - result = self._li_data.strip()
|
| - first = result.split()[0]
|
| - if first:
|
| - result = re.sub(
|
| - r'^%s(\s+%s)+' % (first, first), first, result)
|
| - # Sometimes, it repeats the same thing
|
| - # multiple times.
|
| - result = re.sub(r'unexpected flaky.*', '', result)
|
| - # Remove some extra unnecessary text.
|
| - result = re.sub(r'\bpreamble\b', '', result)
|
| - result = re.sub(r'\bstdio\b', '', result)
|
| - url = self._failure_results_url
|
| - self.failure_results.append(
|
| - BuilderHTMLParser.Result(result, url))
|
| - self._current_failure_result = None
|
| - # Reset the state.
|
| - self._current_failure = False
|
| - self._li_data = ''
|
| - self._failure_results_url = ''
|
| + This uses the HTMLParser class because it's the best thing in
|
| + Python's standard library. We need a little more power than a
|
| + regex. [Search for "You can't parse [X]HTML with regex." for more
|
| + information.
|
| + """
|
| + # pylint: disable=I0011,R0904
|
| + @staticmethod
|
| + def parse(url):
|
| + """Parses a Trybot web page.
|
|
|
| + Args:
|
| + url (string), a trybot result URL.
|
|
|
| -def printer(indent, string):
|
| - """Print indented, wrapped text.
|
| + Returns:
|
| + An array of BuilderHTMLParser.Results, each a description
|
| + of failure results, along with an optional url
|
| """
|
| - def wrap_to(line, columns):
|
| - """Wrap a line to the given number of columns, return a list
|
| - of strings.
|
| - """
|
| - ret = []
|
| - nextline = ''
|
| - for word in line.split():
|
| - if nextline:
|
| - if len(nextline) + 1 + len(word) > columns:
|
| - ret.append(nextline)
|
| - nextline = word
|
| - else:
|
| - nextline += (' ' + word)
|
| - else:
|
| - nextline = word
|
| - if nextline:
|
| - ret.append(nextline)
|
| - return ret
|
| - out = sys.stdout
|
| - spacer = ' '
|
| - for line in string.split('\n'):
|
| - for i, wrapped_line in enumerate(wrap_to(line, 68 - (2 * indent))):
|
| - out.write(spacer * indent)
|
| - if i > 0:
|
| - out.write(spacer)
|
| - out.write(wrapped_line)
|
| - out.write('\n')
|
| - out.flush()
|
| + parser = BuilderHTMLParser()
|
| + try:
|
| + parser.feed(urllib2.urlopen(url).read())
|
| + except (urllib2.URLError,):
|
| + print >> sys.stderr, 'Error getting', url
|
| + return []
|
| + parser.close()
|
| + return parser.failure_results
|
| +
|
| + Result = collections.namedtuple('Result', ['text', 'url'])
|
| +
|
| + def __init__(self):
|
| + HTMLParser.HTMLParser.__init__(self)
|
| + self.failure_results = []
|
| + self._current_failure_result = None
|
| + self._divlevel = None
|
| + self._li_level = 0
|
| + self._li_data = ''
|
| + self._current_failure = False
|
| + self._failure_results_url = ''
|
| +
|
| + def handle_starttag(self, tag, attrs):
|
| + """Overrides the HTMLParser method to implement functionality.
|
| +
|
| + [[begin standard library documentation]]
|
| + This method is called to handle the start of a tag
|
| + (e.g. <div id="main">).
|
| +
|
| + The tag argument is the name of the tag converted to lower
|
| + case. The attrs argument is a list of (name, value) pairs
|
| + containing the attributes found inside the tag's <>
|
| + brackets. The name will be translated to lower case, and
|
| + quotes in the value have been removed, and character and
|
| + entity references have been replaced.
|
| +
|
| + For instance, for the tag <A HREF="http://www.cwi.nl/">, this
|
| + method would be called as handle_starttag('a', [('href',
|
| + 'http://www.cwi.nl/')]).
|
| + [[end standard library documentation]]
|
| + """
|
| + attrs = dict(attrs)
|
| + if tag == 'li':
|
| + # <li> tags can be nested. So we have to count the
|
| + # nest-level for backing out.
|
| + self._li_level += 1
|
| + return
|
| + if tag == 'div' and attrs.get('class') == 'failure result':
|
| + # We care about this sort of thing:
|
| + # <li>
|
| + # <li>
|
| + # <li>
|
| + # <div class="failure result">...</div>
|
| + # </li>
|
| + # </li>
|
| + # We want this text here.
|
| + # </li>
|
| + if self._li_level > 0:
|
| + self._current_failure = True # Tells us to keep text.
|
| + return
|
| +
|
| + if tag == 'a' and self._current_failure:
|
| + href = attrs.get('href')
|
| + # Sometimes we want to keep the stdio url. We always
|
| + # return it, just in case.
|
| + if href.endswith('/logs/stdio'):
|
| + self._failure_results_url = href
|
| +
|
| + def handle_data(self, data):
|
| + """Overrides the HTMLParser method to implement functionality.
|
| +
|
| + [[begin standard library documentation]]
|
| + This method is called to process arbitrary data (e.g. text
|
| + nodes and the content of <script>...</script> and
|
| + <style>...</style>).
|
| + [[end standard library documentation]]
|
| + """
|
| + if self._current_failure:
|
| + self._li_data += data
|
|
|
| + def handle_endtag(self, tag):
|
| + """Overrides the HTMLParser method to implement functionality.
|
|
|
| -def main(control_url, roll_url, verbosity=1):
|
| - """Compare two Codereview URLs
|
| + [[begin standard library documentation]]
|
| + This method is called to handle the end tag of an element
|
| + (e.g. </div>). The tag argument is the name of the tag
|
| + converted to lower case.
|
| + [[end standard library documentation]]
|
| + """
|
| + if tag == 'li':
|
| + self._li_level -= 1
|
| + if 0 == self._li_level:
|
| + if self._current_failure:
|
| + result = self._li_data.strip()
|
| + first = result.split()[0]
|
| + if first:
|
| + result = re.sub(
|
| + r'^%s(\s+%s)+' % (first, first), first, result)
|
| + # Sometimes, it repeats the same thing
|
| + # multiple times.
|
| + result = re.sub(r'unexpected flaky.*', '', result)
|
| + # Remove some extra unnecessary text.
|
| + result = re.sub(r'\bpreamble\b', '', result)
|
| + result = re.sub(r'\bstdio\b', '', result)
|
| + url = self._failure_results_url
|
| + self.failure_results.append(
|
| + BuilderHTMLParser.Result(result, url))
|
| + self._current_failure_result = None
|
| + # Reset the state.
|
| + self._current_failure = False
|
| + self._li_data = ''
|
| + self._failure_results_url = ''
|
|
|
| - Args:
|
| - control_url, roll_url: (strings) URL of the format
|
| - https://codereview.chromium.org/?????????
|
|
|
| - verbosity: (int) verbose level. 0, 1, or 2.
|
| +def printer(indent, string):
|
| + """Print indented, wrapped text.
|
| + """
|
| + def wrap_to(line, columns):
|
| + """Wrap a line to the given number of columns, return a list
|
| + of strings.
|
| """
|
| - # pylint: disable=I0011,R0914,R0912
|
| - control = CodeReviewHTMLParser.parse(control_url)
|
| - roll = CodeReviewHTMLParser.parse(roll_url)
|
| - all_bots = set(control) & set(roll) # Set intersection.
|
| - if not all_bots:
|
| - print >> sys.stderr, (
|
| - 'Error: control %s and roll %s have no common trybots.'
|
| - % (list(control), list(roll)))
|
| - return
|
| -
|
| - control_name = '[control %s]' % control_url.split('/')[-1]
|
| - roll_name = '[roll %s]' % roll_url.split('/')[-1]
|
| + ret = []
|
| + nextline = ''
|
| + for word in line.split():
|
| + if nextline:
|
| + if len(nextline) + 1 + len(word) > columns:
|
| + ret.append(nextline)
|
| + nextline = word
|
| + else:
|
| + nextline += (' ' + word)
|
| + else:
|
| + nextline = word
|
| + if nextline:
|
| + ret.append(nextline)
|
| + return ret
|
| + out = sys.stdout
|
| + spacer = ' '
|
| + for line in string.split('\n'):
|
| + for i, wrapped_line in enumerate(wrap_to(line, 68 - (2 * indent))):
|
| + out.write(spacer * indent)
|
| + if i > 0:
|
| + out.write(spacer)
|
| + out.write(wrapped_line)
|
| + out.write('\n')
|
| + out.flush()
|
|
|
| - out = sys.stdout
|
|
|
| - for bot in sorted(all_bots):
|
| - if (roll[bot].status == 'success'):
|
| - if verbosity > 1:
|
| - printer(0, '==%s==' % bot)
|
| - printer(1, 'OK')
|
| - continue
|
| +def main(control_url, roll_url, verbosity=1):
|
| + """Compare two Codereview URLs
|
| +
|
| + Args:
|
| + control_url, roll_url: (strings) URL of the format
|
| + https://codereview.chromium.org/?????????
|
| +
|
| + verbosity: (int) verbose level. 0, 1, or 2.
|
| + """
|
| + # pylint: disable=I0011,R0914,R0912
|
| + control = CodeReviewHTMLParser.parse(control_url)
|
| + roll = CodeReviewHTMLParser.parse(roll_url)
|
| + all_bots = set(control) & set(roll) # Set intersection.
|
| + if not all_bots:
|
| + print >> sys.stderr, (
|
| + 'Error: control %s and roll %s have no common trybots.'
|
| + % (list(control), list(roll)))
|
| + return
|
| +
|
| + control_name = '[control %s]' % control_url.split('/')[-1]
|
| + roll_name = '[roll %s]' % roll_url.split('/')[-1]
|
| +
|
| + out = sys.stdout
|
| +
|
| + for bot in sorted(all_bots):
|
| + if (roll[bot].status == 'success'):
|
| + if verbosity > 1:
|
| printer(0, '==%s==' % bot)
|
| + printer(1, 'OK')
|
| + continue
|
|
|
| - for (status, name, url) in (
|
| + if control[bot].status != 'failure' and roll[bot].status != 'failure':
|
| + continue
|
| + printer(0, '==%s==' % bot)
|
| +
|
| + formatted_results = []
|
| + for (status, name, url) in [
|
| (control[bot].status, control_name, control[bot].url),
|
| - (roll[bot].status, roll_name, roll[bot].url)):
|
| -
|
| - if status == 'failure':
|
| - printer(1, name)
|
| - results = BuilderHTMLParser.parse(url)
|
| - for result in results:
|
| - formatted_result = re.sub(
|
| - r'(\S*\.html) ', '\n__\g<1>\n', result.text)
|
| - # Strip runtimes.
|
| - formatted_result = re.sub(r'\(.*\)', '', formatted_result)
|
| - printer(2, formatted_result)
|
| - if ('compile' in result.text
|
| - or '...and more' in result.text):
|
| - printer(3, re.sub('/[^/]*$', '/', url) + result.url)
|
| - else:
|
| - printer(1, name)
|
| - printer(2, status)
|
| - out.write('\n')
|
| -
|
| - if verbosity > 0:
|
| - # Print out summary of all of the bots.
|
| - out.write('%11s %11s %4s %s\n\n' %
|
| - ('CONTROL', 'ROLL', 'DIFF', 'BOT'))
|
| - for bot in sorted(all_bots):
|
| - if roll[bot].status == 'success':
|
| - diff = ''
|
| - elif (control[bot].status == 'success' and
|
| - roll[bot].status == 'failure'):
|
| - diff = '!!!!'
|
| - elif ('pending' in control[bot].status or
|
| - 'pending' in roll[bot].status):
|
| - diff = '....'
|
| - else:
|
| - diff = '****'
|
| - out.write('%11s %11s %4s %s\n' % (
|
| - control[bot].status, roll[bot].status, diff, bot))
|
| - out.write('\n')
|
| - out.flush()
|
| + ( roll[bot].status, roll_name, roll[bot].url)]:
|
| + lines = []
|
| + if status == 'failure':
|
| + results = BuilderHTMLParser.parse(url)
|
| + for result in results:
|
| + formatted_result = re.sub(r'(\S*\.html) ', '\n__\g<1>\n', result.text)
|
| + # Strip runtimes.
|
| + formatted_result = re.sub(r'\(.*\)', '', formatted_result)
|
| + lines.append((2, formatted_result))
|
| + if ('compile' in result.text or '...and more' in result.text):
|
| + lines.append((3, re.sub('/[^/]*$', '/', url) + result.url))
|
| + formatted_results.append(lines)
|
| +
|
| + identical = formatted_results[0] == formatted_results[1]
|
| +
|
| +
|
| + for (formatted_result, (status, name, url)) in zip(
|
| + formatted_results,
|
| + [(control[bot].status, control_name, control[bot].url),
|
| + (roll[bot].status, roll_name, roll[bot].url)]):
|
| + if status != 'failure' and not identical:
|
| + printer(1, name)
|
| + printer(2, status)
|
| + elif status == 'failure':
|
| + if identical:
|
| + printer(1, control_name + ' and ' + roll_name + ' failed identically')
|
| + else:
|
| + printer(1, name)
|
| + for (indent, line) in formatted_result:
|
| + printer(indent, line)
|
| + if identical:
|
| + break
|
| + out.write('\n')
|
| +
|
| + if verbosity > 0:
|
| + # Print out summary of all of the bots.
|
| + out.write('%11s %11s %4s %s\n\n' %
|
| + ('CONTROL', 'ROLL', 'DIFF', 'BOT'))
|
| + for bot in sorted(all_bots):
|
| + if roll[bot].status == 'success':
|
| + diff = ''
|
| + elif (control[bot].status == 'success' and
|
| + roll[bot].status == 'failure'):
|
| + diff = '!!!!'
|
| + elif ('pending' in control[bot].status or
|
| + 'pending' in roll[bot].status):
|
| + diff = '....'
|
| + else:
|
| + diff = '****'
|
| + out.write('%11s %11s %4s %s\n' % (
|
| + control[bot].status, roll[bot].status, diff, bot))
|
| + out.write('\n')
|
| + out.flush()
|
|
|
| if __name__ == '__main__':
|
| - if len(sys.argv) < 3:
|
| - print >> sys.stderr, __doc__
|
| - exit(1)
|
| - main(sys.argv[1], sys.argv[2],
|
| - int(os.environ.get('COMPARE_CODEREVIEW_VERBOSITY', 1)))
|
| + if len(sys.argv) < 3:
|
| + print >> sys.stderr, __doc__
|
| + exit(1)
|
| + main(sys.argv[1], sys.argv[2],
|
| + int(os.environ.get('COMPARE_CODEREVIEW_VERBOSITY', 1)))
|
|
|
|
|