| Index: tools/findit/match_set.py
|
| diff --git a/tools/findit/match_set.py b/tools/findit/match_set.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a22d0ef5303b01e541265c83b54cc2fe75bed271
|
| --- /dev/null
|
| +++ b/tools/findit/match_set.py
|
| @@ -0,0 +1,128 @@
|
| +# Copyright (c) 2014 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 logging
|
| +import re
|
| +
|
| +from threading import Lock
|
| +
|
| +import crash_utils
|
| +
|
| +
|
| +REVIEW_URL_PATTERN = re.compile(r'Review URL:( *)(.*)')
|
| +
|
| +
|
| +class Match(object):
|
| + """Represents a match entry.
|
| +
|
| + A match is a CL that is suspected to have caused the crash. A match object
|
| + contains information about files it changes, their authors, etc.
|
| +
|
| + Attributes:
|
| + is_reverted: True if this CL is reverted by other CL.
|
| + revert_of: If this CL is a revert of some other CL, a revision number/
|
| + git hash of that CL.
|
| + crashed_line_numbers: The list of lines that caused crash for this CL.
|
| + function_list: The list of functions that caused the crash.
|
| + min_distance: The minimum distance between the lines that CL changed and
|
| + lines that caused the crash.
|
| + changed_files: The list of files that the CL changed.
|
| + changed_file_urls: The list of URLs for the file.
|
| + author: The author of the CL.
|
| + component_name: The name of the component that this CL belongs to.
|
| + stack_frame_indices: For files that caused crash, list of where in the
|
| + stackframe they occur.
|
| + rank: The highest priority among the files the CL changes. Priority = 1
|
| + if it changes the crashed line, and priority = 2 if it is a simple
|
| + file change.
|
| + priorities: A list of priorities for each of the changed file.
|
| + reivision_url: The revision URL of the CL.
|
| + review_url: The codereview URL that reviews this CL.
|
| + reviewers: The list of people that reviewed this CL.
|
| + reason: The reason why this CL is suspected.
|
| + """
|
| + REVERT_PATTERN = re.compile(r'(revert\w*) r?(\d+)', re.I)
|
| +
|
| + def __init__(self, revision, component_name):
|
| + self.is_reverted = False
|
| + self.revert_of = None
|
| + self.crashed_line_numbers = []
|
| + self.function_list = []
|
| + self.min_distance = crash_utils.INFINITY
|
| + self.changed_files = []
|
| + self.changed_file_urls = []
|
| + self.author = revision['author']
|
| + self.component_name = component_name
|
| + self.stack_frame_indices = []
|
| + self.rank = crash_utils.INFINITY
|
| + self.priorities = []
|
| + self.revision_url = revision['url']
|
| + self.review_url = ''
|
| + self.reviewers = []
|
| + self.reason = None
|
| +
|
| + def ParseMessage(self, message, codereview_api_url):
|
| + """Parses the message.
|
| +
|
| + It checks the message to extract the code review website and list of
|
| + reviewers, and it also checks if the CL is a revert of another CL.
|
| +
|
| + Args:
|
| + message: The message to parse.
|
| + codereview_api_url: URL to retrieve codereview data from.
|
| + """
|
| + for line in message.splitlines():
|
| + line = line.strip()
|
| + review_url_line_match = REVIEW_URL_PATTERN.match(line)
|
| +
|
| + # Check if the line has the code review information.
|
| + if review_url_line_match:
|
| +
|
| + # Get review number for the code review site from the line.
|
| + issue_number = review_url_line_match.group(2)
|
| +
|
| + # Get JSON from the code review site, ignore the line if it fails.
|
| + url = codereview_api_url % issue_number
|
| + json_string = crash_utils.GetDataFromURL(url)
|
| + if not json_string:
|
| + logging.warning('Failed to retrieve code review information from %s',
|
| + url)
|
| + continue
|
| +
|
| + # Load the JSON from the string, and get the list of reviewers.
|
| + code_review = crash_utils.LoadJSON(json_string)
|
| + if code_review:
|
| + self.reviewers = code_review['reviewers']
|
| +
|
| + # Check if this CL is a revert of other CL.
|
| + if line.lower().startswith('revert'):
|
| + self.is_reverted = True
|
| +
|
| + # Check if the line says what CL this CL is a revert of.
|
| + revert = self.REVERT_PATTERN.match(line)
|
| + if revert:
|
| + self.revert_of = revert.group(2)
|
| + return
|
| +
|
| +
|
| +class MatchSet(object):
|
| + """Represents a set of matches.
|
| +
|
| + Attributes:
|
| + matches: A map from CL to a match object.
|
| + cls_to_ignore: A set of CLs to ignore.
|
| + matches_lock: A lock guarding matches dictionary.
|
| + """
|
| +
|
| + def __init__(self, codereview_api_url):
|
| + self.codereview_api_url = codereview_api_url
|
| + self.matches = {}
|
| + self.cls_to_ignore = set()
|
| + self.matches_lock = Lock()
|
| +
|
| + def RemoveRevertedCLs(self):
|
| + """Removes CLs that are revert."""
|
| + for cl in self.matches:
|
| + if cl in self.cls_to_ignore:
|
| + del self.matches[cl]
|
|
|