src/mercurialserver/ruleset.py
branchdebian
changeset 248 107d28ce67f5
parent 242 03d8f07230b3
child 297 9875791ab421
--- a/src/mercurialserver/ruleset.py	Fri Dec 18 13:25:45 2009 +0000
+++ b/src/mercurialserver/ruleset.py	Sat Dec 19 19:21:41 2009 +0000
@@ -1,29 +1,31 @@
-# Copyright 2008-2009 LShift Ltd
-# Author(s):
-# Paul Crowley <paul@lshift.net>
-#
-# This software may be used and distributed according to the terms
-# of the GNU General Public License, incorporated herein by reference.
+"""
+Glob-based, order-based rules matcher that can answer "maybe"
+where the inputs make clear that something is unknown.
+"""
 
 import sys
 import re
 import os
 import os.path
 
-allowedchars = "A-Za-z0-9_-"
-
 def globmatcher(pattern):
     p = "[^/]*".join(re.escape(c) for c in pattern.split("*"))
     # ** means "match recursively" ie "ignore directories"
-    rex = re.compile(p.replace("[^/]*[^/]*", ".*") + "$")
-    # None matches everything
-    return lambda x: x is None or rex.match(x) is not None
+    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
 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 or not m(kw[k]):
+            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 c
@@ -46,32 +48,39 @@
     def get(self, k):
         return self.preset.get(k, None)
         
-    def matchrule(self, kw):
+    def matchrules(self, kw):
         d = self.preset.copy()
         d.update(kw)
+        res = set()
         for a, c in self.rules:
-            if c(d):
-                return a
-        return None
+            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):
-        a = self.matchrule(kw)
-        return a in self.levels and self.levels.index(a) <= self.levels.index(level)
+        for a in self.matchrules(kw):
+            if a in self.levels:
+                if self.levels.index(a) <= self.levels.index(level):
+                    return True
+        return False
     
     def readfile(self, fn):
+        f = open(fn)
         try:
-            f = open(fn)
-            try:
-                for l in f:
-                    l = l.strip()
-                    if len(l) == 0 or l.startswith("#"):
-                        continue
-                    l = l.split()
-                    self.add(l[0], rule([c.split("=", 1) for c in l[1:]]))
-            finally:
-                f.close()
-        except Exception, e:
-            print >> sys.stderr, "Failure reading rules file:", e
+            for l in f:
+                l = l.strip()
+                if len(l) == 0 or l.startswith("#"):
+                    continue
+                l = l.split()
+                self.add(l[0], rule([c.split("=", 1) for c in l[1:]]))
+        finally:
+            f.close()
 
 rules = Ruleset()