OLD | NEW |
(Empty) | |
| 1 # Copyright (c) 2012 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 """Checks protobuf files for illegal imports.""" |
| 6 |
| 7 import codecs |
| 8 import os |
| 9 import re |
| 10 |
| 11 import results |
| 12 from rules import Rule, MessageRule |
| 13 |
| 14 |
| 15 class ProtoChecker(object): |
| 16 |
| 17 EXTENSIONS = [ |
| 18 '.proto', |
| 19 ] |
| 20 |
| 21 # The maximum number of non-import lines we can see before giving up. |
| 22 _MAX_UNINTERESTING_LINES = 50 |
| 23 |
| 24 # The maximum line length, this is to be efficient in the case of very long |
| 25 # lines (which can't be import). |
| 26 _MAX_LINE_LENGTH = 128 |
| 27 |
| 28 # This regular expression will be used to extract filenames from import |
| 29 # statements. |
| 30 _EXTRACT_IMPORT_PATH = re.compile( |
| 31 '[ \t]*[ \t]*import[ \t]+"(.*)"') |
| 32 |
| 33 def __init__(self, verbose, resolve_dotdot=False, root_dir=''): |
| 34 self._verbose = verbose |
| 35 self._resolve_dotdot = resolve_dotdot |
| 36 self._root_dir = root_dir |
| 37 |
| 38 def IsFullPath(self, import_path): |
| 39 """Checks if the given path is a valid path starting from |_root_dir|.""" |
| 40 match = re.match('(.*)/([^/]*\.proto)', import_path) |
| 41 if not match: |
| 42 return False |
| 43 return os.path.isdir(self._root_dir + "/" + match.group(1)) |
| 44 |
| 45 def CheckLine(self, rules, line, dependee_path, fail_on_temp_allow=False): |
| 46 """Checks the given line with the given rule set. |
| 47 |
| 48 Returns a tuple (is_import, dependency_violation) where |
| 49 is_import is True only if the line is an import |
| 50 statement, and dependency_violation is an instance of |
| 51 results.DependencyViolation if the line violates a rule, or None |
| 52 if it does not. |
| 53 """ |
| 54 found_item = self._EXTRACT_IMPORT_PATH.match(line) |
| 55 if not found_item: |
| 56 return False, None # Not a match |
| 57 |
| 58 import_path = found_item.group(1) |
| 59 |
| 60 if '\\' in import_path: |
| 61 return True, results.DependencyViolation( |
| 62 import_path, |
| 63 MessageRule('Import paths may not include backslashes.'), |
| 64 rules) |
| 65 |
| 66 if '/' not in import_path: |
| 67 # Don't fail when no directory is specified. We may want to be more |
| 68 # strict about this in the future. |
| 69 if self._verbose: |
| 70 print ' WARNING: import specified with no directory: ' + import_path |
| 71 return True, None |
| 72 |
| 73 if self._resolve_dotdot and '../' in import_path: |
| 74 dependee_dir = os.path.dirname(dependee_path) |
| 75 import_path = os.path.join(dependee_dir, import_path) |
| 76 import_path = os.path.relpath(import_path, self._root_dir) |
| 77 |
| 78 if not self.IsFullPath(import_path): |
| 79 return True, None |
| 80 |
| 81 rule = rules.RuleApplyingTo(import_path, dependee_path) |
| 82 |
| 83 if (rule.allow == Rule.DISALLOW or |
| 84 (fail_on_temp_allow and rule.allow == Rule.TEMP_ALLOW)): |
| 85 return True, results.DependencyViolation(import_path, rule, rules) |
| 86 return True, None |
| 87 |
| 88 def CheckFile(self, rules, filepath): |
| 89 if self._verbose: |
| 90 print 'Checking: ' + filepath |
| 91 |
| 92 dependee_status = results.DependeeStatus(filepath) |
| 93 last_import = 0 |
| 94 with codecs.open(filepath, encoding='utf-8') as f: |
| 95 for line_num, line in enumerate(f): |
| 96 if line_num - last_import > self._MAX_UNINTERESTING_LINES: |
| 97 break |
| 98 |
| 99 line = line.strip() |
| 100 |
| 101 is_import, violation = self.CheckLine(rules, line, filepath) |
| 102 if is_import: |
| 103 last_import = line_num |
| 104 if violation: |
| 105 dependee_status.AddViolation(violation) |
| 106 |
| 107 return dependee_status |
| 108 |
| 109 @staticmethod |
| 110 def IsProtoFile(file_path): |
| 111 """Returns True iff the given path ends in one of the extensions |
| 112 handled by this checker. |
| 113 """ |
| 114 return os.path.splitext(file_path)[1] in ProtoChecker.EXTENSIONS |
| 115 |
| 116 def ShouldCheck(self, file_path): |
| 117 """Check if the new #include file path should be presubmit checked. |
| 118 |
| 119 Args: |
| 120 file_path: file path to be checked |
| 121 |
| 122 Return: |
| 123 bool: True if the file should be checked; False otherwise. |
| 124 """ |
| 125 return self.IsProtoFile(file_path) |
OLD | NEW |