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

Unified Diff: tools/checkdeps/checkdeps.py

Issue 10805042: Implement ability to specify temporarily-allowed dependencies in DEPS (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Respond to review comments. Add automated unit tests. 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 side-by-side diff with in-line comments
Download patch
Index: tools/checkdeps/checkdeps.py
diff --git a/tools/checkdeps/checkdeps.py b/tools/checkdeps/checkdeps.py
index 9624812086a0d732db98a5a0e5825d4bad09b739..e122de581095ad1743087c861bac2eb048425512 100755
--- a/tools/checkdeps/checkdeps.py
+++ b/tools/checkdeps/checkdeps.py
@@ -18,9 +18,17 @@ gclient. An example would be:
"base":"http://foo.bar/trunk/base"
}
-DEPS files not in the top-level of a module won't need this. Then you have
-any additional include rules. You can add (using "+") or subtract (using "-")
-from the previously specified rules (including module-level deps).
+DEPS files not in the top-level of a module won't need this. Then you
+have any additional include rules. You can add (using "+") or subtract
+(using "-") from the previously specified rules (including
+module-level deps). You can also specify a path that is allowed for
+now but that we intend to remove, using "!"; this is treated the same
+as "+" when check_deps is run by our bots, but a presubmit step will
+show a warning if you add a new include of a file that is only allowed
+by "!".
+
+Note that for .java files, there is currently no difference between
+"+" and "!", even in the presubmit step.
include_rules = {
# Code should be able to use base (it's specified in the module-level
@@ -32,7 +40,11 @@ from the previously specified rules (including module-level deps).
# And it can include files from this other directory even though there is
# no deps rule for it.
- "+tools/crime_fighter"
+ "+tools/crime_fighter",
+
+ # This dependency is allowed for now but work is ongoing to remove it,
+ # so you shouldn't add further dependencies on it.
+ "!base/evil/ok_for_now.h",
}
DEPS files may be placed anywhere in the tree. Each one applies to all
@@ -54,12 +66,13 @@ only lowercase.
import os
import optparse
-import pipes
+import subprocess
import sys
import copy
import cpp_checker
import java_checker
+from rules import Rule, Rules
# Variable name used in the DEPS file to add or subtract include files from
@@ -70,253 +83,277 @@ INCLUDE_RULES_VAR_NAME = "include_rules"
# be checked. This allows us to skip third party code, for example.
SKIP_SUBDIRS_VAR_NAME = "skip_child_includes"
-# Set to true for more output. This is set by the command line options.
-VERBOSE = False
-
-# In lowercase, using forward slashes as directory separators, ending in a
-# forward slash. Set by the command line options.
-BASE_DIRECTORY = ""
-# The directories which contain the sources managed by git.
-GIT_SOURCE_DIRECTORY = set()
+class DepsChecker(object):
+ """Parses include_rules from DEPS files and can verify files in the
+ source tree against them.
+ """
+ def __init__(self, base_directory=None, verbose=False, being_tested=False):
+ """Creates a new DepsChecker.
-# Specifies a single rule for an include, which can be either allow or disallow.
-class Rule(object):
- def __init__(self, allow, directory, source):
- self.allow = allow
- self._dir = directory
- self._source = source
+ Args:
+ base_directory: OS-compatible path to root of checkout, e.g. C:\chr\src.
+ verbose: Set to true for debug output.
+ being_tested: Set to true to ignore the DEPS file at tools/checkdeps/DEPS.
+ """
+ self.base_directory = base_directory
+ if not base_directory:
+ self.base_directory = os.path.abspath(
+ os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', '..'))
- def __str__(self):
- if (self.allow):
- return '"+%s" from %s.' % (self._dir, self._source)
- return '"-%s" from %s.' % (self._dir, self._source)
+ self.verbose = verbose
- def ParentOrMatch(self, other):
- """Returns true if the input string is an exact match or is a parent
- of the current rule. For example, the input "foo" would match "foo/bar"."""
- return self._dir == other or self._dir.startswith(other + "/")
+ self.git_source_directories = set()
+ self._AddGitSourceDirectories()
- def ChildOrMatch(self, other):
- """Returns true if the input string would be covered by this rule. For
- example, the input "foo/bar" would match the rule "foo"."""
- return self._dir == other or other.startswith(self._dir + "/")
+ self._under_test = being_tested
+ def _ApplyRules(self, existing_rules, includes, cur_dir):
+ """Applies the given include rules, returning the new rules.
-def ParseRuleString(rule_string, source):
- """Returns a tuple of a boolean indicating whether the directory is an allow
- rule, and a string holding the directory name.
- """
- if len(rule_string) < 1:
- raise Exception('The rule string "%s" is too short\nin %s' %
- (rule_string, source))
+ Args:
+ existing_rules: A set of existing rules that will be combined.
+ include: The list of rules from the "include_rules" section of DEPS.
+ cur_dir: The current directory. We will create an implicit rule that
+ allows inclusion from this directory.
- if rule_string[0] == "+":
- return (True, rule_string[1:])
- if rule_string[0] == "-":
- return (False, rule_string[1:])
- raise Exception('The rule string "%s" does not begin with a "+" or a "-"' %
- rule_string)
+ Returns: A new set of rules combining the existing_rules with the other
+ arguments.
+ """
+ rules = copy.copy(existing_rules)
+
+ # First apply the implicit "allow" rule for the current directory.
+ if os.path.normpath(cur_dir).lower().startswith(
+ os.path.normpath(self.base_directory).lower()):
+ relative_dir = cur_dir[len(self.base_directory) + 1:]
+ source = relative_dir
+ if len(source) == 0:
+ source = "top level" # Make the help string a little more meaningful.
+ rules.AddRule("+" + relative_dir, "Default rule for " + source)
+ else:
+ raise Exception("Internal error: base directory is not at the beginning" +
+ " for\n %s and base dir\n %s" %
+ (cur_dir, self.base_directory))
+ # Last, apply the additional explicit rules.
+ for (_, rule_str) in enumerate(includes):
M-A Ruel 2012/07/26 18:30:07 I know you just moved the code but while at it, re
+ if not len(relative_dir):
M-A Ruel 2012/07/26 18:30:07 if not relative_dir:
+ rule_description = "the top level include_rules"
+ else:
+ rule_description = relative_dir + "'s include_rules"
+ rules.AddRule(rule_str, rule_description)
-class Rules:
- def __init__(self):
- """Initializes the current rules with an empty rule list."""
- self._rules = []
+ return rules
- def __str__(self):
- ret = "Rules = [\n"
- ret += "\n".join([" %s" % x for x in self._rules])
- ret += "]\n"
- return ret
+ def _ApplyDirectoryRules(self, existing_rules, dir_name):
+ """Combines rules from the existing rules and the new directory.
- def AddRule(self, rule_string, source):
- """Adds a rule for the given rule string.
+ Any directory can contain a DEPS file. Toplevel DEPS files can contain
+ module dependencies which are used by gclient. We use these, along with
+ additional include rules and implicit rules for the given directory, to
+ come up with a combined set of rules to apply for the directory.
Args:
- rule_string: The include_rule string read from the DEPS file to apply.
- source: A string representing the location of that string (filename, etc.)
- so that we can give meaningful errors.
+ existing_rules: The rules for the parent directory. We'll add-on to these.
+ dir_name: The directory name that the deps file may live in (if
+ it exists). This will also be used to generate the
+ implicit rules.
+
+ Returns: A tuple containing: (1) the combined set of rules to apply to the
+ sub-tree, and (2) a list of all subdirectories that should NOT be
+ checked, as specified in the DEPS file (if any).
"""
- (add_rule, rule_dir) = ParseRuleString(rule_string, source)
- # Remove any existing rules or sub-rules that apply. For example, if we're
- # passed "foo", we should remove "foo", "foo/bar", but not "foobar".
- self._rules = [x for x in self._rules if not x.ParentOrMatch(rule_dir)]
- self._rules.insert(0, Rule(add_rule, rule_dir, source))
-
- def DirAllowed(self, allowed_dir):
- """Returns a tuple (success, message), where success indicates if the given
- directory is allowed given the current set of rules, and the message tells
- why if the comparison failed."""
- for rule in self._rules:
- if rule.ChildOrMatch(allowed_dir):
- # This rule applies.
- if rule.allow:
- return (True, "")
- return (False, rule.__str__())
- # No rules apply, fail.
- return (False, "no rule applying")
-
-
-def ApplyRules(existing_rules, includes, cur_dir):
- """Applies the given include rules, returning the new rules.
-
- Args:
- existing_rules: A set of existing rules that will be combined.
- include: The list of rules from the "include_rules" section of DEPS.
- cur_dir: The current directory. We will create an implicit rule that
- allows inclusion from this directory.
-
- Returns: A new set of rules combining the existing_rules with the other
- arguments.
- """
- rules = copy.copy(existing_rules)
-
- # First apply the implicit "allow" rule for the current directory.
- if cur_dir.lower().startswith(BASE_DIRECTORY):
- relative_dir = cur_dir[len(BASE_DIRECTORY) + 1:]
- # Normalize path separators to slashes.
- relative_dir = relative_dir.replace("\\", "/")
- source = relative_dir
- if len(source) == 0:
- source = "top level" # Make the help string a little more meaningful.
- rules.AddRule("+" + relative_dir, "Default rule for " + source)
- else:
- raise Exception("Internal error: base directory is not at the beginning" +
- " for\n %s and base dir\n %s" %
- (cur_dir, BASE_DIRECTORY))
-
- # Last, apply the additional explicit rules.
- for (_, rule_str) in enumerate(includes):
- if not len(relative_dir):
- rule_description = "the top level include_rules"
- else:
- rule_description = relative_dir + "'s include_rules"
- rules.AddRule(rule_str, rule_description)
-
- return rules
-
-
-def ApplyDirectoryRules(existing_rules, dir_name):
- """Combines rules from the existing rules and the new directory.
+ # Check for a .svn directory in this directory or check this directory is
+ # contained in git source direcotries. This will tell us if it's a source
+ # directory and should be checked.
+ if not (os.path.exists(os.path.join(dir_name, ".svn")) or
+ (dir_name.lower() in self.git_source_directories)):
+ return (None, [])
+
+ # Check the DEPS file in this directory.
+ if self.verbose:
+ print "Applying rules from", dir_name
+ def FromImpl(_unused, _unused2):
+ pass # NOP function so "From" doesn't fail.
+
+ def FileImpl(_unused):
+ pass # NOP function so "File" doesn't fail.
+
+ class _VarImpl:
+ def __init__(self, local_scope):
+ self._local_scope = local_scope
+
+ def Lookup(self, var_name):
+ """Implements the Var syntax."""
+ if var_name in self._local_scope.get("vars", {}):
+ return self._local_scope["vars"][var_name]
+ raise Exception("Var is not defined: %s" % var_name)
+
+ local_scope = {}
+ global_scope = {
+ "File": FileImpl,
+ "From": FromImpl,
+ "Var": _VarImpl(local_scope).Lookup,
+ }
+ deps_file = os.path.join(dir_name, "DEPS")
+
+ # The second conditional here is to disregard the
+ # tools/checkdeps/DEPS file while running tests. This DEPS file
+ # has a skip_child_includes for 'testdata' which is necessary for
+ # running production tests, since there are intentional DEPS
+ # violations under the testdata directory. On the other hand when
+ # running tests, we absolutely need to verify the contents of that
+ # directory to trigger those intended violations and see that they
+ # are handled correctly.
+ if os.path.isfile(deps_file) and (
+ not self._under_test or not os.path.split(dir_name)[1] == 'checkdeps'):
+ execfile(deps_file, global_scope, local_scope)
+ elif self.verbose:
+ print " No deps file found in", dir_name
+
+ # Even if a DEPS file does not exist we still invoke ApplyRules
+ # to apply the implicit "allow" rule for the current directory
+ include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, [])
+ skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, [])
+
+ return (self._ApplyRules(existing_rules, include_rules, dir_name),
+ skip_subdirs)
+
+ def CheckDirectory(self, start_dir):
+ """Checks all relevant source files in the specified directory and
+ its subdirectories for compliance with DEPS rules throughout the
+ tree (starting at |self.base_directory|). |start_dir| must be a
+ subdirectory of |self.base_directory|.
+
+ Returns an empty array on success. On failure, the array contains
+ strings that can be printed as human-readable error messages.
+ """
+ # TODO(joi): Make this work for start_dir != base_dir (I have a
+ # subsequent change in flight to do this).
+ base_rules = Rules()
+ java = java_checker.JavaChecker(self.base_directory, self.verbose)
+ cpp = cpp_checker.CppChecker(self.verbose)
+ checkers = dict(
+ (extension, checker)
+ for checker in [java, cpp] for extension in checker.EXTENSIONS)
+ return self._CheckDirectoryImpl(base_rules, checkers, start_dir)
+
+ def _CheckDirectoryImpl(self, parent_rules, checkers, dir_name):
+ (rules, skip_subdirs) = self._ApplyDirectoryRules(parent_rules, dir_name)
+ if rules == None:
+ return []
+
+ # Collect a list of all files and directories to check.
+ files_to_check = []
+ dirs_to_check = []
+ results = []
+ contents = os.listdir(dir_name)
+ for cur in contents:
+ if cur in skip_subdirs:
+ continue # Don't check children that DEPS has asked us to skip.
+ full_name = os.path.join(dir_name, cur)
+ if os.path.isdir(full_name):
+ dirs_to_check.append(full_name)
+ elif os.path.splitext(full_name)[1] in checkers:
+ files_to_check.append(full_name)
+
+
M-A Ruel 2012/07/26 18:30:07 one line is sufficient
+ # First check all files in this directory.
+ for cur in files_to_check:
+ checker = checkers[os.path.splitext(cur)[1]]
+ file_status = checker.CheckFile(rules, cur)
+ if file_status:
+ results.append("ERROR in " + cur + "\n" + file_status)
+
+ # Next recurse into the subdirectories.
+ for cur in dirs_to_check:
+ results.extend(self._CheckDirectoryImpl(rules, checkers, cur))
+ return results
+
+ def CheckAddedCppIncludes(self, added_includes):
+ """This is used from PRESUBMIT.py to check new #include statements added in
+ the change being presubmit checked.
- Any directory can contain a DEPS file. Toplevel DEPS files can contain
- module dependencies which are used by gclient. We use these, along with
- additional include rules and implicit rules for the given directory, to
- come up with a combined set of rules to apply for the directory.
+ Args:
+ added_includes: ((file_path, (include_line, include_line, ...), ...)
- Args:
- existing_rules: The rules for the parent directory. We'll add-on to these.
- dir_name: The directory name that the deps file may live in (if it exists).
- This will also be used to generate the implicit rules.
+ Return:
+ A list of tuples, (bad_file_path, rule_type, rule_description)
+ where rule_type is one of Rule.DISALLOW or Rule.TEMP_ALLOW and
+ rule_description is human-readable. Empty if no problems.
+ """
+ # Map of directory paths to rules to use for those directories, or
+ # None for directories that should be skipped.
+ directory_rules = {}
+
+ def ApplyDirectoryRulesAndSkipSubdirs(parent_rules, dir_path):
+ rules_tuple = self._ApplyDirectoryRules(parent_rules, dir_path)
+ directory_rules[dir_path] = rules_tuple[0]
+ for subdir in rules_tuple[1]:
+ # We skip this one case for running tests.
+ directory_rules[os.path.join(dir_path, subdir)] = None
+
+ ApplyDirectoryRulesAndSkipSubdirs(Rules(), self.base_directory)
+
+ def GetDirectoryRules(dir_path):
+ """Returns a Rules object to use for the given directory, or None
+ if the given directory should be skipped.
+ """
+ if not dir_path.startswith(self.base_directory):
+ dir_path = os.path.join(self.base_directory, dir_path)
+
+ parent_dir = os.path.dirname(dir_path)
+ parent_rules = None
+ if not dir_path in directory_rules:
+ parent_rules = GetDirectoryRules(parent_dir)
+
+ # We need to check for an entry for our dir_path again, in case we
+ # are at a path e.g. A/B/C where A/B/DEPS specifies the C
+ # subdirectory to be skipped; in this case, the invocation to
+ # GetDirectoryRules(parent_dir) has already filled in an entry for
+ # A/B/C.
+ if not dir_path in directory_rules:
+ if not parent_rules:
+ # If the parent directory should be skipped, then the current
+ # directory should also be skipped.
+ directory_rules[dir_path] = None
+ else:
+ ApplyDirectoryRulesAndSkipSubdirs(parent_rules, dir_path)
+ return directory_rules[dir_path]
+
+ cpp = cpp_checker.CppChecker(self.verbose)
+
+ problems = []
+ for file_path, include_lines in added_includes:
+ # TODO(joi): Make this cover Java as well.
+ if not os.path.splitext(file_path)[1] in cpp.EXTENSIONS:
+ pass
+ rules_for_file = GetDirectoryRules(os.path.dirname(file_path))
+ if rules_for_file:
+ for line in include_lines:
+ is_include, line_status, rule_type = cpp.CheckLine(
+ rules_for_file, line, True)
+ if rule_type != Rule.ALLOW:
+ problems.append((file_path, rule_type, line_status))
+ return problems
+
+ def _AddGitSourceDirectories(self):
+ """Adds any directories containing sources managed by git to
+ self.git_source_directories.
+ """
+ if not os.path.exists(os.path.join(self.base_directory, ".git")):
+ return
- Returns: A tuple containing: (1) the combined set of rules to apply to the
- sub-tree, and (2) a list of all subdirectories that should NOT be
- checked, as specified in the DEPS file (if any).
- """
- # Check for a .svn directory in this directory or check this directory is
- # contained in git source direcotries. This will tell us if it's a source
- # directory and should be checked.
- if not (os.path.exists(os.path.join(dir_name, ".svn")) or
- (dir_name.lower() in GIT_SOURCE_DIRECTORY)):
- return (None, [])
-
- # Check the DEPS file in this directory.
- if VERBOSE:
- print "Applying rules from", dir_name
- def FromImpl(_unused, _unused2):
- pass # NOP function so "From" doesn't fail.
-
- def FileImpl(_unused):
- pass # NOP function so "File" doesn't fail.
-
- class _VarImpl:
- def __init__(self, local_scope):
- self._local_scope = local_scope
-
- def Lookup(self, var_name):
- """Implements the Var syntax."""
- if var_name in self._local_scope.get("vars", {}):
- return self._local_scope["vars"][var_name]
- raise Exception("Var is not defined: %s" % var_name)
-
- local_scope = {}
- global_scope = {
- "File": FileImpl,
- "From": FromImpl,
- "Var": _VarImpl(local_scope).Lookup,
- }
- deps_file = os.path.join(dir_name, "DEPS")
-
- if os.path.isfile(deps_file):
- execfile(deps_file, global_scope, local_scope)
- elif VERBOSE:
- print " No deps file found in", dir_name
-
- # Even if a DEPS file does not exist we still invoke ApplyRules
- # to apply the implicit "allow" rule for the current directory
- include_rules = local_scope.get(INCLUDE_RULES_VAR_NAME, [])
- skip_subdirs = local_scope.get(SKIP_SUBDIRS_VAR_NAME, [])
-
- return (ApplyRules(existing_rules, include_rules, dir_name), skip_subdirs)
-
-
-def CheckDirectory(parent_rules, checkers, dir_name):
- (rules, skip_subdirs) = ApplyDirectoryRules(parent_rules, dir_name)
- if rules == None:
- return True
-
- # Collect a list of all files and directories to check.
- files_to_check = []
- dirs_to_check = []
- success = True
- contents = os.listdir(dir_name)
- for cur in contents:
- if cur in skip_subdirs:
- continue # Don't check children that DEPS has asked us to skip.
- full_name = os.path.join(dir_name, cur)
- if os.path.isdir(full_name):
- dirs_to_check.append(full_name)
- elif os.path.splitext(full_name)[1] in checkers:
- files_to_check.append(full_name)
-
- # First check all files in this directory.
- for cur in files_to_check:
- checker = checkers[os.path.splitext(cur)[1]]
- file_status = checker.CheckFile(rules, cur)
- if file_status:
- print "ERROR in " + cur + "\n" + file_status
- success = False
-
- # Next recurse into the subdirectories.
- for cur in dirs_to_check:
- if not CheckDirectory(rules, checkers, cur):
- success = False
-
- return success
-
-
-def GetGitSourceDirectory(root):
- """Returns a set of the directories to be checked.
-
- Args:
- root: The repository root where .git directory exists.
-
- Returns:
- A set of directories which contain sources managed by git.
- """
- git_source_directory = set()
- popen_out = os.popen("cd %s && git ls-files --full-name ." %
- pipes.quote(root))
- for line in popen_out.readlines():
- dir_name = os.path.join(root, os.path.dirname(line))
- # Add the directory as well as all the parent directories.
- while dir_name != root:
- git_source_directory.add(dir_name)
- dir_name = os.path.dirname(dir_name)
- git_source_directory.add(root)
- return git_source_directory
+ popen_out = os.popen("cd %s && git ls-files --full-name ." %
+ subprocess.list2cmdline([self.base_directory]))
+ for line in popen_out.readlines():
+ dir_name = os.path.join(self.base_directory, os.path.dirname(line))
+ # Add the directory as well as all the parent directories.
+ while dir_name != self.base_directory:
+ self.git_source_directories.add(dir_name.lower())
+ dir_name = os.path.dirname(dir_name)
+ self.git_source_directories.add(self.base_directory.lower())
def PrintUsage():
@@ -334,73 +371,42 @@ Examples:
python checkdeps.py --root c:\\source chrome"""
-def checkdeps(options, args):
- global VERBOSE
- if options.verbose:
- VERBOSE = True
+def main():
+ option_parser = optparse.OptionParser()
+ option_parser.add_option("", "--root", default="", dest="base_directory",
+ help='Specifies the repository root. This defaults '
+ 'to "../../.." relative to the script file, which '
+ 'will normally be the repository root.')
+ option_parser.add_option("-v", "--verbose", action="store_true",
+ default=False, help="Print debug logging")
+ options, args = option_parser.parse_args()
- # Optional base directory of the repository.
- global BASE_DIRECTORY
- if not options.base_directory:
- BASE_DIRECTORY = os.path.abspath(
- os.path.join(os.path.abspath(os.path.dirname(__file__)), "../.."))
- else:
- BASE_DIRECTORY = os.path.abspath(options.base_directory)
+ deps_checker = DepsChecker(options.base_directory, options.verbose)
# Figure out which directory we have to check.
- if len(args) == 0:
- # No directory to check specified, use the repository root.
- start_dir = BASE_DIRECTORY
- elif len(args) == 1:
+ start_dir = deps_checker.base_directory
+ if len(args) == 1:
# Directory specified. Start here. It's supposed to be relative to the
# base directory.
- start_dir = os.path.abspath(os.path.join(BASE_DIRECTORY, args[0]))
- else:
+ start_dir = os.path.abspath(
+ os.path.join(deps_checker.base_directory, args[0]))
+ elif len(args) >= 2:
# More than one argument, we don't handle this.
PrintUsage()
return 1
- print "Using base directory:", BASE_DIRECTORY
+ print "Using base directory:", deps_checker.base_directory
print "Checking:", start_dir
- base_rules = Rules()
-
- # The base directory should be lower case from here on since it will be used
- # for substring matching on the includes, and we compile on case-insensitive
- # systems. Plus, we always use slashes here since the include parsing code
- # will also normalize to slashes.
- BASE_DIRECTORY = BASE_DIRECTORY.lower()
- BASE_DIRECTORY = BASE_DIRECTORY.replace("\\", "/")
- start_dir = start_dir.replace("\\", "/")
-
- if os.path.exists(os.path.join(BASE_DIRECTORY, ".git")):
- global GIT_SOURCE_DIRECTORY
- GIT_SOURCE_DIRECTORY = GetGitSourceDirectory(BASE_DIRECTORY)
-
- java = java_checker.JavaChecker(BASE_DIRECTORY, VERBOSE)
- cpp = cpp_checker.CppChecker(VERBOSE)
- checkers = dict(
- (extension, checker)
- for checker in [java, cpp] for extension in checker.EXTENSIONS)
- success = CheckDirectory(base_rules, checkers, start_dir)
- if not success:
+ results = deps_checker.CheckDirectory(start_dir)
+ if results:
+ for result in results:
+ print result
print "\nFAILED\n"
return 1
print "\nSUCCESS\n"
return 0
-def main():
- option_parser = optparse.OptionParser()
- option_parser.add_option("", "--root", default="", dest="base_directory",
- help='Specifies the repository root. This defaults '
- 'to "../../.." relative to the script file, which '
- 'will normally be the repository root.')
- option_parser.add_option("-v", "--verbose", action="store_true",
- default=False, help="Print debug logging")
- options, args = option_parser.parse_args()
- return checkdeps(options, args)
-
-
if '__main__' == __name__:
sys.exit(main())

Powered by Google App Engine
This is Rietveld 408576698