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.
7 from threading
import Lock
12 REVIEW_URL_PATTERN
= re
.compile(r
'Review URL:( *)(.*?)/(\d+)')
16 """Represents a match entry.
18 A match is a CL that is suspected to have caused the crash. A match object
19 contains information about files it changes, their authors, etc.
22 is_revert: True if this CL is reverted by other CL.
23 revert_of: If this CL is a revert of some other CL, a revision number/
25 crashed_line_numbers: The list of lines that caused crash for this CL.
26 function_list: The list of functions that caused the crash.
27 min_distance: The minimum distance between the lines that CL changed and
28 lines that caused the crash.
29 changed_files: The list of files that the CL changed.
30 changed_file_urls: The list of URLs for the file.
31 author: The author of the CL.
32 component_name: The name of the component that this CL belongs to.
33 stack_frame_indices: For files that caused crash, list of where in the
34 stackframe they occur.
35 priorities: A list of priorities for each of the changed file. A priority
36 is 1 if the file changes a crashed line, and 2 if it changes
37 the file but not the crashed line.
38 reivision_url: The revision URL of the CL.
39 review_url: The codereview URL that reviews this CL.
40 reviewers: The list of people that reviewed this CL.
41 reason: The reason why this CL is suspected.
42 time: When this CL was committed.
44 REVERT_PATTERN
= re
.compile(r
'(revert\w*) r?(\d+)', re
.I
)
46 def __init__(self
, revision
, component_name
):
47 self
.is_revert
= False
50 self
.crashed_line_numbers
= []
51 self
.function_list
= []
52 self
.min_distance
= crash_utils
.INFINITY
53 self
.min_distance_info
= None
54 self
.changed_files
= []
55 self
.changed_file_urls
= []
56 self
.author
= revision
['author']
57 self
.component_name
= component_name
58 self
.stack_frame_indices
= []
60 self
.revision_url
= revision
['url']
64 self
.time
= revision
['time']
66 def ParseMessage(self
, message
, codereview_api_url
):
67 """Parses the message.
69 It checks the message to extract the code review website and list of
70 reviewers, and it also checks if the CL is a revert of another CL.
73 message: The message to parse.
74 codereview_api_url: URL to retrieve codereview data from.
76 self
.message
= message
77 for line
in message
.splitlines():
79 review_url_line_match
= REVIEW_URL_PATTERN
.match(line
)
81 # Check if the line has the code review information.
82 if review_url_line_match
:
84 # Get review number for the code review site from the line.
85 issue_number
= review_url_line_match
.group(3)
87 # Get JSON from the code review site, ignore the line if it fails.
88 url
= codereview_api_url
% issue_number
89 json_string
= crash_utils
.GetDataFromURL(url
)
93 # Load the JSON from the string, and get the list of reviewers.
94 code_review
= crash_utils
.LoadJSON(json_string
)
96 self
.reviewers
= code_review
['reviewers']
98 # Check if this CL is a revert of other CL.
99 if line
.lower().startswith('revert'):
100 self
.is_revert
= True
102 # Check if the line says what CL this CL is a revert of.
103 revert
= self
.REVERT_PATTERN
.match(line
)
105 self
.revert_of
= revert
.group(2)
109 class MatchSet(object):
110 """Represents a set of matches.
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.
118 def __init__(self
, codereview_api_url
):
119 self
.codereview_api_url
= codereview_api_url
121 self
.cls_to_ignore
= set()
122 self
.matches_lock
= Lock()
124 def RemoveRevertedCLs(self
):
125 """Removes CLs that are revert."""
126 for cl
in self
.matches
:
127 if cl
in self
.cls_to_ignore
: