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

Side by Side Diff: tools/checkdeps/checkdeps.py

Issue 10832062: Add ability to format errors as a list of temp-allow rules to paste (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address review comments. Created 8 years, 4 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/checkdeps/checkdeps_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Makes sure that files include headers from allowed directories. 6 """Makes sure that files include headers from allowed directories.
7 7
8 Checks DEPS files in the source tree for rules, and applies those rules to 8 Checks DEPS files in the source tree for rules, and applies those rules to
9 "#include" commands in source files. Any source file including something not 9 "#include" commands in source files. Any source file including something not
10 permitted by the DEPS files will fail. 10 permitted by the DEPS files will fail.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 """ 65 """
66 66
67 import os 67 import os
68 import optparse 68 import optparse
69 import subprocess 69 import subprocess
70 import sys 70 import sys
71 import copy 71 import copy
72 72
73 import cpp_checker 73 import cpp_checker
74 import java_checker 74 import java_checker
75 from results import NormalResultsFormatter, TemporaryRulesFormatter
75 from rules import Rule, Rules 76 from rules import Rule, Rules
76 77
77 78
78 # Variable name used in the DEPS file to add or subtract include files from 79 # Variable name used in the DEPS file to add or subtract include files from
79 # the module-level deps. 80 # the module-level deps.
80 INCLUDE_RULES_VAR_NAME = "include_rules" 81 INCLUDE_RULES_VAR_NAME = 'include_rules'
81 82
82 # Optionally present in the DEPS file to list subdirectories which should not 83 # Optionally present in the DEPS file to list subdirectories which should not
83 # be checked. This allows us to skip third party code, for example. 84 # be checked. This allows us to skip third party code, for example.
84 SKIP_SUBDIRS_VAR_NAME = "skip_child_includes" 85 SKIP_SUBDIRS_VAR_NAME = 'skip_child_includes'
85 86
86 87
87 def NormalizePath(path): 88 def NormalizePath(path):
88 """Returns a path normalized to how we write DEPS rules and compare paths. 89 """Returns a path normalized to how we write DEPS rules and compare paths.
89 """ 90 """
90 return path.lower().replace('\\', '/') 91 return path.lower().replace('\\', '/')
91 92
92 93
93 class DepsChecker(object): 94 class DepsChecker(object):
94 """Parses include_rules from DEPS files and can verify files in the 95 """Parses include_rules from DEPS files and can verify files in the
95 source tree against them. 96 source tree against them.
96 """ 97 """
97 98
98 def __init__(self, base_directory=None, verbose=False, being_tested=False): 99 def __init__(self, base_directory=None, verbose=False, being_tested=False):
99 """Creates a new DepsChecker. 100 """Creates a new DepsChecker.
100 101
101 Args: 102 Args:
102 base_directory: OS-compatible path to root of checkout, e.g. C:\chr\src. 103 base_directory: OS-compatible path to root of checkout, e.g. C:\chr\src.
103 verbose: Set to true for debug output. 104 verbose: Set to true for debug output.
104 being_tested: Set to true to ignore the DEPS file at tools/checkdeps/DEPS. 105 being_tested: Set to true to ignore the DEPS file at tools/checkdeps/DEPS.
105 """ 106 """
106 self.base_directory = base_directory 107 self.base_directory = base_directory
107 if not base_directory: 108 if not base_directory:
108 self.base_directory = os.path.abspath( 109 self.base_directory = os.path.abspath(
109 os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', '..')) 110 os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', '..'))
110 111
111 self.verbose = verbose 112 self.verbose = verbose
113 self.results_formatter = NormalResultsFormatter(verbose)
114
115 self._under_test = being_tested
112 116
113 self.git_source_directories = set() 117 self.git_source_directories = set()
114 self._AddGitSourceDirectories() 118 self._AddGitSourceDirectories()
115 119
116 self._under_test = being_tested 120 # Map of normalized directory paths to rules to use for those
121 # directories, or None for directories that should be skipped.
122 self.directory_rules = {}
123 self._ApplyDirectoryRulesAndSkipSubdirs(Rules(), self.base_directory)
124
125 def Report(self):
126 """Prints a report of results, and returns an exit code for the process."""
127 if self.results_formatter.GetResults():
128 self.results_formatter.PrintResults()
129 return 1
130 print '\nSUCCESS\n'
131 return 0
117 132
118 def _ApplyRules(self, existing_rules, includes, cur_dir): 133 def _ApplyRules(self, existing_rules, includes, cur_dir):
119 """Applies the given include rules, returning the new rules. 134 """Applies the given include rules, returning the new rules.
120 135
121 Args: 136 Args:
122 existing_rules: A set of existing rules that will be combined. 137 existing_rules: A set of existing rules that will be combined.
123 include: The list of rules from the "include_rules" section of DEPS. 138 include: The list of rules from the "include_rules" section of DEPS.
124 cur_dir: The current directory, normalized path. We will create an 139 cur_dir: The current directory, normalized path. We will create an
125 implicit rule that allows inclusion from this directory. 140 implicit rule that allows inclusion from this directory.
126 141
127 Returns: A new set of rules combining the existing_rules with the other 142 Returns: A new set of rules combining the existing_rules with the other
128 arguments. 143 arguments.
129 """ 144 """
130 rules = copy.copy(existing_rules) 145 rules = copy.copy(existing_rules)
131 146
132 # First apply the implicit "allow" rule for the current directory. 147 # First apply the implicit "allow" rule for the current directory.
133 if cur_dir.startswith( 148 if cur_dir.startswith(
134 NormalizePath(os.path.normpath(self.base_directory))): 149 NormalizePath(os.path.normpath(self.base_directory))):
135 relative_dir = cur_dir[len(self.base_directory) + 1:] 150 relative_dir = cur_dir[len(self.base_directory) + 1:]
136 151
137 source = relative_dir 152 source = relative_dir
138 if len(source) == 0: 153 if len(source) == 0:
139 source = "top level" # Make the help string a little more meaningful. 154 source = 'top level' # Make the help string a little more meaningful.
140 rules.AddRule("+" + relative_dir, "Default rule for " + source) 155 rules.AddRule('+' + relative_dir, 'Default rule for ' + source)
141 else: 156 else:
142 raise Exception("Internal error: base directory is not at the beginning" + 157 raise Exception('Internal error: base directory is not at the beginning' +
143 " for\n %s and base dir\n %s" % 158 ' for\n %s and base dir\n %s' %
144 (cur_dir, self.base_directory)) 159 (cur_dir, self.base_directory))
145 160
146 # Last, apply the additional explicit rules. 161 # Last, apply the additional explicit rules.
147 for (_, rule_str) in enumerate(includes): 162 for (_, rule_str) in enumerate(includes):
148 if not relative_dir: 163 if not relative_dir:
149 rule_description = "the top level include_rules" 164 rule_description = 'the top level include_rules'
150 else: 165 else:
151 rule_description = relative_dir + "'s include_rules" 166 rule_description = relative_dir + "'s include_rules"
152 rules.AddRule(rule_str, rule_description) 167 rules.AddRule(rule_str, rule_description)
153 168
154 return rules 169 return rules
155 170
156 def _ApplyDirectoryRules(self, existing_rules, dir_name): 171 def _ApplyDirectoryRules(self, existing_rules, dir_name):
157 """Combines rules from the existing rules and the new directory. 172 """Combines rules from the existing rules and the new directory.
158 173
159 Any directory can contain a DEPS file. Toplevel DEPS files can contain 174 Any directory can contain a DEPS file. Toplevel DEPS files can contain
(...skipping 15 matching lines...) Expand all
175 190
176 # Check for a .svn directory in this directory or check this directory is 191 # Check for a .svn directory in this directory or check this directory is
177 # contained in git source direcotries. This will tell us if it's a source 192 # contained in git source direcotries. This will tell us if it's a source
178 # directory and should be checked. 193 # directory and should be checked.
179 if not (os.path.exists(os.path.join(dir_name, ".svn")) or 194 if not (os.path.exists(os.path.join(dir_name, ".svn")) or
180 (norm_dir_name in self.git_source_directories)): 195 (norm_dir_name in self.git_source_directories)):
181 return (None, []) 196 return (None, [])
182 197
183 # Check the DEPS file in this directory. 198 # Check the DEPS file in this directory.
184 if self.verbose: 199 if self.verbose:
185 print "Applying rules from", dir_name 200 print 'Applying rules from', dir_name
186 def FromImpl(_unused, _unused2): 201 def FromImpl(_unused, _unused2):
187 pass # NOP function so "From" doesn't fail. 202 pass # NOP function so "From" doesn't fail.
188 203
189 def FileImpl(_unused): 204 def FileImpl(_unused):
190 pass # NOP function so "File" doesn't fail. 205 pass # NOP function so "File" doesn't fail.
191 206
192 class _VarImpl: 207 class _VarImpl:
193 def __init__(self, local_scope): 208 def __init__(self, local_scope):
194 self._local_scope = local_scope 209 self._local_scope = local_scope
195 210
196 def Lookup(self, var_name): 211 def Lookup(self, var_name):
197 """Implements the Var syntax.""" 212 """Implements the Var syntax."""
198 if var_name in self._local_scope.get("vars", {}): 213 if var_name in self._local_scope.get('vars', {}):
199 return self._local_scope["vars"][var_name] 214 return self._local_scope['vars'][var_name]
200 raise Exception("Var is not defined: %s" % var_name) 215 raise Exception('Var is not defined: %s' % var_name)
201 216
202 local_scope = {} 217 local_scope = {}
203 global_scope = { 218 global_scope = {
204 "File": FileImpl, 219 'File': FileImpl,
205 "From": FromImpl, 220 'From': FromImpl,
206 "Var": _VarImpl(local_scope).Lookup, 221 'Var': _VarImpl(local_scope).Lookup,
207 } 222 }
208 deps_file = os.path.join(dir_name, "DEPS") 223 deps_file = os.path.join(dir_name, 'DEPS')
209 224
210 # The second conditional here is to disregard the 225 # The second conditional here is to disregard the
211 # tools/checkdeps/DEPS file while running tests. This DEPS file 226 # tools/checkdeps/DEPS file while running tests. This DEPS file
212 # has a skip_child_includes for 'testdata' which is necessary for 227 # has a skip_child_includes for 'testdata' which is necessary for
213 # running production tests, since there are intentional DEPS 228 # running production tests, since there are intentional DEPS
214 # violations under the testdata directory. On the other hand when 229 # violations under the testdata directory. On the other hand when
215 # running tests, we absolutely need to verify the contents of that 230 # running tests, we absolutely need to verify the contents of that
216 # directory to trigger those intended violations and see that they 231 # directory to trigger those intended violations and see that they
217 # are handled correctly. 232 # are handled correctly.
218 if os.path.isfile(deps_file) and ( 233 if os.path.isfile(deps_file) and (
219 not self._under_test or not os.path.split(dir_name)[1] == 'checkdeps'): 234 not self._under_test or not os.path.split(dir_name)[1] == 'checkdeps'):
220 execfile(deps_file, global_scope, local_scope) 235 execfile(deps_file, global_scope, local_scope)
221 elif self.verbose: 236 elif self.verbose:
222 print " No deps file found in", dir_name 237 print ' No deps file found in', dir_name
223 238
224 # Even if a DEPS file does not exist we still invoke ApplyRules 239 # Even if a DEPS file does not exist we still invoke ApplyRules
225 # to apply the implicit "allow" rule for the current directory 240 # to apply the implicit "allow" rule for the current directory
226 include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, []) 241 include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, [])
227 skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, []) 242 skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, [])
228 243
229 return (self._ApplyRules(existing_rules, include_rules, norm_dir_name), 244 return (self._ApplyRules(existing_rules, include_rules, norm_dir_name),
230 skip_subdirs) 245 skip_subdirs)
231 246
247 def _ApplyDirectoryRulesAndSkipSubdirs(self, parent_rules, dir_path):
248 """Given |parent_rules| and a subdirectory |dir_path| from the
249 directory that owns the |parent_rules|, add |dir_path|'s rules to
250 |self.directory_rules|, and add None entries for any of its
251 subdirectories that should be skipped.
252 """
253 directory_rules, excluded_subdirs = self._ApplyDirectoryRules(parent_rules,
254 dir_path)
255 self.directory_rules[NormalizePath(dir_path)] = directory_rules
256 for subdir in excluded_subdirs:
257 self.directory_rules[NormalizePath(
258 os.path.normpath(os.path.join(dir_path, subdir)))] = None
259
260 def GetDirectoryRules(self, dir_path):
261 """Returns a Rules object to use for the given directory, or None
262 if the given directory should be skipped. This takes care of
263 first building rules for parent directories (up to
264 self.base_directory) if needed.
265
266 Args:
267 dir_path: A real (non-normalized) path to the directory you want
268 rules for.
269 """
270 norm_dir_path = NormalizePath(dir_path)
271
272 if not norm_dir_path.startswith(
273 NormalizePath(os.path.normpath(self.base_directory))):
274 dir_path = os.path.join(self.base_directory, dir_path)
275 norm_dir_path = NormalizePath(dir_path)
276
277 parent_dir = os.path.dirname(dir_path)
278 parent_rules = None
279 if not norm_dir_path in self.directory_rules:
280 parent_rules = self.GetDirectoryRules(parent_dir)
281
282 # We need to check for an entry for our dir_path again, in case we
283 # are at a path e.g. A/B/C where A/B/DEPS specifies the C
284 # subdirectory to be skipped; in this case, the invocation to
285 # GetDirectoryRules(parent_dir) has already filled in an entry for
286 # A/B/C.
287 if not norm_dir_path in self.directory_rules:
288 if not parent_rules:
289 # If the parent directory should be skipped, then the current
290 # directory should also be skipped.
291 self.directory_rules[norm_dir_path] = None
292 else:
293 self._ApplyDirectoryRulesAndSkipSubdirs(parent_rules, dir_path)
294 return self.directory_rules[norm_dir_path]
295
232 def CheckDirectory(self, start_dir): 296 def CheckDirectory(self, start_dir):
233 """Checks all relevant source files in the specified directory and 297 """Checks all relevant source files in the specified directory and
234 its subdirectories for compliance with DEPS rules throughout the 298 its subdirectories for compliance with DEPS rules throughout the
235 tree (starting at |self.base_directory|). |start_dir| must be a 299 tree (starting at |self.base_directory|). |start_dir| must be a
236 subdirectory of |self.base_directory|. 300 subdirectory of |self.base_directory|.
237 301
238 Returns an empty array on success. On failure, the array contains 302 On completion, self.results_formatter has the results of
239 strings that can be printed as human-readable error messages. 303 processing, and calling Report() will print a report of results.
240 """ 304 """
241 # TODO(joi): Make this work for start_dir != base_dir (I have a
242 # subsequent change in flight to do this).
243 base_rules = Rules()
244 java = java_checker.JavaChecker(self.base_directory, self.verbose) 305 java = java_checker.JavaChecker(self.base_directory, self.verbose)
245 cpp = cpp_checker.CppChecker(self.verbose) 306 cpp = cpp_checker.CppChecker(self.verbose)
246 checkers = dict( 307 checkers = dict(
247 (extension, checker) 308 (extension, checker)
248 for checker in [java, cpp] for extension in checker.EXTENSIONS) 309 for checker in [java, cpp] for extension in checker.EXTENSIONS)
249 return self._CheckDirectoryImpl(base_rules, checkers, start_dir) 310 self._CheckDirectoryImpl(checkers, start_dir)
250 311
251 def _CheckDirectoryImpl(self, parent_rules, checkers, dir_name): 312 def _CheckDirectoryImpl(self, checkers, dir_name):
252 (rules, skip_subdirs) = self._ApplyDirectoryRules(parent_rules, dir_name) 313 rules = self.GetDirectoryRules(dir_name)
253 if rules == None: 314 if rules == None:
254 return [] 315 return
255 316
256 # Collect a list of all files and directories to check. 317 # Collect a list of all files and directories to check.
257 files_to_check = [] 318 files_to_check = []
258 dirs_to_check = [] 319 dirs_to_check = []
259 results = []
260 contents = os.listdir(dir_name) 320 contents = os.listdir(dir_name)
261 for cur in contents: 321 for cur in contents:
262 if cur in skip_subdirs:
263 continue # Don't check children that DEPS has asked us to skip.
264 full_name = os.path.join(dir_name, cur) 322 full_name = os.path.join(dir_name, cur)
265 if os.path.isdir(full_name): 323 if os.path.isdir(full_name):
266 dirs_to_check.append(full_name) 324 dirs_to_check.append(full_name)
267 elif os.path.splitext(full_name)[1] in checkers: 325 elif os.path.splitext(full_name)[1] in checkers:
268 files_to_check.append(full_name) 326 files_to_check.append(full_name)
269 327
270 # First check all files in this directory. 328 # First check all files in this directory.
271 for cur in files_to_check: 329 for cur in files_to_check:
272 checker = checkers[os.path.splitext(cur)[1]] 330 checker = checkers[os.path.splitext(cur)[1]]
273 file_status = checker.CheckFile(rules, cur) 331 file_status = checker.CheckFile(rules, cur)
274 if file_status: 332 if file_status.HasViolations():
275 results.append("ERROR in " + cur + "\n" + file_status) 333 self.results_formatter.AddError(file_status)
276 334
277 # Next recurse into the subdirectories. 335 # Next recurse into the subdirectories.
278 for cur in dirs_to_check: 336 for cur in dirs_to_check:
279 results.extend(self._CheckDirectoryImpl(rules, checkers, cur)) 337 self._CheckDirectoryImpl(checkers, cur)
280 return results
281 338
282 def CheckAddedCppIncludes(self, added_includes): 339 def CheckAddedCppIncludes(self, added_includes):
283 """This is used from PRESUBMIT.py to check new #include statements added in 340 """This is used from PRESUBMIT.py to check new #include statements added in
284 the change being presubmit checked. 341 the change being presubmit checked.
285 342
286 Args: 343 Args:
287 added_includes: ((file_path, (include_line, include_line, ...), ...) 344 added_includes: ((file_path, (include_line, include_line, ...), ...)
288 345
289 Return: 346 Return:
290 A list of tuples, (bad_file_path, rule_type, rule_description) 347 A list of tuples, (bad_file_path, rule_type, rule_description)
291 where rule_type is one of Rule.DISALLOW or Rule.TEMP_ALLOW and 348 where rule_type is one of Rule.DISALLOW or Rule.TEMP_ALLOW and
292 rule_description is human-readable. Empty if no problems. 349 rule_description is human-readable. Empty if no problems.
293 """ 350 """
294 # Map of normalized directory paths to rules to use for those
295 # directories, or None for directories that should be skipped.
296 directory_rules = {}
297
298 def ApplyDirectoryRulesAndSkipSubdirs(parent_rules, dir_path):
299 rules_tuple = self._ApplyDirectoryRules(parent_rules, dir_path)
300 directory_rules[NormalizePath(dir_path)] = rules_tuple[0]
301 for subdir in rules_tuple[1]:
302 # We skip this one case for running tests.
303 directory_rules[NormalizePath(
304 os.path.normpath(os.path.join(dir_path, subdir)))] = None
305
306 ApplyDirectoryRulesAndSkipSubdirs(Rules(), self.base_directory)
307
308 def GetDirectoryRules(dir_path):
309 """Returns a Rules object to use for the given directory, or None
310 if the given directory should be skipped.
311 """
312 norm_dir_path = NormalizePath(dir_path)
313
314 if not dir_path.startswith(
315 NormalizePath(os.path.normpath(self.base_directory))):
316 dir_path = os.path.join(self.base_directory, dir_path)
317 norm_dir_path = NormalizePath(dir_path)
318
319 parent_dir = os.path.dirname(dir_path)
320 parent_rules = None
321 if not norm_dir_path in directory_rules:
322 parent_rules = GetDirectoryRules(parent_dir)
323
324 # We need to check for an entry for our dir_path again, in case we
325 # are at a path e.g. A/B/C where A/B/DEPS specifies the C
326 # subdirectory to be skipped; in this case, the invocation to
327 # GetDirectoryRules(parent_dir) has already filled in an entry for
328 # A/B/C.
329 if not norm_dir_path in directory_rules:
330 if not parent_rules:
331 # If the parent directory should be skipped, then the current
332 # directory should also be skipped.
333 directory_rules[norm_dir_path] = None
334 else:
335 ApplyDirectoryRulesAndSkipSubdirs(parent_rules, dir_path)
336 return directory_rules[norm_dir_path]
337
338 cpp = cpp_checker.CppChecker(self.verbose) 351 cpp = cpp_checker.CppChecker(self.verbose)
339
340 problems = [] 352 problems = []
341 for file_path, include_lines in added_includes: 353 for file_path, include_lines in added_includes:
342 # TODO(joi): Make this cover Java as well. 354 # TODO(joi): Make this cover Java as well.
343 if not cpp.IsCppFile(file_path): 355 if not cpp.IsCppFile(file_path):
344 pass 356 pass
345 rules_for_file = GetDirectoryRules(os.path.dirname(file_path)) 357 rules_for_file = self.GetDirectoryRules(os.path.dirname(file_path))
346 if rules_for_file: 358 if rules_for_file:
347 for line in include_lines: 359 for line in include_lines:
348 is_include, line_status, rule_type = cpp.CheckLine( 360 is_include, violation = cpp.CheckLine(rules_for_file, line, True)
349 rules_for_file, line, True) 361 if violation:
350 if rule_type != Rule.ALLOW: 362 rule_type = violation.violated_rule.allow
351 problems.append((file_path, rule_type, line_status)) 363 if rule_type != Rule.ALLOW:
364 violation_text = NormalResultsFormatter.FormatViolation(
365 violation, self.verbose)
366 problems.append((file_path, rule_type, violation_text))
352 return problems 367 return problems
353 368
354 def _AddGitSourceDirectories(self): 369 def _AddGitSourceDirectories(self):
355 """Adds any directories containing sources managed by git to 370 """Adds any directories containing sources managed by git to
356 self.git_source_directories. 371 self.git_source_directories.
357 """ 372 """
358 if not os.path.exists(os.path.join(self.base_directory, ".git")): 373 if not os.path.exists(os.path.join(self.base_directory, '.git')):
359 return 374 return
360 375
361 popen_out = os.popen("cd %s && git ls-files --full-name ." % 376 popen_out = os.popen('cd %s && git ls-files --full-name .' %
362 subprocess.list2cmdline([self.base_directory])) 377 subprocess.list2cmdline([self.base_directory]))
363 for line in popen_out.readlines(): 378 for line in popen_out.readlines():
364 dir_name = os.path.join(self.base_directory, os.path.dirname(line)) 379 dir_name = os.path.join(self.base_directory, os.path.dirname(line))
365 # Add the directory as well as all the parent directories. Use 380 # Add the directory as well as all the parent directories. Use
366 # forward slashes and lower case to normalize paths. 381 # forward slashes and lower case to normalize paths.
367 while dir_name != self.base_directory: 382 while dir_name != self.base_directory:
368 self.git_source_directories.add(NormalizePath(dir_name)) 383 self.git_source_directories.add(NormalizePath(dir_name))
369 dir_name = os.path.dirname(dir_name) 384 dir_name = os.path.dirname(dir_name)
370 self.git_source_directories.add(NormalizePath(self.base_directory)) 385 self.git_source_directories.add(NormalizePath(self.base_directory))
371 386
372 387
373 def PrintUsage(): 388 def PrintUsage():
374 print """Usage: python checkdeps.py [--root <root>] [tocheck] 389 print """Usage: python checkdeps.py [--root <root>] [tocheck]
375 390
376 --root Specifies the repository root. This defaults to "../../.." relative 391 --root Specifies the repository root. This defaults to "../../.." relative
377 to the script file. This will be correct given the normal location 392 to the script file. This will be correct given the normal location
378 of the script in "<root>/tools/checkdeps". 393 of the script in "<root>/tools/checkdeps".
379 394
380 tocheck Specifies the directory, relative to root, to check. This defaults 395 tocheck Specifies the directory, relative to root, to check. This defaults
381 to "." so it checks everything. Only one level deep is currently 396 to "." so it checks everything.
382 supported, so you can say "chrome" but not "chrome/browser".
383 397
384 Examples: 398 Examples:
385 python checkdeps.py 399 python checkdeps.py
386 python checkdeps.py --root c:\\source chrome""" 400 python checkdeps.py --root c:\\source chrome"""
387 401
388 402
389 def main(): 403 def main():
390 option_parser = optparse.OptionParser() 404 option_parser = optparse.OptionParser()
391 option_parser.add_option("", "--root", default="", dest="base_directory", 405 option_parser.add_option('', '--root', default='', dest='base_directory',
392 help='Specifies the repository root. This defaults ' 406 help='Specifies the repository root. This defaults '
393 'to "../../.." relative to the script file, which ' 407 'to "../../.." relative to the script file, which '
394 'will normally be the repository root.') 408 'will normally be the repository root.')
395 option_parser.add_option("-v", "--verbose", action="store_true", 409 option_parser.add_option('', '--temprules', action='store_true',
396 default=False, help="Print debug logging") 410 default=False, help='Print rules to temporarily '
411 'allow files that fail dependency checking.')
412 option_parser.add_option('-v', '--verbose', action='store_true',
413 default=False, help='Print debug logging')
397 options, args = option_parser.parse_args() 414 options, args = option_parser.parse_args()
398 415
399 deps_checker = DepsChecker(options.base_directory, options.verbose) 416 deps_checker = DepsChecker(options.base_directory, verbose=options.verbose)
400 417
401 # Figure out which directory we have to check. 418 # Figure out which directory we have to check.
402 start_dir = deps_checker.base_directory 419 start_dir = deps_checker.base_directory
403 if len(args) == 1: 420 if len(args) == 1:
404 # Directory specified. Start here. It's supposed to be relative to the 421 # Directory specified. Start here. It's supposed to be relative to the
405 # base directory. 422 # base directory.
406 start_dir = os.path.abspath( 423 start_dir = os.path.abspath(
407 os.path.join(deps_checker.base_directory, args[0])) 424 os.path.join(deps_checker.base_directory, args[0]))
408 elif len(args) >= 2: 425 elif len(args) >= 2:
409 # More than one argument, we don't handle this. 426 # More than one argument, we don't handle this.
410 PrintUsage() 427 PrintUsage()
411 return 1 428 return 1
412 429
413 print "Using base directory:", deps_checker.base_directory 430 print 'Using base directory:', deps_checker.base_directory
414 print "Checking:", start_dir 431 print 'Checking:', start_dir
415 432
416 results = deps_checker.CheckDirectory(start_dir) 433 if options.temprules:
417 if results: 434 deps_checker.results_formatter = TemporaryRulesFormatter()
418 for result in results: 435 deps_checker.CheckDirectory(start_dir)
419 print result 436 return deps_checker.Report()
420 print "\nFAILED\n"
421 return 1
422 print "\nSUCCESS\n"
423 return 0
424 437
425 438
426 if '__main__' == __name__: 439 if '__main__' == __name__:
427 sys.exit(main()) 440 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tools/checkdeps/checkdeps_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698