| OLD | NEW |
| (Empty) | |
| 1 # Copyright 2017 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 from collections import namedtuple |
| 6 import os |
| 7 import re |
| 8 |
| 9 from libs.gitiles.diff import ChangeType |
| 10 |
| 11 # Some projects like "chromium", have many sub projects like |
| 12 # "chromium-blink", "chromium-skia", "chromium-pdfium"...etc., for those |
| 13 # dep projects, the "chromium" ``Project`` can derive the names from their |
| 14 # dep paths. |
| 15 # Some other projects like "android_os", "clank", they don't have any dependency |
| 16 # projects that are relavent to Predator. |
| 17 _PROJECTS_WITH_DEP_PROJECTS = ['chromium'] |
| 18 |
| 19 |
| 20 # TODO(http://crbug.com/659346): write the coverage tests. |
| 21 class Project(namedtuple('Project', |
| 22 ['name', 'path_regexes', 'function_regexes', |
| 23 'host_directories'])): |
| 24 """A representation of a "project", which may host many sub projects. |
| 25 |
| 26 For example: 'android_os', 'clank' or 'chromium'. Notably, a project knows |
| 27 how to identify itself. Hence, given a stack frame, file path or dependency |
| 28 path or whatever, we ask the ``Project`` whether it matches that frame, |
| 29 CL, etc. |
| 30 |
| 31 Properties: |
| 32 name (str): The name of the project, like "chromium", "android_os". |
| 33 path_regexes (list of re.RegexObject): Patterns of paths that project has. |
| 34 function_regexes (list of re.RegexObject): Patterns of functions that |
| 35 project has. |
| 36 host_directories (list of str): The root directories of this project and |
| 37 sub projects this project hosts. |
| 38 N.B. If ``host_directories`` is available, this project can match |
| 39 it with the passed-in ``dep_path`` to tell whether a suspect or stack is |
| 40 from this project. If this information is missing, the project cannot |
| 41 tell that from ``dep_path``; However, that doesn't mean the suspect or |
| 42 stack does not belong to this project, we can use other information like |
| 43 ``path_regexes`` or ``function_regexes`` to analyze. |
| 44 """ |
| 45 __slots__ = () |
| 46 |
| 47 def __new__(cls, name, path_regexes=None, |
| 48 function_regexes=None, host_directories=None): |
| 49 path_regexes = map(re.compile, path_regexes or []) |
| 50 function_regexes = map(re.compile, function_regexes or []) |
| 51 host_directories = host_directories or [] |
| 52 |
| 53 return super(cls, Project).__new__( |
| 54 cls, name, path_regexes, function_regexes, host_directories) |
| 55 |
| 56 def MatchesStackFrame(self, frame): |
| 57 """Returns true if this project matches the frame.""" |
| 58 # Sometimes some marker information are in the frame.raw_file_path. |
| 59 # An example, the path_regex for android_os is -- |
| 60 # "https___googleplex-android.googlesource.com_a_platform_manifest.git/". |
| 61 # It can only be found in frame.raw_file_path, since the frame.file_path |
| 62 # has those kind of information stripped. |
| 63 for path_regex in self.path_regexes: |
| 64 if (path_regex.match(os.path.join(frame.dep_path, frame.file_path)) or |
| 65 path_regex.match(frame.raw_file_path)): |
| 66 return True |
| 67 |
| 68 for function_regex in self.function_regexes: |
| 69 if function_regex.match(frame.function): |
| 70 return True |
| 71 |
| 72 for host_directory in self.host_directories: |
| 73 if frame.dep_path.startswith(host_directory): |
| 74 return True |
| 75 |
| 76 return False |
| 77 |
| 78 def MatchesTouchedFile(self, dep_path, file_path): |
| 79 """Returns true if this project matches the file path.""" |
| 80 # If the path matches the path patterns. |
| 81 for path_regex in self.path_regexes: |
| 82 if path_regex.match(os.path.join(dep_path, file_path)): |
| 83 return True |
| 84 |
| 85 # If the dep_path hosted by this project. |
| 86 for host_directory in self.host_directories: |
| 87 if dep_path.startswith(host_directory): |
| 88 return True |
| 89 |
| 90 return False |
| 91 |
| 92 def GetName(self, dep_path=None): |
| 93 """Returns the project name based on dep path. |
| 94 |
| 95 N.B. (1) If this project doesn't have dep projects, just return the project |
| 96 name. (2) If this project does, return the derived dep project name based on |
| 97 the self.host_directories. |
| 98 """ |
| 99 if self.name not in _PROJECTS_WITH_DEP_PROJECTS or dep_path is None: |
| 100 return self.name |
| 101 |
| 102 # For chromium project, get the name of the sub project from ``dep_path``. |
| 103 for host_directory in self.host_directories: |
| 104 if dep_path.startswith(host_directory): |
| 105 path = dep_path[len(host_directory):] |
| 106 if not path: |
| 107 return self.name |
| 108 |
| 109 return '%s-%s' % (self.name, path.split('/')[0].lower()) |
| 110 |
| 111 # Unknown path, return the whole path as project name. |
| 112 return '%s-%s' % (self.name, |
| 113 '_'.join([dep_part for dep_part in dep_path.split('/') |
| 114 if dep_part])) |
| OLD | NEW |