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

Unified Diff: tools/checkdeps/rules.py

Issue 10823271: Add ability to write include rules specific to subsets of files in a directory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge to head. 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/checkdeps/results.py ('k') | tools/checkdeps/testdata/allowed/DEPS » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.')
« no previous file with comments | « tools/checkdeps/results.py ('k') | tools/checkdeps/testdata/allowed/DEPS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698