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

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: 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/checker.py » ('j') | tools/checkdeps/checker.py » ('J')
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 checker
M-A Ruel 2012/07/17 14:23:20 No need to import 'checker'. Furthermore doing tha
Iain Merrick 2012/07/17 15:55:08 That's sorta what I had originally, then I was con
63 import cpp_checker
64 import java_checker
65
66
62 # Variable name used in the DEPS file to add or subtract include files from 67 # Variable name used in the DEPS file to add or subtract include files from
63 # the module-level deps. 68 # the module-level deps.
64 INCLUDE_RULES_VAR_NAME = "include_rules" 69 INCLUDE_RULES_VAR_NAME = "include_rules"
65 70
66 # Optionally present in the DEPS file to list subdirectories which should not 71 # 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. 72 # be checked. This allows us to skip third party code, for example.
68 SKIP_SUBDIRS_VAR_NAME = "skip_child_includes" 73 SKIP_SUBDIRS_VAR_NAME = "skip_child_includes"
69 74
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. 75 # Set to true for more output. This is set by the command line options.
78 VERBOSE = False 76 VERBOSE = False
79 77
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 78 # In lowercase, using forward slashes as directory separators, ending in a
85 # forward slash. Set by the command line options. 79 # forward slash. Set by the command line options.
86 BASE_DIRECTORY = "" 80 BASE_DIRECTORY = ""
87 81
88 # The directories which contain the sources managed by git. 82 # The directories which contain the sources managed by git.
89 GIT_SOURCE_DIRECTORY = set() 83 GIT_SOURCE_DIRECTORY = set()
90 84
91 85
92 # Specifies a single rule for an include, which can be either allow or disallow. 86 # Specifies a single rule for an include, which can be either allow or disallow.
93 class Rule(object): 87 class Rule(object):
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 print " No deps file found in", dir_name 257 print " No deps file found in", dir_name
264 258
265 # Even if a DEPS file does not exist we still invoke ApplyRules 259 # Even if a DEPS file does not exist we still invoke ApplyRules
266 # to apply the implicit "allow" rule for the current directory 260 # to apply the implicit "allow" rule for the current directory
267 include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, []) 261 include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, [])
268 skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, []) 262 skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, [])
269 263
270 return (ApplyRules(existing_rules, include_rules, dir_name), skip_subdirs) 264 return (ApplyRules(existing_rules, include_rules, dir_name), skip_subdirs)
271 265
272 266
273 def ShouldCheckFile(file_name): 267 def CheckDirectory(parent_rules, checker_factory, 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) 268 (rules, skip_subdirs) = ApplyDirectoryRules(parent_rules, dir_name)
379 if rules == None: 269 if rules == None:
380 return True 270 return True
381 271
382 # Collect a list of all files and directories to check. 272 # Collect a list of all files and directories to check.
383 files_to_check = [] 273 files_to_check = []
384 dirs_to_check = [] 274 dirs_to_check = []
385 success = True 275 success = True
386 contents = os.listdir(dir_name) 276 contents = os.listdir(dir_name)
387 for cur in contents: 277 for cur in contents:
388 if cur in skip_subdirs: 278 if cur in skip_subdirs:
389 continue # Don't check children that DEPS has asked us to skip. 279 continue # Don't check children that DEPS has asked us to skip.
390 full_name = os.path.join(dir_name, cur) 280 full_name = os.path.join(dir_name, cur)
391 if os.path.isdir(full_name): 281 if os.path.isdir(full_name):
392 dirs_to_check.append(full_name) 282 dirs_to_check.append(full_name)
393 elif ShouldCheckFile(full_name): 283 elif checker_factory.GetChecker(full_name):
394 files_to_check.append(full_name) 284 files_to_check.append(full_name)
395 285
396 # First check all files in this directory. 286 # First check all files in this directory.
397 for cur in files_to_check: 287 for cur in files_to_check:
398 file_status = CheckFile(rules, cur) 288 checker = checker_factory.GetChecker(cur)
289 file_status = checker.CheckFile(rules, cur)
399 if file_status != None: 290 if file_status != None:
M-A Ruel 2012/07/17 14:23:20 if file_status: Then you can remove the weird che
Iain Merrick 2012/07/17 15:55:08 Done.
400 print "ERROR in " + cur + "\n" + file_status 291 print "ERROR in " + cur + "\n" + file_status
401 success = False 292 success = False
402 293
403 # Next recurse into the subdirectories. 294 # Next recurse into the subdirectories.
404 for cur in dirs_to_check: 295 for cur in dirs_to_check:
405 if not CheckDirectory(rules, cur): 296 if not CheckDirectory(rules, checker_factory, cur):
406 success = False 297 success = False
407 298
408 return success 299 return success
409 300
410 301
411 def GetGitSourceDirectory(root): 302 def GetGitSourceDirectory(root):
412 """Returns a set of the directories to be checked. 303 """Returns a set of the directories to be checked.
413 304
414 Args: 305 Args:
415 root: The repository root where .git directory exists. 306 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 372 # systems. Plus, we always use slashes here since the include parsing code
482 # will also normalize to slashes. 373 # will also normalize to slashes.
483 BASE_DIRECTORY = BASE_DIRECTORY.lower() 374 BASE_DIRECTORY = BASE_DIRECTORY.lower()
484 BASE_DIRECTORY = BASE_DIRECTORY.replace("\\", "/") 375 BASE_DIRECTORY = BASE_DIRECTORY.replace("\\", "/")
485 start_dir = start_dir.replace("\\", "/") 376 start_dir = start_dir.replace("\\", "/")
486 377
487 if os.path.exists(os.path.join(BASE_DIRECTORY, ".git")): 378 if os.path.exists(os.path.join(BASE_DIRECTORY, ".git")):
488 global GIT_SOURCE_DIRECTORY 379 global GIT_SOURCE_DIRECTORY
489 GIT_SOURCE_DIRECTORY = GetGitSourceDirectory(BASE_DIRECTORY) 380 GIT_SOURCE_DIRECTORY = GetGitSourceDirectory(BASE_DIRECTORY)
490 381
491 success = CheckDirectory(base_rules, start_dir) 382 checker_factory = checker.Factory(BASE_DIRECTORY, VERBOSE)
383 success = CheckDirectory(base_rules, checker_factory, start_dir)
492 if not success: 384 if not success:
493 print "\nFAILED\n" 385 print "\nFAILED\n"
494 return 1 386 return 1
495 print "\nSUCCESS\n" 387 print "\nSUCCESS\n"
496 return 0 388 return 0
497 389
498 390
499 def main(): 391 def main():
500 option_parser = optparse.OptionParser() 392 option_parser = optparse.OptionParser()
501 option_parser.add_option("", "--root", default="", dest="base_directory", 393 option_parser.add_option("", "--root", default="", dest="base_directory",
502 help='Specifies the repository root. This defaults ' 394 help='Specifies the repository root. This defaults '
503 'to "../../.." relative to the script file, which ' 395 'to "../../.." relative to the script file, which '
504 'will normally be the repository root.') 396 'will normally be the repository root.')
505 option_parser.add_option("-v", "--verbose", action="store_true", 397 option_parser.add_option("-v", "--verbose", action="store_true",
506 default=False, help="Print debug logging") 398 default=False, help="Print debug logging")
507 options, args = option_parser.parse_args() 399 options, args = option_parser.parse_args()
508 return checkdeps(options, args) 400 return checkdeps(options, args)
509 401
510 402
511 if '__main__' == __name__: 403 if '__main__' == __name__:
512 sys.exit(main()) 404 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tools/checkdeps/checker.py » ('j') | tools/checkdeps/checker.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698