Refactor ruleset.py so I can be more confident it's correct
authorPaul Crowley <paul@lshift.net>
Mon, 18 Apr 2011 11:44:36 +0100
changeset 300 31c2c6b383fd
parent 299 f41666a08b87
child 301 f88549f44c8e
Refactor ruleset.py so I can be more confident it's correct
src/mercurialserver/ruleset.py
--- a/src/mercurialserver/ruleset.py	Mon Apr 18 11:13:23 2011 +0100
+++ b/src/mercurialserver/ruleset.py	Mon Apr 18 11:44:36 2011 +0100
@@ -13,22 +13,24 @@
     # ** means "match recursively" ie "ignore directories"
     return re.compile(p.replace("[^/]*[^/]*", ".*") + "$")
 
-# Returns True for a definite match
-# False for a definite non-match
-# None where we can't be sure because a key is None
+# Returns 1 for a definite match
+# -1 for a definite non-match
+# 0 where we can't be sure because a key is None
+def rmatch(k, m, kw):
+    if k not in kw:
+        return -1
+    kkw = kw[k]
+    if kkw is None:
+        return 0
+    elif m.match(kkw) is None:
+        return -1
+    else:
+        return 1
+
 def rule(pairs):
     matchers = [(k, globmatcher(v)) for k, v in pairs]
     def c(kw):
-        best = True
-        for k, m in matchers:
-            if k not in kw:
-                return False
-            kkw = kw[k]
-            if kkw is None:
-                best = None
-            elif m.match(kkw) is None:
-                return False
-        return best
+        return min(rmatch(k, m, kw) for k, m in matchers)
     return c
 
 class Ruleset(object):
@@ -41,33 +43,30 @@
         self.preset = {}
 
     def add(self, action, conditions):
-        self.rules.append((action, conditions))
+        # Unrecognized actions are off the high end
+        if action in self.levels:
+            self.rules.append((self.levels.index(action), conditions))
+        else:
+            self.rules.append((len(self.levels), conditions))
 
     def set(self, **kw):
         self.preset.update(kw)
         
     def get(self, k):
         return self.preset.get(k, None)
-        
-    def matchrules(self, kw):
+
+    def allow(self, level, **kw):
+        levelindex = self.levels.index(level)
         d = self.preset.copy()
         d.update(kw)
-        res = set()
         for a, c in self.rules:
             m = c(d)
-            if m is None:
-                # "Maybe match" - add it and carry on
-                res.add(a)
-            elif m:
-                # Definite match - add it and stop
-                res.add(a)
-                break
-        return res
-
-    def allow(self, level, **kw):
-        for a in self.matchrules(kw):
-            if a in self.levels:
-                if self.levels.index(a) <= self.levels.index(level):
+            if m == 1:
+                # Definite match - what it says goes
+                return a <= levelindex
+            elif m == 0:
+                # "Maybe match" - allow if it says yes, ignore if no
+                if a <= levelindex:
                     return True
         return False