Chromium Code Reviews| Index: checkdeps/proto_checker.py |
| diff --git a/checkdeps/proto_checker.py b/checkdeps/proto_checker.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fdd58209e7c1e97e2aa16d1b27faa5c2e0979e89 |
| --- /dev/null |
| +++ b/checkdeps/proto_checker.py |
| @@ -0,0 +1,114 @@ |
| +# Copyright (c) 2012 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. |
| + |
| +"""Checks protobuf files for illegal imports.""" |
| + |
| +import codecs |
| +import os |
| +import re |
| + |
| +import results |
| +from rules import Rule, MessageRule |
| + |
| + |
| +class ProtoChecker(object): |
| + |
| + EXTENSIONS = [ |
| + '.proto', |
| + ] |
| + |
| + # The maximum number of non-import lines we can see before giving up. |
| + _MAX_UNINTERESTING_LINES = 50 |
| + |
| + # The maximum line length, this is to be efficient in the case of very long |
| + # lines (which can't be import). |
| + _MAX_LINE_LENGTH = 128 |
| + |
| + # This regular expression will be used to extract filenames from import |
| + # statements. |
| + _EXTRACT_IMPORT_PATH = re.compile( |
| + '[ \t]*[ \t]*import[ \t]+"(.*)"') |
| + |
| + def __init__(self, verbose, resolve_dotdot=False, root_dir=''): |
| + self._verbose = verbose |
| + self._resolve_dotdot = resolve_dotdot |
| + self._root_dir = root_dir |
| + |
| + def CheckLine(self, rules, line, dependee_path, fail_on_temp_allow=False): |
| + """Checks the given line with the given rule set. |
| + |
| + Returns a tuple (is_import, dependency_violation) where |
| + is_import is True only if the line is an import |
| + statement, and dependency_violation is an instance of |
| + results.DependencyViolation if the line violates a rule, or None |
| + if it does not. |
| + """ |
| + found_item = self._EXTRACT_IMPORT_PATH.match(line) |
| + if not found_item: |
| + return False, None # Not a match |
| + |
| + import_path = found_item.group(1) |
| + |
| + if '\\' in import_path: |
| + return True, results.DependencyViolation( |
| + import_path, |
| + MessageRule('Import paths may not include backslashes.'), |
| + rules) |
| + |
| + if '/' not in import_path: |
| + # Don't fail when no directory is specified. We may want to be more |
| + # strict about this in the future. |
| + if self._verbose: |
| + print ' WARNING: import specified with no directory: ' + import_path |
| + return True, None |
| + |
| + if self._resolve_dotdot and '../' in import_path: |
| + dependee_dir = os.path.dirname(dependee_path) |
| + import_path = os.path.join(dependee_dir, import_path) |
| + import_path = os.path.relpath(import_path, self._root_dir) |
| + |
| + rule = rules.RuleApplyingTo(import_path, dependee_path) |
| + if (rule.allow == Rule.DISALLOW or |
| + (fail_on_temp_allow and rule.allow == Rule.TEMP_ALLOW)): |
| + return True, results.DependencyViolation(import_path, rule, rules) |
| + return True, None |
| + |
| + def CheckFile(self, rules, filepath): |
| + if self._verbose: |
| + print 'Checking: ' + filepath |
| + |
| + dependee_status = results.DependeeStatus(filepath) |
| + last_import = 0 |
| + with codecs.open(filepath, encoding='utf-8') as f: |
| + for line_num, line in enumerate(f): |
| + if line_num - last_import > self._MAX_UNINTERESTING_LINES: |
| + break |
| + |
| + line = line.strip() |
| + |
| + is_import, violation = self.CheckLine(rules, line, filepath) |
| + if is_import: |
| + last_import = line_num |
| + if violation: |
| + dependee_status.AddViolation(violation) |
| + |
| + return dependee_status |
| + |
| + @staticmethod |
| + def IsProtoFile(file_path): |
| + """Returns True iff the given path ends in one of the extensions |
|
brettw
2017/01/25 21:12:18
I find "iff" harder to read and unnecessary (in pr
|
| + handled by this checker. |
| + """ |
| + return os.path.splitext(file_path)[1] in ProtoChecker.EXTENSIONS |
| + |
| + def ShouldCheck(self, file_path): |
| + """Check if the new #include file path should be presubmit checked. |
| + |
| + Args: |
| + file_path: file path to be checked |
| + |
| + Return: |
| + bool: True if the file should be checked; False otherwise. |
| + """ |
| + return self.IsProtoFile(file_path) |