Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / tools / checkdeps / checkdeps.py
blob5bf79076063b98d5293616292d4b9157b7044196
1 #!/usr/bin/env python
2 # Copyright 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Makes sure that files include headers from allowed directories.
8 Checks DEPS files in the source tree for rules, and applies those rules to
9 "#include" and "import" directives in the .cpp and .java source files.
10 Any source file including something not permitted by the DEPS files will fail.
12 See builddeps.py for a detailed description of the DEPS format.
13 """
15 import os
16 import optparse
17 import re
18 import sys
20 import cpp_checker
21 import java_checker
22 import results
24 from builddeps import DepsBuilder
25 from rules import Rule, Rules
28 def _IsTestFile(filename):
29 """Does a rudimentary check to try to skip test files; this could be
30 improved but is good enough for now.
31 """
32 return re.match('(test|mock|dummy)_.*|.*_[a-z]*test\.(cc|mm|java)', filename)
35 class DepsChecker(DepsBuilder):
36 """Parses include_rules from DEPS files and verifies files in the
37 source tree against them.
38 """
40 def __init__(self,
41 base_directory=None,
42 verbose=False,
43 being_tested=False,
44 ignore_temp_rules=False,
45 skip_tests=False):
46 """Creates a new DepsChecker.
48 Args:
49 base_directory: OS-compatible path to root of checkout, e.g. C:\chr\src.
50 verbose: Set to true for debug output.
51 being_tested: Set to true to ignore the DEPS file at tools/checkdeps/DEPS.
52 ignore_temp_rules: Ignore rules that start with Rule.TEMP_ALLOW ("!").
53 """
54 DepsBuilder.__init__(
55 self, base_directory, verbose, being_tested, ignore_temp_rules)
57 self._skip_tests = skip_tests
58 self.results_formatter = results.NormalResultsFormatter(verbose)
60 def Report(self):
61 """Prints a report of results, and returns an exit code for the process."""
62 if self.results_formatter.GetResults():
63 self.results_formatter.PrintResults()
64 return 1
65 print '\nSUCCESS\n'
66 return 0
68 def CheckDirectory(self, start_dir):
69 """Checks all relevant source files in the specified directory and
70 its subdirectories for compliance with DEPS rules throughout the
71 tree (starting at |self.base_directory|). |start_dir| must be a
72 subdirectory of |self.base_directory|.
74 On completion, self.results_formatter has the results of
75 processing, and calling Report() will print a report of results.
76 """
77 java = java_checker.JavaChecker(self.base_directory, self.verbose)
78 cpp = cpp_checker.CppChecker(self.verbose)
79 checkers = dict(
80 (extension, checker)
81 for checker in [java, cpp] for extension in checker.EXTENSIONS)
82 self._CheckDirectoryImpl(checkers, start_dir)
84 def _CheckDirectoryImpl(self, checkers, dir_name):
85 rules = self.GetDirectoryRules(dir_name)
86 if rules is None:
87 return
89 # Collect a list of all files and directories to check.
90 files_to_check = []
91 dirs_to_check = []
92 contents = sorted(os.listdir(dir_name))
93 for cur in contents:
94 full_name = os.path.join(dir_name, cur)
95 if os.path.isdir(full_name):
96 dirs_to_check.append(full_name)
97 elif os.path.splitext(full_name)[1] in checkers:
98 if not self._skip_tests or not _IsTestFile(cur):
99 files_to_check.append(full_name)
101 # First check all files in this directory.
102 for cur in files_to_check:
103 checker = checkers[os.path.splitext(cur)[1]]
104 file_status = checker.CheckFile(rules, cur)
105 if file_status.HasViolations():
106 self.results_formatter.AddError(file_status)
108 # Next recurse into the subdirectories.
109 for cur in dirs_to_check:
110 self._CheckDirectoryImpl(checkers, cur)
112 def CheckAddedCppIncludes(self, added_includes):
113 """This is used from PRESUBMIT.py to check new #include statements added in
114 the change being presubmit checked.
116 Args:
117 added_includes: ((file_path, (include_line, include_line, ...), ...)
119 Return:
120 A list of tuples, (bad_file_path, rule_type, rule_description)
121 where rule_type is one of Rule.DISALLOW or Rule.TEMP_ALLOW and
122 rule_description is human-readable. Empty if no problems.
124 cpp = cpp_checker.CppChecker(self.verbose)
125 problems = []
126 for file_path, include_lines in added_includes:
127 if not cpp.IsCppFile(file_path):
128 continue
129 rules_for_file = self.GetDirectoryRules(os.path.dirname(file_path))
130 if not rules_for_file:
131 continue
132 for line in include_lines:
133 is_include, violation = cpp.CheckLine(
134 rules_for_file, line, file_path, True)
135 if not violation:
136 continue
137 rule_type = violation.violated_rule.allow
138 if rule_type == Rule.ALLOW:
139 continue
140 violation_text = results.NormalResultsFormatter.FormatViolation(
141 violation, self.verbose)
142 problems.append((file_path, rule_type, violation_text))
143 return problems
146 def PrintUsage():
147 print """Usage: python checkdeps.py [--root <root>] [tocheck]
149 --root ROOT Specifies the repository root. This defaults to "../../.."
150 relative to the script file. This will be correct given the
151 normal location of the script in "<root>/tools/checkdeps".
153 --(others) There are a few lesser-used options; run with --help to show them.
155 tocheck Specifies the directory, relative to root, to check. This defaults
156 to "." so it checks everything.
158 Examples:
159 python checkdeps.py
160 python checkdeps.py --root c:\\source chrome"""
163 def main():
164 option_parser = optparse.OptionParser()
165 option_parser.add_option(
166 '', '--root',
167 default='', dest='base_directory',
168 help='Specifies the repository root. This defaults '
169 'to "../../.." relative to the script file, which '
170 'will normally be the repository root.')
171 option_parser.add_option(
172 '', '--ignore-temp-rules',
173 action='store_true', dest='ignore_temp_rules', default=False,
174 help='Ignore !-prefixed (temporary) rules.')
175 option_parser.add_option(
176 '', '--generate-temp-rules',
177 action='store_true', dest='generate_temp_rules', default=False,
178 help='Print rules to temporarily allow files that fail '
179 'dependency checking.')
180 option_parser.add_option(
181 '', '--count-violations',
182 action='store_true', dest='count_violations', default=False,
183 help='Count #includes in violation of intended rules.')
184 option_parser.add_option(
185 '', '--skip-tests',
186 action='store_true', dest='skip_tests', default=False,
187 help='Skip checking test files (best effort).')
188 option_parser.add_option(
189 '-v', '--verbose',
190 action='store_true', default=False,
191 help='Print debug logging')
192 option_parser.add_option(
193 '', '--json',
194 help='Path to JSON output file')
195 options, args = option_parser.parse_args()
197 deps_checker = DepsChecker(options.base_directory,
198 verbose=options.verbose,
199 ignore_temp_rules=options.ignore_temp_rules,
200 skip_tests=options.skip_tests)
201 base_directory = deps_checker.base_directory # Default if needed, normalized
203 # Figure out which directory we have to check.
204 start_dir = base_directory
205 if len(args) == 1:
206 # Directory specified. Start here. It's supposed to be relative to the
207 # base directory.
208 start_dir = os.path.abspath(os.path.join(base_directory, args[0]))
209 elif len(args) >= 2 or (options.generate_temp_rules and
210 options.count_violations):
211 # More than one argument, or incompatible flags, we don't handle this.
212 PrintUsage()
213 return 1
215 if not start_dir.startswith(deps_checker.base_directory):
216 print 'Directory to check must be a subdirectory of the base directory,'
217 print 'but %s is not a subdirectory of %s' % (start_dir, base_directory)
218 return 1
220 print 'Using base directory:', base_directory
221 print 'Checking:', start_dir
223 if options.generate_temp_rules:
224 deps_checker.results_formatter = results.TemporaryRulesFormatter()
225 elif options.count_violations:
226 deps_checker.results_formatter = results.CountViolationsFormatter()
228 if options.json:
229 deps_checker.results_formatter = results.JSONResultsFormatter(
230 options.json, deps_checker.results_formatter)
232 deps_checker.CheckDirectory(start_dir)
233 return deps_checker.Report()
236 if '__main__' == __name__:
237 sys.exit(main())