Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(565)

Side by Side Diff: tools/findit/matchset.py

Issue 421223003: [Findit] Plain objects to represent the returned result from running the algorithm, (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« tools/findit/blame.py ('K') | « tools/findit/blame.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 import re
stgao 2014/08/04 20:44:57 Add a new line before this one.
jeun 2014/08/06 21:33:04 Done.
5 from threading import Lock
6 import findit_for_crash_utils as findit_utils
stgao 2014/08/04 20:44:57 seems not up-to-day.
jeun 2014/08/06 21:33:05 Done.
7
8 LINE_CHANGE_PRIORITY = 1
9 FILE_CHANGE_PRIORITY = 2
10 pl = Lock()
stgao 2014/08/04 20:44:57 Please use full name.
jeun 2014/08/06 21:33:05 Done.
11
12
13 class MatchSet(object):
14 """Represents a set of matches."""
15
16 def __init__(self, codereview_api_url):
17 self.codereview_api_url = codereview_api_url
18 self.matches = {}
19 self.cls_to_avoid = set()
20 self.matches_lock = Lock()
21
22 def GenerateMatchEntry(
stgao 2014/08/04 20:44:58 I think this function is closely-related to the al
jeun 2014/08/06 21:33:05 We can talk about this. I feel like this function
23 self, revisions, cl, file_path, file_name, function, component,
24 crashed_lines, stack_frame_index, file_action, repository_parser):
25 """Generates a match object.
26
27 A match is a CL that is suspected to have caused the crash. A match object
stgao 2014/08/04 20:44:57 It might be better to move the Match class up to t
jeun 2014/08/06 21:33:04 Done.
28 contains a line that the file crashed, a name of the function, the minimum
29 distance from the crashed line and the line this file changed, list of the
30 files that this CL changes, URLs of the files the CL changes, the author of
31 the CL, the component, list of the stack numbers,the priority of the CL,
32 review address and reviewers.
33
34 Args:
35 revisions: a dictionary mapping cl's number to the revision information,
36 as returned from ParseRevisions
stgao 2014/08/04 20:44:57 ParseRevisions is unclear here.
jeun 2014/08/06 21:33:04 Done.
37 cl: a SVN revision number or git hash
38 file_path: path of the file
39 file_name: a name of the file that this CL might be the culprit cl
40 function: function that caused an crash
41 component: a component the file is from
42 crashed_lines: a list of the lines in the file that caused the crash
43 stack_frame_index: a list of positions of this file within a stack
44 file_action: whether file is modified, added or deleted
45 repository_parser: a parser object to parse line diff
46 """
47 # Check if this CL should be avoided
48 self.matches_lock.acquire()
49 if cl in self.cls_to_avoid:
stgao 2014/08/04 20:44:57 avoid -> ignore?
jeun 2014/08/06 21:33:05 Done.
50 self.matches_lock.release()
51 return
52
53 # If this CL is not already identified as suspected, create a new entry.
54 if cl not in self.matches:
55 revision = revisions[cl]
56 match = Match(revision, component)
57 message = revisions[cl]['message']
58 match.ParseMessage(message, self.codereview_api_url)
stgao 2014/08/04 20:44:58 This function call will be time-consuming as it is
jeun 2014/08/06 21:33:04 Done.
59
60 # If this match is a revert, add to the set of CLs to be avoided
61 if match.isrevert:
62 self.cls_to_avoid.add(cl)
63
64 # If this match has info on what CL it is reverted from, add that CL
65 if match.revert_of:
66 self.cls_to_avoid.add(match.revert_of)
stgao 2014/08/04 20:44:58 What if the cl revert_of was already analyzed and
jeun 2014/08/06 21:33:05 I remove all reverts at the end again.
67
68 self.matches_lock.release()
69 return
70 self.matches[cl] = match
71
72 # Else, bring in the existing result
73 else:
74 match = self.matches[cl]
75
76 self.matches_lock.release()
stgao 2014/08/04 20:44:57 If code above raise an exception, the lock won't b
jeun 2014/08/06 21:33:04 Done.
77
78 # Parse line diff information for this file
79 (diff_url, changed_line_numbers, changed_line_contents) = (
80 repository_parser.ParseLineDiff(file_path, component, file_action, cl))
81
82 # Find the intersection between the lines that this file crashed on and
83 # the changed lines
84 (line_intersection, stack_frame_index_intersection) = findit_utils.Intersect ion(
stgao 2014/08/04 20:44:58 style: > 80 chars.
jeun 2014/08/06 21:33:05 Done.
85 crashed_lines, stack_frame_index, changed_line_numbers)
86
87 # Find the minimum distance between the changed lines and crashed lines
88 min_distance = findit_utils.FindMinLineDistance(crashed_lines,
89 changed_line_numbers)
90
91 # Check whether this CL changes the crashed lines or not
92 if line_intersection:
93 priority = LINE_CHANGE_PRIORITY
94 else:
95 priority = FILE_CHANGE_PRIORITY
96
97 # Add the parsed information to the object
98 with self.matches_lock:
99 match.line_of_crash.append(line_intersection)
100 match.file.append(file_name)
101
102 # Update the min distance only if it is less than the current one
103 if min_distance < match.min_distance:
104 match.min_distance = min_distance
105
106 # If this CL does not change the crashed line, all occurrence of this
107 # file in the stack has the same significance
108 if not stack_frame_index_intersection:
109 stack_frame_index_intersection = stack_frame_index
110 match.stack_frame_index.append(stack_frame_index_intersection)
111 match.file_url.append(diff_url)
112
113 # Only record the highest rank of this CL
114 if priority < match.rank:
115 match.rank = priority
116 match.priorities.append(priority)
117 match.function.append(function)
118
119 def RemoveReverts(self):
120 """Removes CLs that are revert."""
121 for cl in self.matches:
122 if cl in self.cls_to_avoid:
123 del self.matches[cl]
124
125
126 class Match(object):
127 """Represents a match entry.
128
129 Attributes:
130 line_of_crash: list of lines that caused crash for this CL
131 function: list of functions that caused the crash
132 min_distance: minimum difference between the lines that CL changed and
133 lines that caused the crash
134 file: list of files that the CL changed
stgao 2014/08/04 20:44:58 files?
jeun 2014/08/06 21:33:05 Done.
135 file_url: list of URLs for the file
stgao 2014/08/04 20:44:57 file_urls?
jeun 2014/08/06 21:33:05 Done.
136 owner: owner of the CL
137 component: component that this CL belongs to
138 stack_frame_index: for files that caused crash, list of where in the
stgao 2014/08/04 20:44:57 The name doesn't indicate it is a list.
jeun 2014/08/06 21:33:04 Done.
139 stackframe they occur
140 rank: the highest priority among the files the CL changes
stgao 2014/08/04 20:44:57 What's the concept of priority here? Would you min
jeun 2014/08/06 21:33:05 Done.
141 priorities: for each files, whether it changes the crashed line or is a
142 simple file change
143 url: URL of the CL
144 review_address: a codereview address that reviews this CL
stgao 2014/08/04 20:44:57 review_url?
jeun 2014/08/06 21:33:05 Done.
145 reviewers: list of people that reviewed this CL
146 reason: reason why this CL is suspected
147 """
148 REVERT_PATTERN = re.compile(r'(revert\w*) r?(\d+)', re.I)
149
150 def __init__(self, revision, component):
151 self.isrevert = False
152 self.revert_of = None
153 self.line_of_crash = []
154 self.function = []
155 self.min_distance = float('inf')
156 self.file = []
157 self.file_url = []
158 self.owner = revision['author']
159 self.component = component
160 self.stack_frame_index = []
161 self.rank = float('inf')
162 self.priorities = []
163 self.url = revision['url']
164 self.review_address = 'N/A'
165 self.reviewers = ['N/A']
166 self.reason = None
167
168 def ParseMessage(self, message, codereview_api_url):
169 """Parses the message.
170
171 It checks the message to extract the code review website and list of
172 reviewers, and it also checks if the CL is a revert of another CL.
173
174 Args:
175 message: a message to parse
176 codereview_api_url: URL to retrieve codereview data from
177 """
178 for line in message.splitlines():
179 line = line.strip()
180
181 # Check if the line has the code review information
182 if line.startswith('Review URL: '):
183
184 # Get review number for the code review site from the line
185 parts = line.split('Review URL: ')
186 self.review_address = parts[1].strip()
187 review_number = self.review_address.split('/')[-1]
stgao 2014/08/04 20:44:57 Usually, it is called issue number.
jeun 2014/08/06 21:33:04 Done.
188
189 # Get JSON from the code review site, ignore the line if it fails
190 url = codereview_api_url % review_number
191 json_string = findit_utils.GetDataFromURL(url)
192 if not json_string:
193 print 'Failed to retrieve code review information from %s' % url
194 continue
195
196 # Load the JSON from the string, and get the list of reviewers
197 code_review = findit_utils.LoadJSON(json_string)
198 if code_review:
199 self.reviewers = code_review['reviewers']
200
201 # Check if this CL is a revert of other CL
202 if line.lower().startswith('revert'):
203 self.isrevert = True
204
205 # Check if the line says what CL this CL is a revert of
206 revert = self.REVERT_PATTERN.match(line)
207 if revert:
208 self.revert_of = revert.group(2)
209 return
OLDNEW
« tools/findit/blame.py ('K') | « tools/findit/blame.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698