Chromium Code Reviews| 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 json | |
| 6 import time | |
| 7 import urllib | |
| 8 | |
| 9 | |
| 10 def NormalizePathLinux(path): | |
|
stgao
2014/08/01 17:22:20
Could we include this function only in this patch?
jeun
2014/08/06 18:22:59
I am not sure what is the best way of doing this,
| |
| 11 """Normalizes linux path. | |
| 12 | |
| 13 Args: | |
| 14 path: a string representing a path | |
| 15 | |
| 16 Returns: | |
| 17 A tuple containing a component this path is in (e.g blink, skia, etc) | |
| 18 and a path in that component's repository | |
| 19 """ | |
| 20 normalized_path = path | |
| 21 # TODO(jeun): integrate with parsing DEPS file | |
|
stgao
2014/08/01 17:22:20
style issue: comment.
jeun
2014/08/06 18:22:59
Done.
| |
| 22 if 'WebKit/' in path: | |
| 23 component = 'blink' | |
| 24 normalized_path = path.split('WebKit/')[1] | |
| 25 else: | |
| 26 component = 'chromium' | |
| 27 | |
| 28 if normalized_path.startswith( | |
| 29 '/b/build/slave/ASAN_Release__symbolized_/build/'): | |
| 30 normalized_path = normalized_path.split( | |
| 31 '/b/build/slave/ASAN_Release__symbolized_/build/')[1] | |
| 32 | |
| 33 if '../../' in normalized_path: | |
| 34 normalized_path = normalized_path.split('../../')[1] | |
| 35 | |
| 36 if 'src/v8/' in normalized_path: | |
| 37 component = 'v8' | |
| 38 normalized_path = normalized_path.split('src/v8/')[1] | |
| 39 | |
| 40 if './' in normalized_path: | |
| 41 normalized_path = normalized_path.split('./')[1] | |
| 42 | |
| 43 if not normalized_path.startswith('src/') and ( | |
| 44 not normalized_path.startswith('Source/')): | |
| 45 normalized_path = 'src/' + normalized_path | |
| 46 | |
| 47 return (component, normalized_path) | |
| 48 | |
| 49 | |
| 50 def SplitRange(regression): | |
| 51 """Splits a range as retrieved from clusterfuzz. | |
| 52 | |
| 53 Args: | |
| 54 regression: a string in format 'r1234:r5678' | |
| 55 | |
| 56 Returns: | |
| 57 a list containing two numbers represented in string, for example | |
| 58 ['1234','5678'] | |
| 59 """ | |
| 60 temp = regression.split(':') | |
| 61 | |
| 62 # If regression information is not available, return none | |
| 63 if len(temp) != 2: | |
| 64 return None | |
| 65 | |
| 66 start_range = temp[0] | |
| 67 end_range = temp[1] | |
| 68 | |
| 69 # Check if the range starts with r, such as in 'r10000' format | |
| 70 if start_range.startswith('r'): | |
| 71 start_range = start_range[1:] | |
| 72 if end_range.startswith('r'): | |
| 73 end_range = end_range[1:] | |
| 74 | |
| 75 return [start_range, end_range] | |
| 76 | |
| 77 | |
| 78 def LoadJSON(json_string): | |
| 79 """Loads json object from string, or None. | |
| 80 | |
| 81 Args: | |
| 82 json_string: a string to get object from. | |
| 83 | |
| 84 Returns: | |
| 85 JSON object if the string represents a JSON object, None otherwise | |
| 86 """ | |
| 87 try: | |
| 88 data = json.loads(json_string) | |
| 89 except ValueError: | |
| 90 data = None | |
| 91 return data | |
| 92 | |
| 93 | |
| 94 def GetDataFromURL(url): | |
| 95 """Retrieves raw data from URL, tries 10 times. | |
| 96 | |
| 97 Args: | |
| 98 url: url to get data from | |
| 99 | |
| 100 Returns: | |
| 101 None if the data retrieval fails, or the raw data. | |
| 102 """ | |
| 103 data = None | |
| 104 for i in range(10): | |
|
stgao
2014/08/01 17:22:20
For the retry, it might be better to make it as a
jeun
2014/08/06 18:22:59
Done.
| |
| 105 | |
| 106 # Retrieves data from URL | |
| 107 try: | |
| 108 data = urllib.urlopen(url) | |
| 109 | |
| 110 # If retrieval is successful, break from the retry look | |
| 111 if data: | |
| 112 break | |
| 113 | |
| 114 # If retrieval fails, try after 0.1 second | |
| 115 except IOError: | |
| 116 time.sleep(0.1) | |
|
stgao
2014/08/01 17:22:20
Sleep interval could be parameterized too.
jeun
2014/08/06 18:22:59
Done.
| |
| 117 continue | |
| 118 | |
| 119 # If returned data has something in it, return the content | |
| 120 if data: | |
| 121 return data.read() | |
| 122 else: | |
| 123 return None | |
| 124 | |
| 125 | |
| 126 def FindMinLineDistance(crashed_line_list, changed_line_numbers): | |
| 127 """Calculates how far the changed line is from one of the crashes. | |
| 128 | |
| 129 Finds the minimum distance between the lines that the file crashed on | |
| 130 and the lines that the file changed. For example, if the file crashed on | |
| 131 line 200 and the CL changes line 203,204 and 205, the function returns 3. | |
| 132 | |
| 133 Args: | |
| 134 crashed_line_list: list of lines that the file crashed on | |
| 135 changed_line_numbers: list of lines that the file changed | |
| 136 | |
| 137 Returns: | |
| 138 the minimum distance. If either of the input lists is empty, | |
| 139 it returns inf. | |
| 140 | |
| 141 """ | |
| 142 min_distance = float('inf') | |
| 143 | |
| 144 for line in crashed_line_list: | |
| 145 for distance in changed_line_numbers: | |
| 146 # Find the current distance and update the min if current distance is | |
| 147 # less than current min | |
| 148 current_distance = abs(line - distance) | |
| 149 if current_distance < min_distance: | |
| 150 min_distance = current_distance | |
| 151 | |
| 152 return min_distance | |
| 153 | |
| 154 | |
| 155 def GuessIfSamePath(path1, path2): | |
| 156 """Guesses if two paths represent same path. | |
| 157 | |
| 158 Compares the name of the folders in the path (by split('/')), and checks | |
| 159 if they match either more than 3 or min of path lengths | |
| 160 | |
| 161 Args: | |
| 162 path1: First path | |
| 163 path2: Second path to compare | |
| 164 | |
| 165 Returns: | |
| 166 True if it they are thought to be a same path, False otherwise | |
| 167 """ | |
| 168 path1 = path1.split('/') | |
| 169 path2 = path2.split('/') | |
| 170 | |
| 171 intersection = set(path1).intersection(set(path2)) | |
| 172 return len(intersection) >= (min(3, min(len(path1), len(path2)))) | |
| 173 | |
| 174 | |
| 175 def FindMinStackFrameNum(stack_frame_index, priorities): | |
| 176 """Finds the minimum stack number, from the list of stack numbers. | |
| 177 | |
| 178 Args: | |
| 179 stack_frame_index: a list of list containing stack position | |
| 180 priorities: a list of of priority for each file | |
| 181 | |
| 182 Returns: | |
| 183 inf if stack_frame_index is empty, minimum stack number otherwise | |
| 184 """ | |
| 185 # Get the indexes of the highest priority (or low priority number) | |
| 186 highest_priority = min(priorities) | |
| 187 highest_priority_indices = [] | |
| 188 for i in range(len(priorities)): | |
| 189 if priorities[i] == highest_priority: | |
| 190 highest_priority_indices.append(i) | |
| 191 | |
| 192 # Gather the list of stack frame numbers for the files that change the | |
| 193 # crash lines | |
| 194 flattened = [] | |
| 195 for i in highest_priority_indices: | |
| 196 flattened += stack_frame_index[i] | |
| 197 | |
| 198 # If no stack frame information is available, return inf. Else, return min | |
| 199 if not flattened: | |
| 200 return float('inf') | |
| 201 else: | |
| 202 return min(flattened) | |
| 203 | |
| 204 | |
| 205 def AddHyperlink(to_add, link): | |
| 206 """Returns a string with HTML link tag. | |
| 207 | |
| 208 Args: | |
| 209 to_add: a string to add link | |
| 210 link: a link to add to the string | |
| 211 | |
| 212 Returns: | |
| 213 a string with hyperlink added | |
| 214 """ | |
| 215 return '<a href="%s">%s<\\a>' % (link, to_add) | |
| 216 | |
| 217 | |
| 218 def PrettifyList(l): | |
| 219 """Returns a string representation of a list of ints. | |
| 220 | |
| 221 Args: | |
| 222 l: an int list to prettify | |
| 223 Returns: | |
| 224 a string representation of list | |
| 225 """ | |
| 226 return str(l)[1:-1] | |
| 227 | |
| 228 | |
| 229 def PrettifyFiles(file_list): | |
| 230 """Returns a string representation of a list of file names. | |
| 231 | |
| 232 Args: | |
| 233 file_list: a list of tuple, (file_name, file_url) | |
| 234 Returns: | |
| 235 a string representation of file names | |
| 236 """ | |
| 237 ret = ['\n'] | |
| 238 for file_name, file_url in file_list: | |
| 239 ret.append(' %s\n' % AddHyperlink(file_name, file_url)) | |
| 240 return ''.join(ret) | |
| 241 | |
| 242 | |
| 243 def Intersection(crashed_line_list, stack_frame_index, changed_line_numbers): | |
| 244 """Finds the overlap betwee changed lines and crashed lines. | |
| 245 | |
| 246 Finds the intersection of the lines that caused the crash and | |
| 247 lines that the file changes. The intersection looks within 3 lines | |
| 248 of the line that caused the crash. | |
| 249 | |
| 250 Args: | |
| 251 crashed_line_list: list of lines that the file crashed on | |
| 252 stack_frame_index: list of positions in stack for each of the lines | |
| 253 changed_line_numbers: list of lines that the file changed | |
| 254 | |
| 255 Returns: | |
| 256 line_intersection: intersection between crashed_line_list and | |
| 257 changed_line_numbers | |
| 258 stack_frame_index_intersection: stack number for each of the intersections | |
| 259 """ | |
| 260 line_intersection = [] | |
| 261 stack_frame_index_intersection = [] | |
| 262 | |
| 263 # Iterate through the crashed lines, and its occurence in stack | |
| 264 for (line, stack_frame_index) in zip(crashed_line_list, stack_frame_index): | |
| 265 | |
| 266 # Also check previous 3 lines | |
| 267 line_minus_n = range(line - 3, line + 1) | |
| 268 | |
| 269 for changed_line in changed_line_numbers: | |
| 270 | |
| 271 # If a CL does not change crahsed line, check next line | |
| 272 if changed_line not in line_minus_n: | |
| 273 continue | |
| 274 | |
| 275 # If the changed line is exactly the crashed line, add that line | |
| 276 if line in changed_line_numbers: | |
| 277 to_add = line | |
| 278 | |
| 279 # If the changed line is within 3 lines of the crashed line, add the line | |
| 280 else: | |
| 281 to_add = changed_line | |
| 282 | |
| 283 # Avoid adding the same line twiece | |
| 284 if to_add not in line_intersection: | |
| 285 line_intersection.append(to_add) | |
| 286 stack_frame_index_intersection.append(stack_frame_index) | |
| 287 | |
| 288 break | |
| 289 | |
| 290 return (line_intersection, stack_frame_index_intersection) | |
| OLD | NEW |