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]),