Chromium Code Reviews| Index: appengine/findit/crash/project.py |
| diff --git a/appengine/findit/crash/project.py b/appengine/findit/crash/project.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b97a119c67fe0b6cd97f0eca1937b4eff2bc2223 |
| --- /dev/null |
| +++ b/appengine/findit/crash/project.py |
| @@ -0,0 +1,116 @@ |
| +# Copyright 2017 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. |
| + |
| +from collections import namedtuple |
| +import os |
| +import re |
| + |
| +from libs.gitiles.diff import ChangeType |
| + |
| +# Some projects like "chromium", it has many dependency projects like |
| +# "chromium-blink", "chromium-skia", "chromium-pdfium"...etc., for those |
| +# dep projects, the "chromium" ``Project`` can derive the names from their |
| +# dep paths. |
| +# Some other projects like "android_os", "clank", they don't have any dependency |
| +# projects that are relavent to Predator. |
| +_PROJECTS_WITH_DEP_PROJECTS = ['chromium'] |
| + |
| + |
| +# TODO(http://crbug.com/659346): write the coverage tests. |
| +class Project(namedtuple('Project', |
| + ['name', 'path_regexs', 'function_regexs', |
| + 'host_directories'])): |
| + """A representation of a "project". |
| + |
| + For example: 'android_os', 'clank' or 'chromium'. Notably, a project knows |
| + how to identify itself. Hence, given a stack frame, file path or dependency |
| + path or whatever, we ask the ``Project`` whether it matches that frame, |
| + CL, etc. |
| + |
| + Properties: |
| + name (str): The name of the project, like "chromium", "android_os". |
| + path_regexs (list of re.RegexObject): Patterns of paths that project has. |
| + function_regexs (list of re.RegexObject): Patterns of functions that project |
| + has. |
| + host_directories (list of str): The root directoris of this project and its |
| + dependency projects. |
| + N.B. If ``host_directories`` is availabe, this project can match |
| + it with the passed-in ``dep_path`` to tell whether a suspect or stack is |
| + from this project, else if this information is missing, the project cannot |
| + tell that from ``dep_path``, however that doesn't mean the suspect or |
| + stack does not belong to this project, we can use other information like |
| + ``path_regexs`` or ``function_regexs`` to analyze. |
| + """ |
| + __slots__ = () |
| + |
| + def __new__(cls, name, path_regexs=None, |
| + function_regexs=None, host_directories=None): |
| + path_regexs = [re.compile(path_regex) for path_regex in |
| + path_regexs] if path_regexs else [] |
| + function_regexs = [re.compile(function_regex) for function_regex in |
| + function_regexs] if function_regexs else [] |
| + host_directories = host_directories or [] |
| + |
| + return super(cls, Project).__new__( |
| + cls, name, path_regexs, function_regexs, host_directories) |
| + |
| + def MatchesStackFrame(self, frame): |
| + """Returns true if this project matches the frame.""" |
| + for path_regex in self.path_regexs: |
| + if (path_regex.match(frame.dep_path + frame.file_path) or |
| + path_regex.match(frame.raw_file_path)): |
| + return True |
| + |
| + for function_regex in self.function_regexs: |
| + if function_regex.match(frame.function): |
| + return True |
| + |
| + for host_directory in self.host_directories: |
| + if frame.dep_path.startswith(host_directory): |
| + return True |
| + |
| + return False |
| + |
| + def MatchesTouchedFile(self, dep_path, touched_file): |
| + """Returns true if this project matches the file path.""" |
| + if touched_file.change_type == ChangeType.DELETE: |
| + path = touched_file.old_path |
| + else: |
| + path = touched_file.new_path |
| + |
| + # if the path matches the path patterns. |
|
lijeffrey
2017/01/27 15:42:20
nit: If
Sharu Jiang
2017/01/27 18:39:04
Done.
|
| + for path_regex in self.path_regexs: |
| + if path_regex.match(os.path.join(dep_path, path)): |
| + return True |
| + |
| + # If the dep_path hosted by this project. |
| + for host_directory in self.host_directories: |
| + if dep_path.startswith(host_directory): |
| + return True |
|
lijeffrey
2017/01/27 15:42:20
I think this can be simplified slightly to:
retur
Sharu Jiang
2017/01/27 18:39:04
Hm... I want to keep these two conditions separate
|
| + |
| + return False |
| + |
| + def GetName(self, dep_path=None): |
| + """Returns the project name based on dep path. |
| + |
| + N.B. (1) If this project doesn't have dep projects, just return the project |
| + name. (2) If this project does, return the derived dep project name based on |
| + the self.host_directories. |
| + """ |
| + if self.name not in _PROJECTS_WITH_DEP_PROJECTS or dep_path is None: |
| + return self.name |
| + |
| + # For chromium project, get the name of the sub project from ``dep_path``. |
| + for host_directory in self.host_directories: |
| + if dep_path.startswith(host_directory): |
| + path = dep_path[len(host_directory):] |
| + if not path: |
| + return self.name |
| + |
| + return '%s-%s' % (self.name, path.split('/')[0].lower()) |
| + |
| + # Unknown path, return the whole path as project name. |
| + return '%s-%s' % (self.name, |
| + '_'.join([dep_part for dep_part in dep_path.split('/') |
| + if dep_part])) |