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

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

Issue 478763003: [Findit] Bug fixing and implemented some feature requests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed codereview and removed all references to logging 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
OLDNEW
1 # Copyright (c) 2014 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from threading import Lock, Thread 5 from threading import Lock, Thread
6 6
7 from common import utils 7 from common import utils
8 import crash_utils
8 9
9 10
10 class Blame(object): 11 class Blame(object):
11 """Represents a blame object. 12 """Represents a blame object.
12 13
13 The object contains blame information for one line of stack, and this 14 The object contains blame information for one line of stack, and this
14 information is shown when there are no CLs that change the crashing files. 15 information is shown when there are no CLs that change the crashing files.
15 Attributes: 16 Attributes:
16 line_content: The content of the line to find the blame for. 17 line_content: The content of the line to find the blame for.
17 component_name: The name of the component for this line. 18 component_name: The name of the component for this line.
18 stack_frame_index: The stack frame index of this file. 19 stack_frame_index: The stack frame index of this file.
19 file_name: The name of the file. 20 file_name: The name of the file.
20 line_number: The line that caused a crash. 21 line_number: The line that caused a crash.
21 author: The author of this line on the latest revision. 22 author: The author of this line on the latest revision.
22 crash_revision: The revision that caused the crash. 23 crash_revision: The revision that caused the crash.
23 revision: The latest revision of this line before the crash revision. 24 revision: The latest revision of this line before the crash revision.
24 url: The url of the change for the revision. 25 url: The url of the change for the revision.
25 range_start: The starting range of the regression for this component. 26 range_start: The starting range of the regression for this component.
26 range_end: The ending range of the regression. 27 range_end: The ending range of the regression.
27 28
28 """ 29 """
29 30
30 def __init__(self, line_content, component_name, stack_frame_index, 31 def __init__(self, line_content, component_name, stack_frame_index,
31 file_name, line_number, author, revision, 32 file_name, line_number, author, revision, message,
32 url, range_start, range_end): 33 url, range_start, range_end):
33 # Set all the variables from the arguments. 34 # Set all the variables from the arguments.
34 self.line_content = line_content 35 self.line_content = line_content
35 self.component_name = component_name 36 self.component_name = component_name
36 self.stack_frame_index = stack_frame_index 37 self.stack_frame_index = stack_frame_index
37 self.file = file_name 38 self.file = file_name
38 self.line_number = line_number 39 self.line_number = line_number
39 self.author = author 40 self.author = author
40 self.revision = revision 41 self.revision = revision
42 self.message = message
41 self.url = url 43 self.url = url
42 self.range_start = range_start 44 self.range_start = range_start
43 self.range_end = range_end 45 self.range_end = range_end
44 46
45 47
46 class BlameList(object): 48 class BlameList(object):
47 """Represents a list of blame objects. 49 """Represents a list of blame objects.
48 50
49 Thread-safe. 51 Thread-safe.
50 """ 52 """
51 53
52 def __init__(self): 54 def __init__(self):
53 self.blame_list = [] 55 self.blame_list = []
54 self.blame_list_lock = Lock() 56 self.blame_list_lock = Lock()
55 57
56 def __getitem__(self, index): 58 def __getitem__(self, index):
57 return self.blame_list[index] 59 return self.blame_list[index]
58 60
59 def FindBlame(self, callstack, crash_revision_dict, regression_dict, parsers, 61 def FindBlame(self, callstack, component_to_crash_revision_dict,
62 component_to_regression_dict, parsers,
60 top_n_frames=10): 63 top_n_frames=10):
61 """Given a stack within a stacktrace, retrieves blame information. 64 """Given a stack within a stacktrace, retrieves blame information.
62 65
63 Only either first 'top_n_frames' or the length of stack, whichever is 66 Only either first 'top_n_frames' or the length of stack, whichever is
64 shorter, results are returned. The default value of 'top_n_frames' is 10. 67 shorter, results are returned. The default value of 'top_n_frames' is 10.
65 68
66 Args: 69 Args:
67 callstack: The list of stack frames. 70 callstack: The list of stack frames.
68 crash_revision_dict: A dictionary that maps component to its crash 71 component_to_crash_revision_dict: A dictionary that maps component to its
69 revision. 72 crash revision.
70 regression_dict: A dictionary that maps component to its revision 73 component_to_regression_dict: A dictionary that maps component to its
71 range. 74 revision range.
72 parsers: A list of two parsers, svn_parser and git_parser 75 parsers: A list of two parsers, svn_parser and git_parser
73 top_n_frames: A number of stack frames to show the blame result for. 76 top_n_frames: A number of stack frames to show the blame result for.
74 """ 77 """
75 # Only return blame information for first 'top_n_frames' frames. 78 # Only return blame information for first 'top_n_frames' frames.
76 stack_frames = callstack.GetTopNFrames(top_n_frames) 79 stack_frames = callstack.GetTopNFrames(top_n_frames)
77 threads = [] 80 threads = []
78 # Iterate through frames in stack. 81 # Iterate through frames in stack.
79 for stack_frame in stack_frames: 82 for stack_frame in stack_frames:
80 # If the component this line is from does not have a crash revision, 83 # If the component this line is from does not have a crash revision,
81 # it is not possible to get blame information, so ignore this line. 84 # it is not possible to get blame information, so ignore this line.
82 component_path = stack_frame.component_path 85 component_path = stack_frame.component_path
83 if component_path not in crash_revision_dict: 86 if component_path not in component_to_crash_revision_dict:
84 continue 87 continue
85 88
86 crash_revision = crash_revision_dict[component_path]['revision'] 89 crash_revision = component_to_crash_revision_dict[
90 component_path]['revision']
87 range_start = None 91 range_start = None
88 range_end = None 92 range_end = None
89 is_git = utils.IsGitHash(crash_revision) 93 repository_type = crash_utils.GetRepositoryType(crash_revision)
90 if is_git: 94 repository_parser = parsers[repository_type]
91 repository_parser = parsers['git']
92 else:
93 repository_parser = parsers['svn']
94 95
95 # If the revision is in SVN, and if regression information is available, 96 # If the revision is in SVN, and if regression information is available,
96 # get it. For Git, we cannot know the ordering between hash numbers. 97 # get it. For Git, we cannot know the ordering between hash numbers.
97 if not is_git: 98 if repository_type == 'svn':
98 if regression_dict and component_path in regression_dict: 99 if component_to_regression_dict and \
99 component_object = regression_dict[component_path] 100 component_path in component_to_regression_dict:
101 component_object = component_to_regression_dict[component_path]
100 range_start = int(component_object['old_revision']) 102 range_start = int(component_object['old_revision'])
101 range_end = int(component_object['new_revision']) 103 range_end = int(component_object['new_revision'])
102 104
103 # Generate blame entry, one thread for one entry. 105 # Generate blame entry, one thread for one entry.
104 blame_thread = Thread( 106 blame_thread = Thread(
105 target=self.__GenerateBlameEntry, 107 target=self.__GenerateBlameEntry,
106 args=[repository_parser, stack_frame, crash_revision, 108 args=[repository_parser, stack_frame, crash_revision,
107 range_start, range_end]) 109 range_start, range_end])
108 threads.append(blame_thread) 110 threads.append(blame_thread)
109 blame_thread.start() 111 blame_thread.start()
110 112
111 # Join the results before returning. 113 # Join the results before returning.
112 for blame_thread in threads: 114 for blame_thread in threads:
113 blame_thread.join() 115 blame_thread.join()
114 116
115 def __GenerateBlameEntry(self, repository_parser, stack_frame, 117 def __GenerateBlameEntry(self, repository_parser, stack_frame,
116 crash_revision, range_start, range_end): 118 crash_revision, range_start, range_end):
117 """Generates blame list from the arguments.""" 119 """Generates blame list from the arguments."""
118 stack_frame_index = stack_frame.index 120 stack_frame_index = stack_frame.index
119 component_path = stack_frame.component_path 121 component_path = stack_frame.component_path
120 component_name = stack_frame.component_name 122 component_name = stack_frame.component_name
121 file_name = stack_frame.file_name 123 file_name = stack_frame.file_name
122 file_path = stack_frame.file_path 124 file_path = stack_frame.file_path
123 crashed_line_number = stack_frame.crashed_line_number 125 crashed_line_number = stack_frame.crashed_line_range[0]
124 126
125 # Parse blame information. 127 # Parse blame information.
126 parsed_blame_info = repository_parser.ParseBlameInfo( 128 parsed_blame_info = repository_parser.ParseBlameInfo(
127 component_path, file_path, crashed_line_number, crash_revision) 129 component_path, file_path, crashed_line_number, crash_revision)
128 130
129 # If it fails to retrieve information, do not do anything. 131 # If it fails to retrieve information, do not do anything.
130 if not parsed_blame_info or len(parsed_blame_info) != 4: 132 if not parsed_blame_info:
131 return 133 return
132 134
133 # Create blame object from the parsed info and add it to the list. 135 # Create blame object from the parsed info and add it to the list.
134 (line_content, revision, author, url) = parsed_blame_info 136 (line_content, revision, author, url, message) = parsed_blame_info
135 blame = Blame(line_content, component_name, stack_frame_index, file_name, 137 blame = Blame(line_content, component_name, stack_frame_index, file_name,
136 crashed_line_number, author, revision, url, 138 crashed_line_number, author, revision, message, url,
137 range_start, range_end) 139 range_start, range_end)
138 140
139 with self.blame_list_lock: 141 with self.blame_list_lock:
140 self.blame_list.append(blame) 142 self.blame_list.append(blame)
141 143
142 def FilterAndSortBlameList(self): 144 def FilterAndSortBlameList(self):
143 """Filters and sorts the blame list.""" 145 """Filters and sorts the blame list."""
144 # Sort the blame list by its position in stack. 146 # Sort the blame list by its position in stack.
145 self.blame_list.sort(key=lambda blame: blame.stack_frame_index) 147 self.blame_list.sort(key=lambda blame: blame.stack_frame_index)
146 148
147 filtered_blame_list = [] 149 filtered_blame_list = []
148 150
149 for blame in self.blame_list: 151 for blame in self.blame_list:
150 # If regression information is available, check if it needs to be 152 # If regression information is available, check if it needs to be
151 # filtered. 153 # filtered.
152 if blame.range_start and blame.range_end: 154 if blame.range_start and blame.range_end:
153 155
154 # Discards results that are after the end of regression. 156 # Discards results that are after the end of regression.
155 if not utils.IsGitHash(blame.revision) and ( 157 if not utils.IsGitHash(blame.revision) and (
156 int(blame.range_end) <= int(blame.revision)): 158 int(blame.range_end) <= int(blame.revision)):
157 continue 159 continue
158 160
159 filtered_blame_list.append(blame) 161 filtered_blame_list.append(blame)
160 162
161 self.blame_list = filtered_blame_list 163 self.blame_list = filtered_blame_list
OLDNEW
« no previous file with comments | « tools/findit/OWNERS ('k') | tools/findit/chromium_deps.py » ('j') | tools/findit/crash_utils.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698