Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/hgweb.py @ 1896:f8f818a04f5b
move hgweb template code out to templater
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Sun, 26 Feb 2006 12:59:28 -0800 |
parents | a373881fdf2a |
children | 58b6784cf9f1 |
comparison
equal
deleted
inserted
replaced
1800:414e81ae971f | 1896:f8f818a04f5b |
---|---|
4 # Copyright 2005 Matt Mackall <mpm@selenic.com> | 4 # Copyright 2005 Matt Mackall <mpm@selenic.com> |
5 # | 5 # |
6 # This software may be used and distributed according to the terms | 6 # This software may be used and distributed according to the terms |
7 # of the GNU General Public License, incorporated herein by reference. | 7 # of the GNU General Public License, incorporated herein by reference. |
8 | 8 |
9 import os, cgi, sys, urllib | 9 import os, cgi, sys |
10 import mimetypes | 10 import mimetypes |
11 from demandload import demandload | 11 from demandload import demandload |
12 demandload(globals(), "mdiff time re socket zlib errno ui hg ConfigParser") | 12 demandload(globals(), "mdiff time re socket zlib errno ui hg ConfigParser") |
13 demandload(globals(), "zipfile tempfile StringIO tarfile BaseHTTPServer util") | 13 demandload(globals(), "zipfile tempfile StringIO tarfile BaseHTTPServer util") |
14 demandload(globals(), "mimetypes") | 14 demandload(globals(), "mimetypes templater") |
15 from node import * | 15 from node import * |
16 from i18n import gettext as _ | 16 from i18n import gettext as _ |
17 | 17 |
18 def templatepath(): | 18 def templatepath(): |
19 for f in "templates", "../templates": | 19 for f in "templates", "../templates": |
20 p = os.path.join(os.path.dirname(__file__), f) | 20 p = os.path.join(os.path.dirname(__file__), f) |
21 if os.path.isdir(p): | 21 if os.path.isdir(p): |
22 return os.path.normpath(p) | 22 return os.path.normpath(p) |
23 | |
24 def age(x): | |
25 def plural(t, c): | |
26 if c == 1: | |
27 return t | |
28 return t + "s" | |
29 def fmt(t, c): | |
30 return "%d %s" % (c, plural(t, c)) | |
31 | |
32 now = time.time() | |
33 then = x[0] | |
34 delta = max(1, int(now - then)) | |
35 | |
36 scales = [["second", 1], | |
37 ["minute", 60], | |
38 ["hour", 3600], | |
39 ["day", 3600 * 24], | |
40 ["week", 3600 * 24 * 7], | |
41 ["month", 3600 * 24 * 30], | |
42 ["year", 3600 * 24 * 365]] | |
43 | |
44 scales.reverse() | |
45 | |
46 for t, s in scales: | |
47 n = delta / s | |
48 if n >= 2 or s == 1: | |
49 return fmt(t, n) | |
50 | |
51 def nl2br(text): | |
52 return text.replace('\n', '<br/>\n') | |
53 | |
54 def obfuscate(text): | |
55 return ''.join(['&#%d;' % ord(c) for c in text]) | |
56 | 23 |
57 def up(p): | 24 def up(p): |
58 if p[0] != "/": | 25 if p[0] != "/": |
59 p = "/" + p | 26 p = "/" + p |
60 if p[-1] == "/": | 27 if p[-1] == "/": |
129 if file: | 96 if file: |
130 headers.append(('Content-disposition', 'attachment; filename=%s' % file)) | 97 headers.append(('Content-disposition', 'attachment; filename=%s' % file)) |
131 if size > 0: | 98 if size > 0: |
132 headers.append(('Content-length', str(size))) | 99 headers.append(('Content-length', str(size))) |
133 self.header(headers) | 100 self.header(headers) |
134 | |
135 class templater(object): | |
136 def __init__(self, mapfile, filters={}, defaults={}): | |
137 self.cache = {} | |
138 self.map = {} | |
139 self.base = os.path.dirname(mapfile) | |
140 self.filters = filters | |
141 self.defaults = defaults | |
142 | |
143 for l in file(mapfile): | |
144 m = re.match(r'(\S+)\s*=\s*"(.*)"$', l) | |
145 if m: | |
146 self.cache[m.group(1)] = m.group(2) | |
147 else: | |
148 m = re.match(r'(\S+)\s*=\s*(\S+)', l) | |
149 if m: | |
150 self.map[m.group(1)] = os.path.join(self.base, m.group(2)) | |
151 else: | |
152 raise LookupError(_("unknown map entry '%s'") % l) | |
153 | |
154 def __call__(self, t, **map): | |
155 m = self.defaults.copy() | |
156 m.update(map) | |
157 try: | |
158 tmpl = self.cache[t] | |
159 except KeyError: | |
160 tmpl = self.cache[t] = file(self.map[t]).read() | |
161 return self.template(tmpl, self.filters, **m) | |
162 | |
163 def template(self, tmpl, filters={}, **map): | |
164 while tmpl: | |
165 m = re.search(r"#([a-zA-Z0-9]+)((%[a-zA-Z0-9]+)*)((\|[a-zA-Z0-9]+)*)#", tmpl) | |
166 if m: | |
167 yield tmpl[:m.start(0)] | |
168 v = map.get(m.group(1), "") | |
169 v = callable(v) and v(**map) or v | |
170 | |
171 format = m.group(2) | |
172 fl = m.group(4) | |
173 | |
174 if format: | |
175 q = v.__iter__ | |
176 for i in q(): | |
177 lm = map.copy() | |
178 lm.update(i) | |
179 yield self(format[1:], **lm) | |
180 | |
181 v = "" | |
182 | |
183 elif fl: | |
184 for f in fl.split("|")[1:]: | |
185 v = filters[f](v) | |
186 | |
187 yield v | |
188 tmpl = tmpl[m.end(0):] | |
189 else: | |
190 yield tmpl | |
191 return | |
192 | |
193 common_filters = { | |
194 "escape": lambda x: cgi.escape(x, True), | |
195 "urlescape": urllib.quote, | |
196 "strip": lambda x: x.strip(), | |
197 "age": age, | |
198 "date": lambda x: util.datestr(x), | |
199 "addbreaks": nl2br, | |
200 "obfuscate": obfuscate, | |
201 "short": (lambda x: x[:12]), | |
202 "firstline": (lambda x: x.splitlines(1)[0]), | |
203 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"), | |
204 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"), | |
205 } | |
206 | 101 |
207 class hgweb(object): | 102 class hgweb(object): |
208 def __init__(self, repo, name=None): | 103 def __init__(self, repo, name=None): |
209 if type(repo) == type(""): | 104 if type(repo) == type(""): |
210 self.repo = hg.repository(ui.ui(), repo) | 105 self.repo = hg.repository(ui.ui(), repo) |
908 url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri) | 803 url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri) |
909 if not self.reponame: | 804 if not self.reponame: |
910 self.reponame = (self.repo.ui.config("web", "name") | 805 self.reponame = (self.repo.ui.config("web", "name") |
911 or uri.strip('/') or self.repo.root) | 806 or uri.strip('/') or self.repo.root) |
912 | 807 |
913 self.t = templater(m, common_filters, | 808 self.t = templater.templater(m, templater.common_filters, |
914 {"url": url, | 809 {"url": url, |
915 "repo": self.reponame, | 810 "repo": self.reponame, |
916 "header": header, | 811 "header": header, |
917 "footer": footer, | 812 "footer": footer, |
918 }) | 813 }) |
919 | 814 |
920 if not req.form.has_key('cmd'): | 815 if not req.form.has_key('cmd'): |
921 req.form['cmd'] = [self.t.cache['default'],] | 816 req.form['cmd'] = [self.t.cache['default'],] |
922 | 817 |
923 if req.form['cmd'][0] == 'changelog': | 818 if req.form['cmd'][0] == 'changelog': |