aboutsummaryrefslogtreecommitdiff
path: root/scripts/maint/checkIncludes.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/maint/checkIncludes.py')
-rwxr-xr-xscripts/maint/checkIncludes.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py
index 46a3f39638..3afd9bbebe 100755
--- a/scripts/maint/checkIncludes.py
+++ b/scripts/maint/checkIncludes.py
@@ -33,6 +33,9 @@ else:
def open_file(fname):
return open(fname, 'r', encoding='utf-8')
+def warn(msg):
+ print(msg, file=sys.stderr)
+
def err(msg):
""" Declare that an error has happened, and remember that there has
been an error. """
@@ -48,14 +51,34 @@ def fname_is_c(fname):
INCLUDE_PATTERN = re.compile(r'\s*#\s*include\s+"([^"]*)"')
RULES_FNAME = ".may_include"
+ALLOWED_PATTERNS = [
+ re.compile(r'^.*\*\.(h|inc)$'),
+ re.compile(r'^.*/.*\.h$'),
+ re.compile(r'^ext/.*\.c$'),
+ re.compile(r'^orconfig.h$'),
+ re.compile(r'^micro-revision.i$'),
+]
+
+def pattern_is_normal(s):
+ for p in ALLOWED_PATTERNS:
+ if p.match(s):
+ return True
+ return False
+
class Rules(object):
""" A 'Rules' object is the parsed version of a .may_include file. """
def __init__(self, dirpath):
self.dirpath = dirpath
+ if dirpath.startswith("src/"):
+ self.incpath = dirpath[4:]
+ else:
+ self.incpath = dirpath
self.patterns = []
self.usedPatterns = set()
def addPattern(self, pattern):
+ if not pattern_is_normal(pattern):
+ warn("Unusual pattern {} in {}".format(pattern, self.dirpath))
self.patterns.append(pattern)
def includeOk(self, path):
@@ -86,6 +109,20 @@ class Rules(object):
if p not in self.usedPatterns:
print("Pattern {} in {} was never used.".format(p, self.dirpath))
+ def getAllowedDirectories(self):
+ allowed = []
+ for p in self.patterns:
+ m = re.match(r'^(.*)/\*\.(h|inc)$', p)
+ if m:
+ allowed.append(m.group(1))
+ continue
+ m = re.match(r'^(.*)/[^/]*$', p)
+ if m:
+ allowed.append(m.group(1))
+ continue
+
+ return allowed
+
def load_include_rules(fname):
""" Read a rules file from 'fname', and return it as a Rules object. """
result = Rules(os.path.split(fname)[0])
@@ -98,6 +135,9 @@ def load_include_rules(fname):
return result
list_unused = False
+log_sorted_levels = False
+
+uses_dirs = { }
for dirpath, dirnames, fnames in os.walk("src"):
if ".may_include" in fnames:
@@ -108,8 +148,34 @@ for dirpath, dirnames, fnames in os.walk("src"):
if list_unused:
rules.noteUnusedRules()
+ uses_dirs[rules.incpath] = rules.getAllowedDirectories()
+
if trouble:
err(
"""To change which includes are allowed in a C file, edit the {}
files in its enclosing directory.""".format(RULES_FNAME))
sys.exit(1)
+
+all_levels = []
+
+n = 0
+while uses_dirs:
+ n += 0
+ cur_level = []
+ for k in list(uses_dirs):
+ uses_dirs[k] = [ d for d in uses_dirs[k]
+ if (d in uses_dirs and d != k)]
+ if uses_dirs[k] == []:
+ cur_level.append(k)
+ for k in cur_level:
+ del uses_dirs[k]
+ n += 1
+ if cur_level and log_sorted_levels:
+ print(n, cur_level)
+ if n > 100:
+ break
+
+if uses_dirs:
+ print("There are circular .may_include dependencies in here somewhere:",
+ uses_dirs)
+ sys.exit(1)