src/mercurialserver/ruleset.py
branchdebian
changeset 313 f597eb3b5aaf
parent 311 3cbde66305e4
child 371 e9ce904b62a9
--- a/src/mercurialserver/ruleset.py	Sun Dec 19 09:49:18 2010 +0000
+++ b/src/mercurialserver/ruleset.py	Tue Sep 06 11:16:58 2011 +0100
@@ -13,63 +13,56 @@
     # ** 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):
-        for k, m in matchers:
-            if k not in kw:
-                return False
-            kkw = kw[k]
-            if kkw is None:
-                return None
-            if m.match(kkw) is None:
-                return False
-        return True
+        return min(rmatch(k, m, kw) for k, m in matchers)
     return c
 
 class Ruleset(object):
     '''Class representing the rules in a rule file'''
-    
+
     levels = ["init", "write", "read", "deny"]
 
     def __init__(self):
         self.rules = []
         self.preset = {}
 
-    def add(self, action, conditions):
-        self.rules.append((action, 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
-    
+
     def readfile(self, fn):
         f = open(fn)
         try:
@@ -78,9 +71,14 @@
                 if len(l) == 0 or l.startswith("#"):
                     continue
                 l = l.split()
-                self.add(l[0], rule([c.split("=", 1) for c in l[1:]]))
+                # Unrecognized actions are off the high end
+                if l[0] in self.levels:
+                    ix = self.levels.index(l[0])
+                else:
+                    ix = len(self.levels)
+                self.rules.append((ix,
+                    rule([c.split("=", 1) for c in l[1:]])))
         finally:
             f.close()
 
 rules = Ruleset()
-