8 import sys |
8 import sys |
9 import re |
9 import re |
10 import os |
10 import os |
11 import os.path |
11 import os.path |
12 |
12 |
13 allowedchars = "A-Za-z0-9_-" |
|
14 |
|
15 def globmatcher(pattern): |
13 def globmatcher(pattern): |
16 p = "[^/]*".join(re.escape(c) for c in pattern.split("*")) |
14 p = "[^/]*".join(re.escape(c) for c in pattern.split("*")) |
17 # ** means "match recursively" ie "ignore directories" |
15 # ** means "match recursively" ie "ignore directories" |
18 rex = re.compile(p.replace("[^/]*[^/]*", ".*") + "$") |
16 return re.compile(p.replace("[^/]*[^/]*", ".*") + "$") |
19 # None matches everything |
|
20 return lambda x: x is None or rex.match(x) is not None |
|
21 |
17 |
|
18 # Returns True for a definite match |
|
19 # False for a definite non-match |
|
20 # None where we can't be sure because a key is None |
22 def rule(pairs): |
21 def rule(pairs): |
23 matchers = [(k, globmatcher(v)) for k, v in pairs] |
22 matchers = [(k, globmatcher(v)) for k, v in pairs] |
24 def c(kw): |
23 def c(kw): |
25 for k, m in matchers: |
24 for k, m in matchers: |
26 if k not in kw or not m(kw[k]): |
25 if k not in kw: |
|
26 return False |
|
27 kkw = kw[k] |
|
28 if kkw is None: |
|
29 return None |
|
30 if m.match(kkw) is None: |
27 return False |
31 return False |
28 return True |
32 return True |
29 return c |
33 return c |
30 |
34 |
31 class Ruleset(object): |
35 class Ruleset(object): |
44 self.preset.update(kw) |
48 self.preset.update(kw) |
45 |
49 |
46 def get(self, k): |
50 def get(self, k): |
47 return self.preset.get(k, None) |
51 return self.preset.get(k, None) |
48 |
52 |
49 def matchrule(self, kw): |
53 def matchrules(self, kw): |
50 d = self.preset.copy() |
54 d = self.preset.copy() |
51 d.update(kw) |
55 d.update(kw) |
|
56 res = set() |
52 for a, c in self.rules: |
57 for a, c in self.rules: |
53 if c(d): |
58 m = c(d) |
54 return a |
59 if m is None: |
55 return None |
60 # "Maybe match" - add it and carry on |
|
61 res.add(a) |
|
62 elif m: |
|
63 # Definite match - add it and stop |
|
64 res.add(a) |
|
65 break |
|
66 return res |
56 |
67 |
57 def allow(self, level, **kw): |
68 def allow(self, level, **kw): |
58 a = self.matchrule(kw) |
69 for a in self.matchrules(kw): |
59 return a in self.levels and self.levels.index(a) <= self.levels.index(level) |
70 if a in self.levels: |
|
71 if self.levels.index(a) <= self.levels.index(level): |
|
72 return True |
|
73 return False |
60 |
74 |
61 def readfile(self, fn): |
75 def readfile(self, fn): |
|
76 f = open(fn) |
62 try: |
77 try: |
63 f = open(fn) |
78 for l in f: |
64 try: |
79 l = l.strip() |
65 for l in f: |
80 if len(l) == 0 or l.startswith("#"): |
66 l = l.strip() |
81 continue |
67 if len(l) == 0 or l.startswith("#"): |
82 l = l.split() |
68 continue |
83 self.add(l[0], rule([c.split("=", 1) for c in l[1:]])) |
69 l = l.split() |
84 finally: |
70 self.add(l[0], rule([c.split("=", 1) for c in l[1:]])) |
85 f.close() |
71 finally: |
|
72 f.close() |
|
73 except Exception, e: |
|
74 print >> sys.stderr, "Failure reading rules file:", e |
|
75 |
86 |
76 rules = Ruleset() |
87 rules = Ruleset() |
77 |
88 |