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

Side by Side Diff: tools/findit/blame.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
« no previous file with comments | « no previous file | tools/findit/matchset.py » ('j') | tools/findit/matchset.py » ('J')
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 from threading import Lock, Thread
stgao 2014/08/04 20:44:56 Please add an empty line before this one.
jeun 2014/08/06 21:33:03 Done.
5
6 import findit_for_crash_utils as findit_utils
stgao 2014/08/04 20:44:56 Seems not up-to-day.
jeun 2014/08/06 21:33:03 Done.
7 import gitparser
8 import svnparser
stgao 2014/08/04 20:44:56 Hmm, why we use the parsers here? I remember blam
jeun 2014/08/06 21:33:04 I have changed the code that parsers do not use th
9 import utils
10
11
12 class Blame(object):
13 """Represents a blame object.
14
15 The object contains blame information for one line of stack, and this
16 information is shown when there are no CLs that change the crashing files.
17 Attributes:
18 content: the content of the line to find the blame for
19 component: the component this line is in
20 stack_frame_index: stack frame index of this file
21 file_name: name of the file
22 line: line that caused a crash
stgao 2014/08/04 20:44:56 line_number?
jeun 2014/08/06 21:33:03 Done.
23 author: the author of this line on the latest revision
24 crash_revision: revision that caused the crash
25 revision: the latest revision of this line before the crash revision
26 url: url of this revision
stgao 2014/08/04 20:44:56 url to the file change or the whole CL change?
jeun 2014/08/06 21:33:04 This revision, the whole CL change.
stgao 2014/08/09 19:51:02 In that case, please update the documentation here
jeun 2014/08/12 18:17:33 Done.
27 regression: the regression range of the component, if it exists
28
29 """
30
31 def __init__(self, content, component, stack_frame_index, file_name, line,
32 author, crash_revision, revision, url, regression):
33 # Set all the variables from the arguments
stgao 2014/08/04 20:44:56 Style: should end with a dot.
jeun 2014/08/06 21:33:03 Done.
34 self.content = content
35 self.component = component
36 self.stack_frame_index = stack_frame_index
37 self.file = file_name
38 self.line = line
39 self.author = author
40 self.revision = revision
41 self.url = url
42 self.regression = regression
43 self.distance = float('inf')
44 revision = int(revision)
45
46 # Calculate the distance, where it measures how far the last revision is
47 # from the regression range
48 if regression:
49 range1 = int(regression[0])
50 range2 = int(regression[1])
51 self.distance = min(abs(range1 - revision), abs(range2 - revision))
52
53 # If the regression is in SVN but it does not have regression info, check
54 # how far the last revision is from crash revision
55 elif not utils.IsGitHash(crash_revision):
56 self.distance = abs(int(crash_revision) - revision)
57
58
59 class BlameList(object):
60 """Represents a list of blame objects.
61
62 Thread-safe.
63 """
64
65 def __init__(self):
66 self.blame_list = []
67 self.blame_list_lock = Lock()
68
69 def __getitem__(self, index):
70 return self.blame_list[index]
71
72 def AddBlame(self, blame):
73 """Adds blame object to the set."""
74 with self.blame_list_lock:
75 self.blame_list.append(blame)
76
77 def sort(self, key=None):
78 return self.blame_list.sort(key=key)
79
80 def FindBlame(self, callstack, crash_revision_dic, revision_range_dic,
81 url_map):
82 """Given a stack within a stacktrace, retrieves blame information.
83
84 Only either first 10 or the length of stack, whichever is shorter,
stgao 2014/08/04 20:44:56 How about making it configurable?
jeun 2014/08/06 21:33:03 Done.
85 results are returned.
86
87 Args:
88 callstack: a list of stacktrace lines
89 crash_revision_dic: a dictionary that maps component to its crash revision
90 revision_range_dic: a dictionary that maps component to its revision range
91 url_map: a map from repository type to urls
92
93 Returns:
94 a list of blame object
stgao 2014/08/04 20:44:56 indent?
jeun 2014/08/06 21:33:04 Done.
95 """
96 # Only return blame information for first 10 frames
97 stack_list = callstack.GetFirstN(10)
98
99 threads = []
100 # Iterate through frames in stack
101 for stacktrace_line in stack_list:
102
stgao 2014/08/04 20:44:57 This empty line could be removed.
jeun 2014/08/06 21:33:03 Done.
103 # If the component this line is from does not have a crash revision,
104 # It is not possible to get blame information so ignore this line
105 component = stacktrace_line.component
106 if component not in crash_revision_dic:
107 continue
108
109 crash_revision = crash_revision_dic[component]
110 regression = None
111 is_svn = not utils.IsGitHash(crash_revision)
112
113 # If the revision is in SVN, and if revision information is available,
114 # get it. Not for Git because we cannot calculate the distance
stgao 2014/08/04 20:44:56 style: no ending dot. It is a common issue in thi
jeun 2014/08/06 21:33:04 Done.
115 if is_svn:
116 repository_parser = svnparser.SVNParser(url_map['svn'])
117 if revision_range_dic and component in revision_range_dic:
118 regression = revision_range_dic[component]
119 else:
120 repository_parser = gitparser.GitParser(url_map['git'])
121
122 # Generate blame entry, one thread for one entry
123 blame_thread = Thread(
124 target=self.__GenerateBlameList,
125 args=[repository_parser, stacktrace_line, crash_revision, regression])
126 threads.append(blame_thread)
127 blame_thread.start()
128
129 # Join the results before returning
130 for blame_thread in threads:
131 blame_thread.join()
stgao 2014/08/04 20:44:57 It seems nothing is returned. If this is intended,
jeun 2014/08/06 21:33:04 Done.
132
133 def __GenerateBlameList(self, repository_parser, stacktrace_line,
stgao 2014/08/04 20:44:56 This function generate a single Blame only. The na
jeun 2014/08/06 21:33:03 Done.
134 crash_revision, regression):
135 """Generates blame list from the arguments."""
136 stack_frame_index = stacktrace_line.stack_frame_index
137 component = stacktrace_line.component
138 file_name = stacktrace_line.file_name
139 file_path = stacktrace_line.file_path
140 line = stacktrace_line.crashed_line
141
142 blame = repository_parser.ParseBlameInfo(
143 stack_frame_index, component, file_name, file_path, line,
144 crash_revision, regression)
145
146 if blame:
147 self.AddBlame(blame)
148
149 def PrettifyBlame(self):
150 """Returns a string representation of blame results.
151
152 Returns:
153 a string representation of blame_list
154 """
155 blame_list = self.blame_list
156 return_string = []
157 return_string.append('Below are the blame information of the stacktrace.\n')
158 return_string.append('[\n')
159
160 # If blame info is not available, return the message
161 if not blame_list:
162 return_string.append('No Blame Information Available.\n')
163 return ''.join(return_string)
164
165 # Sort the blame list by its distance, and its position in stack
166 blame_list.sort(key=lambda blame: (blame.diff, blame.stack))
stgao 2014/08/04 20:44:56 blame.diff?
jeun 2014/08/06 21:33:03 changed to distance
167
168 for blame in blame_list:
169
stgao 2014/08/04 20:44:57 This empty line could be removed.
jeun 2014/08/06 21:33:03 Done.
170 # If regression information is available, do some filtering
171 if blame.regression:
172 regressed = blame.regression
173
174 # Discards results that are too far from the regression range.
175 # For example, if regression is 10000:11000, it is very not
176 # likely that a commit from revision 1000 would have caused a crash.
177 if blame.distance > int(regressed[0]) / 4 and blame.distance > int(
178 regressed[1]) / 4:
179 continue
180
181 return_string.append(' {\n')
182 return_string.append(
183 ' suspected_cl: %s\n' % findit_utils.AddHyperlink(
184 blame.revision,
185 blame.url))
186 return_string.append(' component: %s\n' % blame.component)
187 return_string.append(' owner: %s\n' % blame.author)
188 reason = (
189 'The CL changes line %s of file %s from stack %d.' %
190 (blame.line, blame.file, blame.stack))
191 return_string.append(' reason: %s\n' % reason)
192 if blame.content:
193 return_string.append(' content: %s\n' % blame.content)
194 return_string.append(' }\n')
195
196 return_string.append(']\n')
197 return_string.append('-------------------------------------------\n')
198 return ''.join(return_string)
OLDNEW
« no previous file with comments | « no previous file | tools/findit/matchset.py » ('j') | tools/findit/matchset.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698