src/mercurialserver/ruleset.py
changeset 300 31c2c6b383fd
parent 297 9875791ab421
child 301 f88549f44c8e
equal deleted inserted replaced
299:f41666a08b87 300:31c2c6b383fd
    11 def globmatcher(pattern):
    11 def globmatcher(pattern):
    12     p = "[^/]*".join(re.escape(c) for c in pattern.split("*"))
    12     p = "[^/]*".join(re.escape(c) for c in pattern.split("*"))
    13     # ** means "match recursively" ie "ignore directories"
    13     # ** means "match recursively" ie "ignore directories"
    14     return re.compile(p.replace("[^/]*[^/]*", ".*") + "$")
    14     return re.compile(p.replace("[^/]*[^/]*", ".*") + "$")
    15 
    15 
    16 # Returns True for a definite match
    16 # Returns 1 for a definite match
    17 # False for a definite non-match
    17 # -1 for a definite non-match
    18 # None where we can't be sure because a key is None
    18 # 0 where we can't be sure because a key is None
       
    19 def rmatch(k, m, kw):
       
    20     if k not in kw:
       
    21         return -1
       
    22     kkw = kw[k]
       
    23     if kkw is None:
       
    24         return 0
       
    25     elif m.match(kkw) is None:
       
    26         return -1
       
    27     else:
       
    28         return 1
       
    29 
    19 def rule(pairs):
    30 def rule(pairs):
    20     matchers = [(k, globmatcher(v)) for k, v in pairs]
    31     matchers = [(k, globmatcher(v)) for k, v in pairs]
    21     def c(kw):
    32     def c(kw):
    22         best = True
    33         return min(rmatch(k, m, kw) for k, m in matchers)
    23         for k, m in matchers:
       
    24             if k not in kw:
       
    25                 return False
       
    26             kkw = kw[k]
       
    27             if kkw is None:
       
    28                 best = None
       
    29             elif m.match(kkw) is None:
       
    30                 return False
       
    31         return best
       
    32     return c
    34     return c
    33 
    35 
    34 class Ruleset(object):
    36 class Ruleset(object):
    35     '''Class representing the rules in a rule file'''
    37     '''Class representing the rules in a rule file'''
    36     
    38     
    39     def __init__(self):
    41     def __init__(self):
    40         self.rules = []
    42         self.rules = []
    41         self.preset = {}
    43         self.preset = {}
    42 
    44 
    43     def add(self, action, conditions):
    45     def add(self, action, conditions):
    44         self.rules.append((action, conditions))
    46         # Unrecognized actions are off the high end
       
    47         if action in self.levels:
       
    48             self.rules.append((self.levels.index(action), conditions))
       
    49         else:
       
    50             self.rules.append((len(self.levels), conditions))
    45 
    51 
    46     def set(self, **kw):
    52     def set(self, **kw):
    47         self.preset.update(kw)
    53         self.preset.update(kw)
    48         
    54         
    49     def get(self, k):
    55     def get(self, k):
    50         return self.preset.get(k, None)
    56         return self.preset.get(k, None)
    51         
    57 
    52     def matchrules(self, kw):
    58     def allow(self, level, **kw):
       
    59         levelindex = self.levels.index(level)
    53         d = self.preset.copy()
    60         d = self.preset.copy()
    54         d.update(kw)
    61         d.update(kw)
    55         res = set()
       
    56         for a, c in self.rules:
    62         for a, c in self.rules:
    57             m = c(d)
    63             m = c(d)
    58             if m is None:
    64             if m == 1:
    59                 # "Maybe match" - add it and carry on
    65                 # Definite match - what it says goes
    60                 res.add(a)
    66                 return a <= levelindex
    61             elif m:
    67             elif m == 0:
    62                 # Definite match - add it and stop
    68                 # "Maybe match" - allow if it says yes, ignore if no
    63                 res.add(a)
    69                 if a <= levelindex:
    64                 break
       
    65         return res
       
    66 
       
    67     def allow(self, level, **kw):
       
    68         for a in self.matchrules(kw):
       
    69             if a in self.levels:
       
    70                 if self.levels.index(a) <= self.levels.index(level):
       
    71                     return True
    70                     return True
    72         return False
    71         return False
    73     
    72     
    74     def readfile(self, fn):
    73     def readfile(self, fn):
    75         f = open(fn)
    74         f = open(fn)