OLD | NEW |
(Empty) | |
| 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 logging |
| 6 import re |
| 7 from threading import Lock |
| 8 |
| 9 import crash_utils |
| 10 |
| 11 |
| 12 class Match(object): |
| 13 """Represents a match entry. |
| 14 |
| 15 A match is a CL that is suspected to have caused the crash. A match object |
| 16 contains information about files it changes, their authors, etc. |
| 17 |
| 18 Attributes: |
| 19 line_of_crash: The list of lines that caused crash for this CL. |
| 20 function: The list of functions that caused the crash. |
| 21 min_distance: The minimum difference between the lines that CL changed and |
| 22 lines that caused the crash. |
| 23 files: The list of files that the CL changed. |
| 24 file_urls: The list of URLs for the file. |
| 25 author: The author of the CL. |
| 26 component_name: The name of the component that this CL belongs to. |
| 27 stack_frame_indices: For files that caused crash, list of where in the |
| 28 stackframe they occur. |
| 29 rank: The highest priority among the files the CL changes. |
| 30 priorities: For each files, whether it changes the crashed line |
| 31 (priority = 1) or is a simple file change (priority = 2). |
| 32 reivision_url: The revision URL of the CL. |
| 33 review_url: The codereview URL that reviews this CL. |
| 34 reviewers: The list of people that reviewed this CL. |
| 35 reason: The reason why this CL is suspected. |
| 36 """ |
| 37 REVERT_PATTERN = re.compile(r'(revert\w*) r?(\d+)', re.I) |
| 38 |
| 39 def __init__(self, revision, component_name): |
| 40 self.is_reverted = False |
| 41 self.revert_of = None |
| 42 self.line_of_crash = [] |
| 43 self.function = [] |
| 44 self.min_distance = crash_utils.INFINITY |
| 45 self.files = [] |
| 46 self.file_urls = [] |
| 47 self.author = revision['author'] |
| 48 self.component_name = component_name |
| 49 self.stack_frame_indices = [] |
| 50 self.rank = crash_utils.INFINITY |
| 51 self.priorities = [] |
| 52 self.revision_url = revision['url'] |
| 53 self.review_url = 'N/A' |
| 54 self.reviewers = ['N/A'] |
| 55 self.reason = None |
| 56 |
| 57 def ParseMessage(self, message, codereview_api_url): |
| 58 """Parses the message. |
| 59 |
| 60 It checks the message to extract the code review website and list of |
| 61 reviewers, and it also checks if the CL is a revert of another CL. |
| 62 |
| 63 Args: |
| 64 message: The message to parse. |
| 65 codereview_api_url: URL to retrieve codereview data from. |
| 66 """ |
| 67 for line in message.splitlines(): |
| 68 line = line.strip() |
| 69 |
| 70 # Check if the line has the code review information. |
| 71 if line.startswith('Review URL: '): |
| 72 |
| 73 # Get review number for the code review site from the line. |
| 74 parts = line.split('Review URL: ') |
| 75 self.review_url = parts[1].strip() |
| 76 issue_number = self.review_url.split('/')[-1] |
| 77 |
| 78 # Get JSON from the code review site, ignore the line if it fails. |
| 79 url = codereview_api_url % issue_number |
| 80 json_string = crash_utils.GetDataFromURL(url) |
| 81 if not json_string: |
| 82 logging.warning('Failed to retrieve code review information from %s', |
| 83 url) |
| 84 continue |
| 85 |
| 86 # Load the JSON from the string, and get the list of reviewers. |
| 87 code_review = crash_utils.LoadJSON(json_string) |
| 88 if code_review: |
| 89 self.reviewers = code_review['reviewers'] |
| 90 |
| 91 # Check if this CL is a revert of other CL. |
| 92 if line.lower().startswith('revert'): |
| 93 self.is_reverted = True |
| 94 |
| 95 # Check if the line says what CL this CL is a revert of. |
| 96 revert = self.REVERT_PATTERN.match(line) |
| 97 if revert: |
| 98 self.revert_of = revert.group(2) |
| 99 return |
| 100 |
| 101 |
| 102 class MatchSet(object): |
| 103 """Represents a set of matches. |
| 104 |
| 105 Attributes: |
| 106 matches: A map from CL to a match object. |
| 107 cls_to_ignore: A set of CLs to ignore. |
| 108 matches_lock: A lock guarding matches dictionary. |
| 109 """ |
| 110 |
| 111 def __init__(self, codereview_api_url): |
| 112 self.codereview_api_url = codereview_api_url |
| 113 self.matches = {} |
| 114 self.cls_to_ignore = set() |
| 115 self.matches_lock = Lock() |
| 116 |
| 117 def RemoveReverts(self): |
| 118 """Removes CLs that are revert.""" |
| 119 for cl in self.matches: |
| 120 if cl in self.cls_to_ignore: |
| 121 del self.matches[cl] |
OLD | NEW |