Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / findit / match_set.py
1 # Copyright 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
8 from threading import Lock
9
10 import crash_utils
11
12
13 REVIEW_URL_PATTERN = re.compile(r'Review URL:( *)(.*)')
14
15
16 class Match(object):
17   """Represents a match entry.
18
19   A match is a CL that is suspected to have caused the crash. A match object
20   contains information about files it changes, their authors, etc.
21
22   Attributes:
23     is_reverted: True if this CL is reverted by other CL.
24     revert_of: If this CL is a revert of some other CL, a revision number/
25                git hash of that CL.
26     crashed_line_numbers: The list of lines that caused crash for this CL.
27     function_list: The list of functions that caused the crash.
28     min_distance: The minimum distance between the lines that CL changed and
29                   lines that caused the crash.
30     changed_files: The list of files that the CL changed.
31     changed_file_urls: The list of URLs for the file.
32     author: The author of the CL.
33     component_name: The name of the component that this CL belongs to.
34     stack_frame_indices: For files that caused crash, list of where in the
35                          stackframe they occur.
36     rank: The highest priority among the files the CL changes. Priority = 1
37           if it changes the crashed line, and priority = 2 if it is a simple
38           file change.
39     priorities: A list of priorities for each of the changed file.
40     reivision_url: The revision URL of the CL.
41     review_url: The codereview URL that reviews this CL.
42     reviewers: The list of people that reviewed this CL.
43     reason: The reason why this CL is suspected.
44   """
45   REVERT_PATTERN = re.compile(r'(revert\w*) r?(\d+)', re.I)
46
47   def __init__(self, revision, component_name):
48     self.is_reverted = False
49     self.revert_of = None
50     self.crashed_line_numbers = []
51     self.function_list = []
52     self.min_distance = crash_utils.INFINITY
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.rank = crash_utils.INFINITY
59     self.priorities = []
60     self.revision_url = revision['url']
61     self.review_url = ''
62     self.reviewers = []
63     self.reason = None
64
65   def ParseMessage(self, message, codereview_api_url):
66     """Parses the message.
67
68     It checks the message to extract the code review website and list of
69     reviewers, and it also checks if the CL is a revert of another CL.
70
71     Args:
72       message: The message to parse.
73       codereview_api_url: URL to retrieve codereview data from.
74     """
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(2)
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           logging.warning('Failed to retrieve code review information from %s',
90                           url)
91           continue
92
93         # Load the JSON from the string, and get the list of reviewers.
94         code_review = crash_utils.LoadJSON(json_string)
95         if code_review:
96           self.reviewers = code_review['reviewers']
97
98       # Check if this CL is a revert of other CL.
99       if line.lower().startswith('revert'):
100         self.is_reverted = True
101
102         # Check if the line says what CL this CL is a revert of.
103         revert = self.REVERT_PATTERN.match(line)
104         if revert:
105           self.revert_of = revert.group(2)
106         return
107
108
109 class MatchSet(object):
110   """Represents a set of matches.
111
112   Attributes:
113     matches: A map from CL to a match object.
114     cls_to_ignore: A set of CLs to ignore.
115     matches_lock: A lock guarding matches dictionary.
116   """
117
118   def __init__(self, codereview_api_url):
119     self.codereview_api_url = codereview_api_url
120     self.matches = {}
121     self.cls_to_ignore = set()
122     self.matches_lock = Lock()
123
124   def RemoveRevertedCLs(self):
125     """Removes CLs that are revert."""
126     for cl in self.matches:
127       if cl in self.cls_to_ignore:
128         del self.matches[cl]