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

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: . 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') | tools/checkdeps/java_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 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 import results
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 = results.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 the current
erikwright (departed) 2012/07/31 17:22:45 'current directory' is a bit confusing here. I ass
Jói 2012/08/01 15:22:58 Done.
250 directory's rules to |self.directory_rules|, and add None entries
251 for any of its subdirectories that should be skipped.
252 """
253 rules_tuple = self._ApplyDirectoryRules(parent_rules, dir_path)
erikwright (departed) 2012/07/31 17:22:45 For documentation, might I suggest something like:
Jói 2012/08/01 15:22:58 Done.
254 self.directory_rules[NormalizePath(dir_path)] = rules_tuple[0]
255 for subdir in rules_tuple[1]:
256 # We skip this one case for running tests.
erikwright (departed) 2012/07/31 17:22:45 This comment is confusing and probably unnecessary
Jói 2012/08/01 15:22:58 Whoops, it was something I meant to remove along w
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 dir_path.startswith(
erikwright (departed) 2012/07/31 17:22:45 shouldn't this be 'if not norm_dir_path.startswith
Jói 2012/08/01 15:22:58 Quite right, fixed.
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 Returns an empty array on success. On failure, the array contains
239 strings that can be printed as human-readable error messages. 303 strings that can be printed as human-readable error messages.
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 return self._CheckDirectoryImpl(checkers, start_dir)
erikwright (departed) 2012/07/31 17:22:46 It seems that you need to change this statement to
Jói 2012/08/01 15:22:58 Done.
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 formatter = results.NormalResultsFormatter(False)
365 violation_lines = formatter.FormatViolation(violation)
366 problems.append((file_path, rule_type,
367 '\n'.join(violation_lines)))
352 return problems 368 return problems
353 369
354 def _AddGitSourceDirectories(self): 370 def _AddGitSourceDirectories(self):
355 """Adds any directories containing sources managed by git to 371 """Adds any directories containing sources managed by git to
356 self.git_source_directories. 372 self.git_source_directories.
357 """ 373 """
358 if not os.path.exists(os.path.join(self.base_directory, ".git")): 374 if not os.path.exists(os.path.join(self.base_directory, '.git')):
359 return 375 return
360 376
361 popen_out = os.popen("cd %s && git ls-files --full-name ." % 377 popen_out = os.popen('cd %s && git ls-files --full-name .' %
362 subprocess.list2cmdline([self.base_directory])) 378 subprocess.list2cmdline([self.base_directory]))
363 for line in popen_out.readlines(): 379 for line in popen_out.readlines():
364 dir_name = os.path.join(self.base_directory, os.path.dirname(line)) 380 dir_name = os.path.join(self.base_directory, os.path.dirname(line))
365 # Add the directory as well as all the parent directories. Use 381 # Add the directory as well as all the parent directories. Use
366 # forward slashes and lower case to normalize paths. 382 # forward slashes and lower case to normalize paths.
367 while dir_name != self.base_directory: 383 while dir_name != self.base_directory:
368 self.git_source_directories.add(NormalizePath(dir_name)) 384 self.git_source_directories.add(NormalizePath(dir_name))
369 dir_name = os.path.dirname(dir_name) 385 dir_name = os.path.dirname(dir_name)
370 self.git_source_directories.add(NormalizePath(self.base_directory)) 386 self.git_source_directories.add(NormalizePath(self.base_directory))
371 387
372 388
373 def PrintUsage(): 389 def PrintUsage():
374 print """Usage: python checkdeps.py [--root <root>] [tocheck] 390 print """Usage: python checkdeps.py [--root <root>] [tocheck]
375 391
376 --root Specifies the repository root. This defaults to "../../.." relative 392 --root Specifies the repository root. This defaults to "../../.." relative
377 to the script file. This will be correct given the normal location 393 to the script file. This will be correct given the normal location
378 of the script in "<root>/tools/checkdeps". 394 of the script in "<root>/tools/checkdeps".
379 395
380 tocheck Specifies the directory, relative to root, to check. This defaults 396 tocheck Specifies the directory, relative to root, to check. This defaults
381 to "." so it checks everything. Only one level deep is currently 397 to "." so it checks everything.
382 supported, so you can say "chrome" but not "chrome/browser".
383 398
384 Examples: 399 Examples:
385 python checkdeps.py 400 python checkdeps.py
386 python checkdeps.py --root c:\\source chrome""" 401 python checkdeps.py --root c:\\source chrome"""
387 402
388 403
389 def main(): 404 def main():
390 option_parser = optparse.OptionParser() 405 option_parser = optparse.OptionParser()
391 option_parser.add_option("", "--root", default="", dest="base_directory", 406 option_parser.add_option('', '--root', default='', dest='base_directory',
392 help='Specifies the repository root. This defaults ' 407 help='Specifies the repository root. This defaults '
393 'to "../../.." relative to the script file, which ' 408 'to "../../.." relative to the script file, which '
394 'will normally be the repository root.') 409 'will normally be the repository root.')
395 option_parser.add_option("-v", "--verbose", action="store_true", 410 option_parser.add_option('', '--temprules', action='store_true',
396 default=False, help="Print debug logging") 411 default=False, help='Print rules to temporarily '
412 'allow files that fail dependency checking.')
413 option_parser.add_option('-v', '--verbose', action='store_true',
414 default=False, help='Print debug logging')
397 options, args = option_parser.parse_args() 415 options, args = option_parser.parse_args()
398 416
399 deps_checker = DepsChecker(options.base_directory, options.verbose) 417 deps_checker = DepsChecker(options.base_directory, verbose=options.verbose)
400 418
401 # Figure out which directory we have to check. 419 # Figure out which directory we have to check.
402 start_dir = deps_checker.base_directory 420 start_dir = deps_checker.base_directory
403 if len(args) == 1: 421 if len(args) == 1:
404 # Directory specified. Start here. It's supposed to be relative to the 422 # Directory specified. Start here. It's supposed to be relative to the
405 # base directory. 423 # base directory.
406 start_dir = os.path.abspath( 424 start_dir = os.path.abspath(
407 os.path.join(deps_checker.base_directory, args[0])) 425 os.path.join(deps_checker.base_directory, args[0]))
408 elif len(args) >= 2: 426 elif len(args) >= 2:
409 # More than one argument, we don't handle this. 427 # More than one argument, we don't handle this.
410 PrintUsage() 428 PrintUsage()
411 return 1 429 return 1
412 430
413 print "Using base directory:", deps_checker.base_directory 431 print 'Using base directory:', deps_checker.base_directory
414 print "Checking:", start_dir 432 print 'Checking:', start_dir
415 433
416 results = deps_checker.CheckDirectory(start_dir) 434 if options.temprules:
417 if results: 435 deps_checker.results_formatter = results.TemporaryRulesFormatter()
418 for result in results: 436 deps_checker.CheckDirectory(start_dir)
419 print result 437 return deps_checker.Report()
420 print "\nFAILED\n"
421 return 1
422 print "\nSUCCESS\n"
423 return 0
424 438
425 439
426 if '__main__' == __name__: 440 if '__main__' == __name__:
427 sys.exit(main()) 441 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tools/checkdeps/checkdeps_test.py » ('j') | tools/checkdeps/java_checker.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698