30 if escape: raise SyntaxError(_('unterminated escape')) |
30 if escape: raise SyntaxError(_('unterminated escape')) |
31 return fp.getvalue() |
31 return fp.getvalue() |
32 |
32 |
33 class templater(object): |
33 class templater(object): |
34 def __init__(self, mapfile, filters={}, defaults={}): |
34 def __init__(self, mapfile, filters={}, defaults={}): |
|
35 self.mapfile = mapfile or 'template' |
35 self.cache = {} |
36 self.cache = {} |
36 self.map = {} |
37 self.map = {} |
37 self.base = os.path.dirname(mapfile) |
38 self.base = (mapfile and os.path.dirname(mapfile)) or '' |
38 self.filters = filters |
39 self.filters = filters |
39 self.defaults = defaults |
40 self.defaults = defaults |
40 |
41 |
|
42 if not mapfile: |
|
43 return |
41 i = 0 |
44 i = 0 |
42 for l in file(mapfile): |
45 for l in file(mapfile): |
|
46 l = l.rstrip('\r\n') |
43 i += 1 |
47 i += 1 |
44 m = re.match(r'(\S+)\s*=\s*(["\'].*["\'])$', l) |
48 if l.startswith('#') or not l.strip(): continue |
|
49 m = re.match(r'([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$', l) |
45 if m: |
50 if m: |
46 try: |
51 key, val = m.groups() |
47 s = m.group(2) |
52 if val[0] in "'\"": |
48 self.cache[m.group(1)] = parsestring(s) |
53 try: |
49 except SyntaxError, inst: |
54 self.cache[key] = parsestring(val) |
50 raise SyntaxError('%s:%s: %s' % (mapfile, i, inst.args[0])) |
55 except SyntaxError, inst: |
|
56 raise SyntaxError('%s:%s: %s' % |
|
57 (mapfile, i, inst.args[0])) |
|
58 else: |
|
59 self.map[key] = os.path.join(self.base, val) |
51 else: |
60 else: |
52 m = re.match(r'(\S+)\s*=\s*(\S+)', l) |
61 raise SyntaxError(_("%s:%s: parse error") % (mapfile, i)) |
53 if m: |
|
54 self.map[m.group(1)] = os.path.join(self.base, m.group(2)) |
|
55 else: |
|
56 raise LookupError(_("unknown map entry '%s'") % l) |
|
57 |
62 |
58 def __contains__(self, key): |
63 def __contains__(self, key): |
59 return key in self.cache |
64 return key in self.cache |
60 |
65 |
61 def __call__(self, t, **map): |
66 def __call__(self, t, **map): |
62 m = self.defaults.copy() |
67 m = self.defaults.copy() |
63 m.update(map) |
68 m.update(map) |
64 try: |
69 try: |
65 tmpl = self.cache[t] |
70 tmpl = self.cache[t] |
66 except KeyError: |
71 except KeyError: |
67 tmpl = self.cache[t] = file(self.map[t]).read() |
72 try: |
|
73 tmpl = self.cache[t] = file(self.map[t]).read() |
|
74 except IOError, inst: |
|
75 raise IOError(inst.args[0], _('template file %s: %s') % |
|
76 (self.map[t], inst.args[1])) |
68 return self.template(tmpl, self.filters, **m) |
77 return self.template(tmpl, self.filters, **m) |
69 |
78 |
70 template_re = re.compile(r"[#{]([a-zA-Z_][a-zA-Z0-9_]*)" |
79 template_re = re.compile(r"[#{]([a-zA-Z_][a-zA-Z0-9_]*)" |
71 r"((%[a-zA-Z_][a-zA-Z0-9_]*)*)" |
80 r"((%[a-zA-Z_][a-zA-Z0-9_]*)*)" |
72 r"((\|[a-zA-Z_][a-zA-Z0-9_]*)*)[#}]") |
81 r"((\|[a-zA-Z_][a-zA-Z0-9_]*)*)[#}]") |
74 def template(self, tmpl, filters={}, **map): |
83 def template(self, tmpl, filters={}, **map): |
75 lm = map.copy() |
84 lm = map.copy() |
76 while tmpl: |
85 while tmpl: |
77 m = self.template_re.search(tmpl) |
86 m = self.template_re.search(tmpl) |
78 if m: |
87 if m: |
79 start = m.start(0) |
88 start, end = m.span(0) |
|
89 s, e = tmpl[start], tmpl[end - 1] |
|
90 key = m.group(1) |
|
91 if ((s == '#' and e != '#') or (s == '{' and e != '}')): |
|
92 raise SyntaxError(_("'%s'/'%s' mismatch expanding '%s'") % |
|
93 (s, e, key)) |
80 if start: |
94 if start: |
81 yield tmpl[:start] |
95 yield tmpl[:start] |
82 v = map.get(m.group(1), "") |
96 v = map.get(key, "") |
83 v = callable(v) and v(**map) or v |
97 v = callable(v) and v(**map) or v |
84 |
98 |
85 format = m.group(2) |
99 format = m.group(2) |
86 fl = m.group(4) |
100 fl = m.group(4) |
87 |
101 |
151 |
165 |
152 common_filters = { |
166 common_filters = { |
153 "addbreaks": nl2br, |
167 "addbreaks": nl2br, |
154 "age": age, |
168 "age": age, |
155 "date": lambda x: util.datestr(x), |
169 "date": lambda x: util.datestr(x), |
|
170 "domain": domain, |
156 "escape": lambda x: cgi.escape(x, True), |
171 "escape": lambda x: cgi.escape(x, True), |
157 "firstline": (lambda x: x.splitlines(1)[0]), |
172 "firstline": (lambda x: x.splitlines(1)[0]), |
158 "domain": domain, |
|
159 "obfuscate": obfuscate, |
173 "obfuscate": obfuscate, |
160 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"), |
174 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"), |
161 "person": person, |
175 "person": person, |
162 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"), |
176 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"), |
163 "short": (lambda x: x[:12]), |
177 "short": (lambda x: x[:12]), |