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

Unified Diff: appengine/findit/crash/project.py

Issue 2657913002: [Predator] Add ``Project`` class and ``ClassifySuspect`` method to project and component classifier (Closed)
Patch Set: Fix nits. Created 3 years, 11 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 side-by-side diff with in-line comments
Download patch
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..9660c6029129abc97953e07a3456e82eed673c20
--- /dev/null
+++ b/appengine/findit/crash/project.py
@@ -0,0 +1,121 @@
+# 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
Martin Barbella 2017/01/27 23:30:58 Nit: s/it has/have/
Sharu Jiang 2017/01/30 22:23:52 Done.
+# "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',
wrengr 2017/01/30 19:14:19 Nit: "regexes" is the standard way to pluralize "r
Sharu Jiang 2017/01/30 22:23:52 Done.
+ 'host_directories'])):
+ """A representation of a "project".
wrengr 2017/01/30 19:14:19 This line doesn't explain anything beyond what the
Sharu Jiang 2017/01/30 22:23:52 Done.
+
+ 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
wrengr 2017/01/30 19:14:19 (s/directoris/directories/ && s/and its/and their/
Sharu Jiang 2017/01/30 22:23:52 Done.
+ dependency projects.
+ N.B. If ``host_directories`` is availabe, this project can match
wrengr 2017/01/30 19:14:19 s/availabe/available/
Sharu Jiang 2017/01/30 22:23:52 Done.
+ 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
wrengr 2017/01/30 19:14:19 s/, else if/. If/
Sharu Jiang 2017/01/30 22:23:52 Done.
+ tell that from ``dep_path``, however that doesn't mean the suspect or
wrengr 2017/01/30 19:14:19 s/, however/; however,/
Sharu Jiang 2017/01/30 22:23:52 Done.
+ 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
wrengr 2017/01/30 19:14:19 can replace this line with ``map(re.compile, path_
Sharu Jiang 2017/01/30 22:23:52 Done.
+ path_regexs] if path_regexs else []
+ function_regexs = [re.compile(function_regex) for function_regex in
+ function_regexs] if function_regexs else []
wrengr 2017/01/30 19:14:19 ditto
Sharu Jiang 2017/01/30 22:23:52 Done.
+ 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."""
+ # Sometimes some marker information are in the frame.raw_file_path.
+ # An example, the path_regex for android_os is --
+ # "https___googleplex-android.googlesource.com_a_platform_manifest.git/".
+ # It can only be found in frame.raw_file_path, since the frame.file_path
+ # has those kind of information stripped.
+ for path_regex in self.path_regexs:
+ if (path_regex.match(os.path.join(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:
wrengr 2017/01/30 19:14:19 Since this conditional shows up repeatedly, should
Sharu Jiang 2017/01/30 22:23:52 Done.
+ path = touched_file.old_path
+ else:
+ path = touched_file.new_path
+
+ # If the path matches the path patterns.
+ 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
+
+ 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]))

Powered by Google App Engine
This is Rietveld 408576698