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

Side by Side Diff: tools/checkdeps/rules.py

Issue 307333003: Remove now obsolete checkdeps copy (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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 | « tools/checkdeps/results.py ('k') | tools/checkdeps/testdata/DEPS » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Base classes to represent dependency rules, used by checkdeps.py"""
6
7
8 import os
9 import re
10
11
12 class Rule(object):
13 """Specifies a single rule for an include, which can be one of
14 ALLOW, DISALLOW and TEMP_ALLOW.
15 """
16
17 # These are the prefixes used to indicate each type of rule. These
18 # are also used as values for self.allow to indicate which type of
19 # rule this is.
20 ALLOW = '+'
21 DISALLOW = '-'
22 TEMP_ALLOW = '!'
23
24 def __init__(self, allow, directory, dependent_directory, source):
25 self.allow = allow
26 self._dir = directory
27 self._dependent_dir = dependent_directory
28 self._source = source
29
30 def __str__(self):
31 return '"%s%s" from %s.' % (self.allow, self._dir, self._source)
32
33 def AsDependencyTuple(self):
34 """Returns a tuple (allow, dependent dir, dependee dir) for this rule,
35 which is fully self-sufficient to answer the question whether the dependent
36 is allowed to depend on the dependee, without knowing the external
37 context."""
38 return self.allow, self._dependent_dir or '.', self._dir or '.'
39
40 def ParentOrMatch(self, other):
41 """Returns true if the input string is an exact match or is a parent
42 of the current rule. For example, the input "foo" would match "foo/bar"."""
43 return self._dir == other or self._dir.startswith(other + '/')
44
45 def ChildOrMatch(self, other):
46 """Returns true if the input string would be covered by this rule. For
47 example, the input "foo/bar" would match the rule "foo"."""
48 return self._dir == other or other.startswith(self._dir + '/')
49
50
51 class MessageRule(Rule):
52 """A rule that has a simple message as the reason for failing,
53 unrelated to directory or source.
54 """
55
56 def __init__(self, reason):
57 super(MessageRule, self).__init__(Rule.DISALLOW, '', '', '')
58 self._reason = reason
59
60 def __str__(self):
61 return self._reason
62
63
64 def ParseRuleString(rule_string, source):
65 """Returns a tuple of a character indicating what type of rule this
66 is, and a string holding the path the rule applies to.
67 """
68 if not rule_string:
69 raise Exception('The rule string "%s" is empty\nin %s' %
70 (rule_string, source))
71
72 if not rule_string[0] in [Rule.ALLOW, Rule.DISALLOW, Rule.TEMP_ALLOW]:
73 raise Exception(
74 'The rule string "%s" does not begin with a "+", "-" or "!".' %
75 rule_string)
76
77 return rule_string[0], rule_string[1:]
78
79
80 class Rules(object):
81 """Sets of rules for files in a directory.
82
83 By default, rules are added to the set of rules applicable to all
84 dependee files in the directory. Rules may also be added that apply
85 only to dependee files whose filename (last component of their path)
86 matches a given regular expression; hence there is one additional
87 set of rules per unique regular expression.
88 """
89
90 def __init__(self):
91 """Initializes the current rules with an empty rule list for all
92 files.
93 """
94 # We keep the general rules out of the specific rules dictionary,
95 # as we need to always process them last.
96 self._general_rules = []
97
98 # Keys are regular expression strings, values are arrays of rules
99 # that apply to dependee files whose basename matches the regular
100 # expression. These are applied before the general rules, but
101 # their internal order is arbitrary.
102 self._specific_rules = {}
103
104 def __str__(self):
105 result = ['Rules = {\n (apply to all files): [\n%s\n ],' % '\n'.join(
106 ' %s' % x for x in self._general_rules)]
107 for regexp, rules in self._specific_rules.iteritems():
108 result.append(' (limited to files matching %s): [\n%s\n ]' % (
109 regexp, '\n'.join(' %s' % x for x in rules)))
110 result.append(' }')
111 return '\n'.join(result)
112
113 def AsDependencyTuples(self, include_general_rules, include_specific_rules):
114 """Returns a list of tuples (allow, dependent dir, dependee dir) for the
115 specified rules (general/specific). Currently only general rules are
116 supported."""
117 def AddDependencyTuplesImpl(deps, rules, extra_dependent_suffix=""):
118 for rule in rules:
119 (allow, dependent, dependee) = rule.AsDependencyTuple()
120 tup = (allow, dependent + extra_dependent_suffix, dependee)
121 deps.add(tup)
122
123 deps = set()
124 if include_general_rules:
125 AddDependencyTuplesImpl(deps, self._general_rules)
126 if include_specific_rules:
127 for regexp, rules in self._specific_rules.iteritems():
128 AddDependencyTuplesImpl(deps, rules, "/" + regexp)
129 return deps
130
131 def AddRule(self, rule_string, dependent_dir, source, dependee_regexp=None):
132 """Adds a rule for the given rule string.
133
134 Args:
135 rule_string: The include_rule string read from the DEPS file to apply.
136 source: A string representing the location of that string (filename, etc.)
137 so that we can give meaningful errors.
138 dependent_dir: The directory to which this rule applies.
139 dependee_regexp: The rule will only be applied to dependee files
140 whose filename (last component of their path)
141 matches the expression. None to match all
142 dependee files.
143 """
144 rule_type, rule_dir = ParseRuleString(rule_string, source)
145
146 if not dependee_regexp:
147 rules_to_update = self._general_rules
148 else:
149 if dependee_regexp in self._specific_rules:
150 rules_to_update = self._specific_rules[dependee_regexp]
151 else:
152 rules_to_update = []
153
154 # Remove any existing rules or sub-rules that apply. For example, if we're
155 # passed "foo", we should remove "foo", "foo/bar", but not "foobar".
156 rules_to_update = [x for x in rules_to_update
157 if not x.ParentOrMatch(rule_dir)]
158 rules_to_update.insert(0, Rule(rule_type, rule_dir, dependent_dir, source))
159
160 if not dependee_regexp:
161 self._general_rules = rules_to_update
162 else:
163 self._specific_rules[dependee_regexp] = rules_to_update
164
165 def RuleApplyingTo(self, include_path, dependee_path):
166 """Returns the rule that applies to |include_path| for a dependee
167 file located at |dependee_path|.
168 """
169 dependee_filename = os.path.basename(dependee_path)
170 for regexp, specific_rules in self._specific_rules.iteritems():
171 if re.match(regexp, dependee_filename):
172 for rule in specific_rules:
173 if rule.ChildOrMatch(include_path):
174 return rule
175 for rule in self._general_rules:
176 if rule.ChildOrMatch(include_path):
177 return rule
178 return MessageRule('no rule applying.')
OLDNEW
« no previous file with comments | « tools/checkdeps/results.py ('k') | tools/checkdeps/testdata/DEPS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698