[tor-commits] [tor/master] Update the check-includes script to enforce some naming and no-circularity rules

nickm at torproject.org nickm at torproject.org
Wed Dec 5 13:19:33 UTC 2018


commit c3c8c926bfc8e44e28f3a404e3452f014f6bcbaa
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Nov 7 10:30:46 2018 -0500

    Update the check-includes script to enforce some naming and no-circularity rules
---
 scripts/maint/checkIncludes.py | 64 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py
index 46a3f3963..ecda3fc56 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])
@@ -99,6 +136,8 @@ def load_include_rules(fname):
 
 list_unused = False
 
+uses_dirs = { }
+
 for dirpath, dirnames, fnames in os.walk("src"):
     if ".may_include" in fnames:
         rules = load_include_rules(os.path.join(dirpath, RULES_FNAME))
@@ -108,8 +147,33 @@ 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:
+        print(n, cur_level)
+    if n > 100:
+        break
+
+if uses_dirs:
+    print("Circular dependencies in here somewhere:", uses_dirs)
+    sys.exit(1)





More information about the tor-commits mailing list