Home | History | Annotate | Download | only in findit
      1 # Copyright (c) 2014 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import re
      6 
      7 from threading import Lock
      8 
      9 import crash_utils
     10 
     11 
     12 REVIEW_URL_PATTERN = re.compile(r'Review URL:( *)(.*?)/(\d+)')
     13 
     14 
     15 class Match(object):
     16   """Represents a match entry.
     17 
     18   A match is a CL that is suspected to have caused the crash. A match object
     19   contains information about files it changes, their authors, etc.
     20 
     21   Attributes:
     22     is_revert: True if this CL is reverted by other CL.
     23     revert_of: If this CL is a revert of some other CL, a revision number/
     24                git hash of that CL.
     25     crashed_line_numbers: The list of lines that caused crash for this CL.
     26     function_list: The list of functions that caused the crash.
     27     min_distance: The minimum distance between the lines that CL changed and
     28                   lines that caused the crash.
     29     changed_files: The list of files that the CL changed.
     30     changed_file_urls: The list of URLs for the file.
     31     author: The author of the CL.
     32     component_name: The name of the component that this CL belongs to.
     33     stack_frame_indices: For files that caused crash, list of where in the
     34                          stackframe they occur.
     35     priorities: A list of priorities for each of the changed file. A priority
     36                 is 1 if the file changes a crashed line, and 2 if it changes
     37                 the file but not the crashed line.
     38     reivision_url: The revision URL of the CL.
     39     review_url: The codereview URL that reviews this CL.
     40     reviewers: The list of people that reviewed this CL.
     41     reason: The reason why this CL is suspected.
     42   """
     43   REVERT_PATTERN = re.compile(r'(revert\w*) r?(\d+)', re.I)
     44 
     45   def __init__(self, revision, component_name):
     46     self.is_revert = False
     47     self.revert_of = None
     48     self.message = None
     49     self.crashed_line_numbers = []
     50     self.function_list = []
     51     self.min_distance = crash_utils.INFINITY
     52     self.min_distance_info = None
     53     self.changed_files = []
     54     self.changed_file_urls = []
     55     self.author = revision['author']
     56     self.component_name = component_name
     57     self.stack_frame_indices = []
     58     self.priorities = []
     59     self.revision_url = revision['url']
     60     self.review_url = ''
     61     self.reviewers = []
     62     self.reason = None
     63 
     64   def ParseMessage(self, message, codereview_api_url):
     65     """Parses the message.
     66 
     67     It checks the message to extract the code review website and list of
     68     reviewers, and it also checks if the CL is a revert of another CL.
     69 
     70     Args:
     71       message: The message to parse.
     72       codereview_api_url: URL to retrieve codereview data from.
     73     """
     74     self.message = message
     75     for line in message.splitlines():
     76       line = line.strip()
     77       review_url_line_match = REVIEW_URL_PATTERN.match(line)
     78 
     79       # Check if the line has the code review information.
     80       if review_url_line_match:
     81 
     82         # Get review number for the code review site from the line.
     83         issue_number = review_url_line_match.group(3)
     84 
     85         # Get JSON from the code review site, ignore the line if it fails.
     86         url = codereview_api_url % issue_number
     87         json_string = crash_utils.GetDataFromURL(url)
     88         if not json_string:
     89           continue
     90 
     91         # Load the JSON from the string, and get the list of reviewers.
     92         code_review = crash_utils.LoadJSON(json_string)
     93         if code_review:
     94           self.reviewers = code_review['reviewers']
     95 
     96       # Check if this CL is a revert of other CL.
     97       if line.lower().startswith('revert'):
     98         self.is_revert = True
     99 
    100         # Check if the line says what CL this CL is a revert of.
    101         revert = self.REVERT_PATTERN.match(line)
    102         if revert:
    103           self.revert_of = revert.group(2)
    104         return
    105 
    106 
    107 class MatchSet(object):
    108   """Represents a set of matches.
    109 
    110   Attributes:
    111     matches: A map from CL to a match object.
    112     cls_to_ignore: A set of CLs to ignore.
    113     matches_lock: A lock guarding matches dictionary.
    114   """
    115 
    116   def __init__(self, codereview_api_url):
    117     self.codereview_api_url = codereview_api_url
    118     self.matches = {}
    119     self.cls_to_ignore = set()
    120     self.matches_lock = Lock()
    121 
    122   def RemoveRevertedCLs(self):
    123     """Removes CLs that are revert."""
    124     for cl in self.matches:
    125       if cl in self.cls_to_ignore:
    126         del self.matches[cl]
    127