Chromium Code Reviews| Index: appengine/findit/crash/results.py |
| diff --git a/appengine/findit/crash/results.py b/appengine/findit/crash/results.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..abe6c258cd127fe5f8a57ac9fea8f4f6a450d82e |
| --- /dev/null |
| +++ b/appengine/findit/crash/results.py |
| @@ -0,0 +1,137 @@ |
| +# Copyright 2016 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +_INFINITY = 1000 |
| + |
| + |
| +class Result(object): |
| + |
| + def __init__(self, changelog, dep_path, component, |
| + confidence=None, reason=None): |
| + self.changelog = changelog |
| + self.dep_path = dep_path |
| + self.component = component |
| + self.confidence = confidence |
| + self.reason = reason |
| + |
| + self.file_to_stack_infos = {} |
| + |
| + def ToDict(self): |
| + changelog_json = self.changelog.ToDict() |
|
stgao
2016/04/15 18:35:19
This seems unnecessary as we only refer to several
Sharu
2016/04/15 22:59:47
Done.
|
| + return { |
| + 'url': changelog_json['commit_url'], |
| + 'revision': changelog_json['revision'], |
| + 'dep_path': self.dep_path, |
| + 'component': self.component, |
| + 'author': changelog_json['author_email'], |
| + 'time': changelog_json['author_time'], |
| + 'reason': self.reason, |
| + 'confidence': self.confidence, |
| + } |
| + |
| + def ToString(self): |
| + if not self.file_to_stack_infos: |
| + return '' |
| + |
| + lines = [] |
| + for file_path, stack_infos in self.file_to_stack_infos.iteritems(): |
| + line_parts = [] |
| + for frame, _ in stack_infos: |
| + line_parts.append('%s (#%d)' % (frame.function, frame.index)) |
| + |
| + lines.append('Changed file %s which crashed in %s' % ( |
| + file_path, ', '.join(line_parts))) |
| + |
| + return '\n'.join(lines) |
| + |
| + def __str__(self): |
| + return self.ToString() |
| + |
| + def __repr__(self): |
| + return self.ToString() |
| + |
| + |
| +class MatchResult(Result): |
| + |
| + def __init__(self, changelog, dep_path, component, |
| + confidence=None, reason=None): |
| + super(MatchResult, self).__init__( |
| + changelog, dep_path, component, confidence, reason) |
| + |
| + self.min_distance = _INFINITY |
| + |
| + def Update(self, file_path, stack_infos, blame): |
| + """Updates match result once a file_path is found both shown in |
| + stacktrace and touched by the changelog of this result. |
|
stgao
2016/04/15 18:35:19
changelog here might not be that clear enough. It
Sharu
2016/04/15 22:59:47
Done.
|
| + |
| + Inserts the file path and its stack infos, and updates the min distance |
| + if less distance is found between touched lines of this result and |
| + crashed lines in the file path. |
| + |
| + Args: |
| + file_path (str): File path of the crashed file. |
| + stack_infos (list): List of (StackFrame, callstack priority) tuples, |
| + represents frames of this file and the callstack priorities of those |
| + frames. |
| + blame (Blame): Blame oject of this file. |
| + """ |
| + self.file_to_stack_infos[file_path] = stack_infos |
| + |
| + for region in blame: |
| + if region.revision != self.changelog.revision: |
| + continue |
| + |
| + region_lines = range(region.start, region.start + region.count) |
| + |
| + for frame, _ in stack_infos: |
| + self.min_distance = min(self.min_distance, self._DistanceOfTwoRegions( |
| + frame.crashed_line_numbers, region_lines)) |
| + |
| + def _DistanceOfTwoRegions(self, region1, region2): |
| + |
| + if set(region1).intersection(set(region2)): |
| + return 0 |
| + |
| + if region1[-1] < region2[0]: |
| + return region2[0] - region1[-1] |
| + |
| + return region1[0] - region2[-1] |
| + |
| + |
| +class MatchResults(dict): |
| + |
| + def __init__(self, ignore_cls=None): |
| + super(MatchResults, self).__init__() |
| + self.ignore_cls = ignore_cls |
| + |
| + def GenerateMatchResults(self, file_path, dep_path, |
| + stack_infos, changelogs, blame): |
| + """Generates match results based on newly found file path, its stack_infos, |
| + and all the changelogs that touched this file in the dep in regression |
| + ranges, those reverted changelogs should be ignored. |
| + |
| + Args: |
| + file_path (str): File path of the crashed file. |
| + dep_path (str): Path of the dependency of the file. |
| + stack_infos (list): List of (StackFrame, callstack priority) tuples, |
| + represents frames of this file and the callstack priorities of those |
| + frames. |
| + changelogs (list): List of Changelog objects in the dep in regression |
| + range which touched the file. |
| + blame (Blame): Blame of the file. |
| + """ |
| + |
| + for changelog in changelogs: |
| + if self.ignore_cls and changelog.revision in self.ignore_cls: |
| + continue |
| + |
| + if changelog.revision not in self: |
| + # TODO(katesonia): Enable component classifier later. Get it from |
| + # file_path and dep_path. |
| + component = '' |
| + self[changelog.revision] = MatchResult(changelog, dep_path, component) |
| + |
| + match_result = self[changelog.revision] |
| + |
| + match_result.Update(file_path, stack_infos, blame) |