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

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

Issue 10790014: Add Java support to checkdeps.py (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: More cleanup Created 8 years, 5 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
« no previous file with comments | « no previous file | tools/checkdeps/cpp_checker.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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 only lowercase. 52 only lowercase.
53 """ 53 """
54 54
55 import os 55 import os
56 import optparse 56 import optparse
57 import pipes 57 import pipes
58 import re 58 import re
59 import sys 59 import sys
60 import copy 60 import copy
61 61
62 import cpp_checker
63 import java_checker
64
65
62 # Variable name used in the DEPS file to add or subtract include files from 66 # Variable name used in the DEPS file to add or subtract include files from
63 # the module-level deps. 67 # the module-level deps.
64 INCLUDE_RULES_VAR_NAME = "include_rules" 68 INCLUDE_RULES_VAR_NAME = "include_rules"
65 69
66 # Optionally present in the DEPS file to list subdirectories which should not 70 # Optionally present in the DEPS file to list subdirectories which should not
67 # be checked. This allows us to skip third party code, for example. 71 # be checked. This allows us to skip third party code, for example.
68 SKIP_SUBDIRS_VAR_NAME = "skip_child_includes" 72 SKIP_SUBDIRS_VAR_NAME = "skip_child_includes"
69 73
70 # The maximum number of non-include lines we can see before giving up.
71 MAX_UNINTERESTING_LINES = 50
72
73 # The maximum line length, this is to be efficient in the case of very long
74 # lines (which can't be #includes).
75 MAX_LINE_LENGTH = 128
76
77 # Set to true for more output. This is set by the command line options. 74 # Set to true for more output. This is set by the command line options.
78 VERBOSE = False 75 VERBOSE = False
79 76
80 # This regular expression will be used to extract filenames from include
81 # statements.
82 EXTRACT_INCLUDE_PATH = re.compile('[ \t]*#[ \t]*(?:include|import)[ \t]+"(.*)"')
83
84 # In lowercase, using forward slashes as directory separators, ending in a 77 # In lowercase, using forward slashes as directory separators, ending in a
85 # forward slash. Set by the command line options. 78 # forward slash. Set by the command line options.
86 BASE_DIRECTORY = "" 79 BASE_DIRECTORY = ""
87 80
88 # The directories which contain the sources managed by git. 81 # The directories which contain the sources managed by git.
89 GIT_SOURCE_DIRECTORY = set() 82 GIT_SOURCE_DIRECTORY = set()
90 83
91 84
92 # Specifies a single rule for an include, which can be either allow or disallow. 85 # Specifies a single rule for an include, which can be either allow or disallow.
93 class Rule(object): 86 class Rule(object):
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 print " No deps file found in", dir_name 256 print " No deps file found in", dir_name
264 257
265 # Even if a DEPS file does not exist we still invoke ApplyRules 258 # Even if a DEPS file does not exist we still invoke ApplyRules
266 # to apply the implicit "allow" rule for the current directory 259 # to apply the implicit "allow" rule for the current directory
267 include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, []) 260 include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, [])
268 skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, []) 261 skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, [])
269 262
270 return (ApplyRules(existing_rules, include_rules, dir_name), skip_subdirs) 263 return (ApplyRules(existing_rules, include_rules, dir_name), skip_subdirs)
271 264
272 265
273 def ShouldCheckFile(file_name): 266 def CheckDirectory(parent_rules, checkers, dir_name):
274 """Returns True if the given file is a type we want to check."""
275 checked_extensions = [
276 '.h',
277 '.cc',
278 '.m',
279 '.mm',
280 ]
281 basename, extension = os.path.splitext(file_name)
282 return extension in checked_extensions
283
284
285 def CheckLine(rules, line):
286 """Checks the given file with the given rule set.
287 Returns a tuple (is_include, illegal_description).
288 If the line is an #include directive the first value will be True.
289 If it is also an illegal include, the second value will be a string describing
290 the error. Otherwise, it will be None."""
291 found_item = EXTRACT_INCLUDE_PATH.match(line)
292 if not found_item:
293 return False, None # Not a match
294
295 include_path = found_item.group(1)
296
297 # Fix up backslashes in case somebody accidentally used them.
298 include_path.replace("\\", "/")
299
300 if include_path.find("/") < 0:
301 # Don't fail when no directory is specified. We may want to be more
302 # strict about this in the future.
303 if VERBOSE:
304 print " WARNING: directory specified with no path: " + include_path
305 return True, None
306
307 (allowed, why_failed) = rules.DirAllowed(include_path)
308 if not allowed:
309 if VERBOSE:
310 retval = "\nFor " + rules.__str__()
311 else:
312 retval = ""
313 return True, retval + ('Illegal include: "%s"\n Because of %s' %
314 (include_path, why_failed))
315
316 return True, None
317
318
319 def CheckFile(rules, file_name):
320 """Checks the given file with the given rule set.
321
322 Args:
323 rules: The set of rules that apply to files in this directory.
324 file_name: The source file to check.
325
326 Returns: Either a string describing the error if there was one, or None if
327 the file checked out OK.
328 """
329 if VERBOSE:
330 print "Checking: " + file_name
331
332 ret_val = "" # We'll collect the error messages in here
333 last_include = 0
334 try:
335 cur_file = open(file_name, "r")
336 in_if0 = 0
337 for line_num in xrange(sys.maxint):
338 if line_num - last_include > MAX_UNINTERESTING_LINES:
339 break
340
341 cur_line = cur_file.readline(MAX_LINE_LENGTH)
342 if cur_line == "":
343 break
344 cur_line = cur_line.strip()
345
346 # Check to see if we're at / inside a #if 0 block
347 if cur_line == '#if 0':
348 in_if0 += 1
349 continue
350 if in_if0 > 0:
351 if cur_line.startswith('#if'):
352 in_if0 += 1
353 elif cur_line == '#endif':
354 in_if0 -= 1
355 continue
356
357 is_include, line_status = CheckLine(rules, cur_line)
358 if is_include:
359 last_include = line_num
360 if line_status is not None:
361 if len(line_status) > 0: # Add newline to separate messages.
362 line_status += "\n"
363 ret_val += line_status
364 cur_file.close()
365
366 except IOError:
367 if VERBOSE:
368 print "Unable to open file: " + file_name
369 cur_file.close()
370
371 # Map empty string to None for easier checking.
372 if len(ret_val) == 0:
373 return None
374 return ret_val
375
376
377 def CheckDirectory(parent_rules, dir_name):
378 (rules, skip_subdirs) = ApplyDirectoryRules(parent_rules, dir_name) 267 (rules, skip_subdirs) = ApplyDirectoryRules(parent_rules, dir_name)
379 if rules == None: 268 if rules == None:
380 return True 269 return True
381 270
382 # Collect a list of all files and directories to check. 271 # Collect a list of all files and directories to check.
383 files_to_check = [] 272 files_to_check = []
384 dirs_to_check = [] 273 dirs_to_check = []
385 success = True 274 success = True
386 contents = os.listdir(dir_name) 275 contents = os.listdir(dir_name)
387 for cur in contents: 276 for cur in contents:
388 if cur in skip_subdirs: 277 if cur in skip_subdirs:
389 continue # Don't check children that DEPS has asked us to skip. 278 continue # Don't check children that DEPS has asked us to skip.
390 full_name = os.path.join(dir_name, cur) 279 full_name = os.path.join(dir_name, cur)
391 if os.path.isdir(full_name): 280 if os.path.isdir(full_name):
392 dirs_to_check.append(full_name) 281 dirs_to_check.append(full_name)
393 elif ShouldCheckFile(full_name): 282 elif os.path.splitext(full_name)[1] in checkers:
394 files_to_check.append(full_name) 283 files_to_check.append(full_name)
395 284
396 # First check all files in this directory. 285 # First check all files in this directory.
397 for cur in files_to_check: 286 for cur in files_to_check:
398 file_status = CheckFile(rules, cur) 287 checker = checkers[os.path.splitext(cur)[1]]
399 if file_status != None: 288 file_status = checker.CheckFile(rules, cur)
289 if file_status:
400 print "ERROR in " + cur + "\n" + file_status 290 print "ERROR in " + cur + "\n" + file_status
401 success = False 291 success = False
402 292
403 # Next recurse into the subdirectories. 293 # Next recurse into the subdirectories.
404 for cur in dirs_to_check: 294 for cur in dirs_to_check:
405 if not CheckDirectory(rules, cur): 295 if not CheckDirectory(rules, checkers, cur):
406 success = False 296 success = False
407 297
408 return success 298 return success
409 299
410 300
411 def GetGitSourceDirectory(root): 301 def GetGitSourceDirectory(root):
412 """Returns a set of the directories to be checked. 302 """Returns a set of the directories to be checked.
413 303
414 Args: 304 Args:
415 root: The repository root where .git directory exists. 305 root: The repository root where .git directory exists.
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 # systems. Plus, we always use slashes here since the include parsing code 371 # systems. Plus, we always use slashes here since the include parsing code
482 # will also normalize to slashes. 372 # will also normalize to slashes.
483 BASE_DIRECTORY = BASE_DIRECTORY.lower() 373 BASE_DIRECTORY = BASE_DIRECTORY.lower()
484 BASE_DIRECTORY = BASE_DIRECTORY.replace("\\", "/") 374 BASE_DIRECTORY = BASE_DIRECTORY.replace("\\", "/")
485 start_dir = start_dir.replace("\\", "/") 375 start_dir = start_dir.replace("\\", "/")
486 376
487 if os.path.exists(os.path.join(BASE_DIRECTORY, ".git")): 377 if os.path.exists(os.path.join(BASE_DIRECTORY, ".git")):
488 global GIT_SOURCE_DIRECTORY 378 global GIT_SOURCE_DIRECTORY
489 GIT_SOURCE_DIRECTORY = GetGitSourceDirectory(BASE_DIRECTORY) 379 GIT_SOURCE_DIRECTORY = GetGitSourceDirectory(BASE_DIRECTORY)
490 380
491 success = CheckDirectory(base_rules, start_dir) 381 java = java_checker.JavaChecker(BASE_DIRECTORY, VERBOSE)
382 cpp = cpp_checker.CppChecker(VERBOSE)
383 checkers = dict((extension, checker)
M-A Ruel 2012/07/20 12:53:27 Weird alignment. Either all at +4 or at (. But I p
Iain Merrick 2012/07/23 14:22:09 Done.
384 for checker in [java, cpp] for extension in checker.EXTENSIONS)
385 success = CheckDirectory(base_rules, checkers, start_dir)
492 if not success: 386 if not success:
493 print "\nFAILED\n" 387 print "\nFAILED\n"
494 return 1 388 return 1
495 print "\nSUCCESS\n" 389 print "\nSUCCESS\n"
496 return 0 390 return 0
497 391
498 392
499 def main(): 393 def main():
500 option_parser = optparse.OptionParser() 394 option_parser = optparse.OptionParser()
501 option_parser.add_option("", "--root", default="", dest="base_directory", 395 option_parser.add_option("", "--root", default="", dest="base_directory",
502 help='Specifies the repository root. This defaults ' 396 help='Specifies the repository root. This defaults '
503 'to "../../.." relative to the script file, which ' 397 'to "../../.." relative to the script file, which '
504 'will normally be the repository root.') 398 'will normally be the repository root.')
505 option_parser.add_option("-v", "--verbose", action="store_true", 399 option_parser.add_option("-v", "--verbose", action="store_true",
506 default=False, help="Print debug logging") 400 default=False, help="Print debug logging")
507 options, args = option_parser.parse_args() 401 options, args = option_parser.parse_args()
508 return checkdeps(options, args) 402 return checkdeps(options, args)
509 403
510 404
511 if '__main__' == __name__: 405 if '__main__' == __name__:
512 sys.exit(main()) 406 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tools/checkdeps/cpp_checker.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698