Mercurial > hg-stable
comparison mercurial/templater.py @ 1905:0c760737b996
improve template errors when something is wrong.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Mon, 27 Feb 2006 12:41:20 -0800 |
parents | a7e416bf3c1d |
children | 9dec2479622d |
comparison
equal
deleted
inserted
replaced
1904:a7e416bf3c1d | 1905:0c760737b996 |
---|---|
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 |
96 elif fl: | 110 elif fl: |
97 for f in fl.split("|")[1:]: | 111 for f in fl.split("|")[1:]: |
98 v = filters[f](v) | 112 v = filters[f](v) |
99 | 113 |
100 yield v | 114 yield v |
101 tmpl = tmpl[m.end(0):] | 115 tmpl = tmpl[end:] |
102 else: | 116 else: |
103 yield tmpl | 117 yield tmpl |
104 break | 118 break |
105 | 119 |
106 agescales = [("second", 1), | 120 agescales = [("second", 1), |
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]), |