| Index: tools/checkdeps/rules.py
|
| diff --git a/tools/checkdeps/rules.py b/tools/checkdeps/rules.py
|
| index 4ec5cf4fc7e8dd1207485ac96d0cea7acd6f2592..09d718c7234b6cb0560c928990510e48ae836d37 100644
|
| --- a/tools/checkdeps/rules.py
|
| +++ b/tools/checkdeps/rules.py
|
| @@ -5,6 +5,10 @@
|
| """Base classes to represent dependency rules, used by checkdeps.py"""
|
|
|
|
|
| +import os
|
| +import re
|
| +
|
| +
|
| class Rule(object):
|
| """Specifies a single rule for an include, which can be one of
|
| ALLOW, DISALLOW and TEMP_ALLOW.
|
| @@ -36,13 +40,13 @@ class Rule(object):
|
| return self._dir == other or other.startswith(self._dir + '/')
|
|
|
|
|
| -class SpecificRule(Rule):
|
| - """A rule that has a specific reason not related to directory or
|
| - source, for failing.
|
| +class MessageRule(Rule):
|
| + """A rule that has a simple message as the reason for failing,
|
| + unrelated to directory or source.
|
| """
|
|
|
| def __init__(self, reason):
|
| - super(SpecificRule, self).__init__(Rule.DISALLOW, '', '')
|
| + super(MessageRule, self).__init__(Rule.DISALLOW, '', '')
|
| self._reason = reason
|
|
|
| def __str__(self):
|
| @@ -50,8 +54,8 @@ class SpecificRule(Rule):
|
|
|
|
|
| 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.
|
| + """Returns a tuple of a character indicating what type of rule this
|
| + is, and a string holding the path the rule applies to.
|
| """
|
| if not rule_string:
|
| raise Exception('The rule string "%s" is empty\nin %s' %
|
| @@ -66,30 +70,82 @@ def ParseRuleString(rule_string, source):
|
|
|
|
|
| class Rules(object):
|
| + """Sets of rules for files in a directory.
|
| +
|
| + By default, rules are added to the set of rules applicable to all
|
| + dependee files in the directory. Rules may also be added that apply
|
| + only to dependee files whose filename (last component of their path)
|
| + matches a given regular expression; hence there is one additional
|
| + set of rules per unique regular expression.
|
| + """
|
| +
|
| def __init__(self):
|
| - """Initializes the current rules with an empty rule list."""
|
| - self._rules = []
|
| + """Initializes the current rules with an empty rule list for all
|
| + files.
|
| + """
|
| + # We keep the general rules out of the specific rules dictionary,
|
| + # as we need to always process them last.
|
| + self._general_rules = []
|
|
|
| - def __str__(self):
|
| - return 'Rules = [\n%s]' % '\n'.join(' %s' % x for x in self._rules)
|
| + # Keys are regular expression strings, values are arrays of rules
|
| + # that apply to dependee files whose basename matches the regular
|
| + # expression. These are applied before the general rules, but
|
| + # their internal order is arbitrary.
|
| + self._specific_rules = {}
|
|
|
| - def AddRule(self, rule_string, source):
|
| + def __str__(self):
|
| + result = ['Rules = {\n (apply to all files): [\n%s\n ],' % '\n'.join(
|
| + ' %s' % x for x in self._general_rules)]
|
| + for regexp, rules in self._specific_rules.iteritems():
|
| + result.append(' (limited to files matching %s): [\n%s\n ]' % (
|
| + regexp, '\n'.join(' %s' % x for x in rules)))
|
| + result.append(' }')
|
| + return '\n'.join(result)
|
| +
|
| + def AddRule(self, rule_string, source, dependee_regexp=None):
|
| """Adds a rule for the given rule string.
|
|
|
| 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.
|
| + dependee_regexp: The rule will only be applied to dependee files
|
| + whose filename (last component of their path)
|
| + matches the expression. None to match all
|
| + dependee files.
|
| """
|
| - (add_rule, rule_dir) = ParseRuleString(rule_string, source)
|
| + (rule_type, rule_dir) = ParseRuleString(rule_string, source)
|
| +
|
| + if not dependee_regexp:
|
| + rules_to_update = self._general_rules
|
| + else:
|
| + if dependee_regexp in self._specific_rules:
|
| + rules_to_update = self._specific_rules[dependee_regexp]
|
| + else:
|
| + rules_to_update = []
|
| +
|
| # 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 RuleApplyingTo(self, allowed_dir):
|
| - """Returns the rule that applies to 'allowed_dir'."""
|
| - for rule in self._rules:
|
| - if rule.ChildOrMatch(allowed_dir):
|
| + rules_to_update = [x for x in rules_to_update
|
| + if not x.ParentOrMatch(rule_dir)]
|
| + rules_to_update.insert(0, Rule(rule_type, rule_dir, source))
|
| +
|
| + if not dependee_regexp:
|
| + self._general_rules = rules_to_update
|
| + else:
|
| + self._specific_rules[dependee_regexp] = rules_to_update
|
| +
|
| + def RuleApplyingTo(self, include_path, dependee_path):
|
| + """Returns the rule that applies to |include_path| for a dependee
|
| + file located at |dependee_path|.
|
| + """
|
| + dependee_filename = os.path.basename(dependee_path)
|
| + for regexp, specific_rules in self._specific_rules.iteritems():
|
| + if re.match(regexp, dependee_filename):
|
| + for rule in specific_rules:
|
| + if rule.ChildOrMatch(include_path):
|
| + return rule
|
| + for rule in self._general_rules:
|
| + if rule.ChildOrMatch(include_path):
|
| return rule
|
| - return SpecificRule('no rule applying.')
|
| + return MessageRule('no rule applying.')
|
|
|