Mercurial > public > mercurial-scm > hg
comparison mercurial/hgweb.py @ 133:fb84d3e71042
added template support for some hgweb output, also, template files for
the parts that have been converted
author | jake@edge2.net |
---|---|
date | Sat, 21 May 2005 16:13:42 -0700 |
parents | 210eeb6f5197 |
children | 13d609f8d830 |
comparison
equal
deleted
inserted
replaced
132:210eeb6f5197 | 133:fb84d3e71042 |
---|---|
23 return ''.join(l) | 23 return ''.join(l) |
24 | 24 |
25 def httphdr(type): | 25 def httphdr(type): |
26 print 'Content-type: %s\n' % type | 26 print 'Content-type: %s\n' % type |
27 | 27 |
28 class template: | |
29 def __init__(self, tmpl_dir): | |
30 self.tmpl_dir = tmpl_dir | |
31 def do_page(self, tmpl_fn, **map): | |
32 out = [] | |
33 txt = file(os.path.join(self.tmpl_dir, tmpl_fn)).read() | |
34 while txt: | |
35 m = re.search(r"#([a-zA-Z0-9]+)#", txt) | |
36 if m: | |
37 out.append(txt[:m.start(0)]) | |
38 v = map.get(m.group(1), "") | |
39 if callable(v): | |
40 for y in v(**map): out.append(y) | |
41 else: | |
42 out.append(str(v)) | |
43 txt = txt[m.end(0):] | |
44 else: | |
45 out.append(txt) | |
46 txt = '' | |
47 return ''.join(out) | |
48 | |
28 class page: | 49 class page: |
29 def __init__(self, type="text/html", title="Mercurial Web", | 50 def __init__(self, tmpl_dir = "", type="text/html", title="Mercurial Web", |
30 charset="ISO-8859-1"): | 51 charset="ISO-8859-1"): |
52 self.tmpl = template(tmpl_dir) | |
53 | |
31 print 'Content-type: %s; charset=%s\n' % (type, charset) | 54 print 'Content-type: %s; charset=%s\n' % (type, charset) |
32 print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">' | 55 print self.tmpl.do_page('htmlstart.tmpl', title = title) |
33 print '<HTML>' | |
34 print '<!-- created by hgweb 0.1 - jake@edge2.net -->' | |
35 print '<HEAD><TITLE>%s</TITLE>' % title | |
36 print '<style type="text/css">' | |
37 print 'body { font-family: sans-serif; font-size: 12px; }' | |
38 print 'table { font-size: 12px; }' | |
39 print '.errmsg { font-size: 200%; color: red; }' | |
40 print '.filename { font-size: 150%; color: purple; }' | |
41 print '.manifest { font-size: 150%; color: purple; }' | |
42 print '.filehist { font-size: 150%; color: purple; }' | |
43 print '.plusline { color: green; }' | |
44 print '.minusline { color: red; }' | |
45 print '.atline { color: purple; }' | |
46 print '</style>' | |
47 print '</HEAD>' | |
48 print '<BODY>' | |
49 | 56 |
50 def endpage(self): | 57 def endpage(self): |
51 print '</BODY>' | 58 print '</BODY>' |
52 print '</HTML>' | 59 print '</HTML>' |
53 | 60 |
71 class errpage(page): | 78 class errpage(page): |
72 def __init__(self): | 79 def __init__(self): |
73 page.__init__(self, title="Mercurial Web Error Page") | 80 page.__init__(self, title="Mercurial Web Error Page") |
74 | 81 |
75 class change_list(page): | 82 class change_list(page): |
76 | 83 def __init__(self, repo, tmpl_dir, reponame, numchanges = 50): |
77 numchanges = 50 # number of changes to show | 84 page.__init__(self, tmpl_dir) |
78 | 85 self.repo = repo |
79 def __init__(self, repo, reponame): | 86 self.numchanges = numchanges |
80 page.__init__(self) | 87 print self.tmpl.do_page('changestitle.tmpl', reponame=reponame) |
81 self.repo = repo | |
82 print '<h3>Changes For: %s</h3>' % reponame | |
83 | 88 |
84 def content(self, hi=None): | 89 def content(self, hi=None): |
85 cl = [] | 90 cl = [] |
86 count = self.repo.changelog.count() | 91 count = self.repo.changelog.count() |
87 if not hi: | 92 if not hi: |
124 def change_table(self, nodeid, changes): | 129 def change_table(self, nodeid, changes): |
125 hn = hg.hex(nodeid) | 130 hn = hg.hex(nodeid) |
126 i = self.repo.changelog.rev(nodeid) | 131 i = self.repo.changelog.rev(nodeid) |
127 (h1, h2) = [ hg.hex(x) for x in self.repo.changelog.parents(nodeid) ] | 132 (h1, h2) = [ hg.hex(x) for x in self.repo.changelog.parents(nodeid) ] |
128 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0]))) | 133 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0]))) |
129 print '<table summary="" width="100%" border="1">' | 134 files = [] |
130 print '\t<tr><td valign="top" width="10%">author:</td>' + \ | |
131 '<td valign="top" width="20%%">%s</td>' % \ | |
132 (obfuscate(changes[1]), ) | |
133 print '\t\t<td valign="top" width="10%">description:</td>' + \ | |
134 '<td width="60%">' + \ | |
135 '<a href="?cmd=chkin;nd=%s">%s</a></td></tr>' % \ | |
136 (hn, nl2br(cgi.escape(changes[4])), ) | |
137 print '\t<tr><td>date:</td><td>%s UTC</td>' % (datestr, ) | |
138 print '\t\t<td valign="top">files:</td><td valign="top">' | |
139 for f in changes[3]: | 135 for f in changes[3]: |
140 print '\t\t<a href="?cmd=file;cs=%s;fn=%s">%s</a> ' % \ | 136 files.append('<a href="?cmd=file;cs=%s;fn=%s">%s</a> ' \ |
141 (hn, f, cgi.escape(f), ) | 137 % (hn, f, cgi.escape(f))) |
142 print '\t</td></tr>' | 138 print self.tmpl.do_page('change_table.tmpl', |
143 print '\t<tr><td>revision:</td><td colspan="3">%d:<a ' % (i, ) + \ | 139 author=obfuscate(changes[1]), |
144 'href="?cmd=chkin;nd=%s">%s</a></td></tr>' % (hn, hn, ) | 140 desc=nl2br(cgi.escape(changes[4])), date=datestr, |
145 print '</table><br />' | 141 files=''.join(files), revnum=i, revnode=hn) |
146 | 142 |
147 class checkin(page): | 143 class checkin(page): |
148 def __init__(self, repo, nodestr): | 144 def __init__(self, repo, tmpl_dir, nodestr): |
149 page.__init__(self) | 145 page.__init__(self, tmpl_dir) |
150 self.repo = repo | 146 self.repo = repo |
151 self.node = hg.bin(nodestr) | 147 self.node = hg.bin(nodestr) |
152 self.nodestr = nodestr | 148 self.nodestr = nodestr |
153 print '<h3>Checkin: %s</h3>' % nodestr | 149 print '<h3>Checkin: %s</h3>' % nodestr |
154 | 150 |
158 parents = self.repo.changelog.parents(self.node) | 154 parents = self.repo.changelog.parents(self.node) |
159 (h1, h2) = [ hg.hex(x) for x in parents ] | 155 (h1, h2) = [ hg.hex(x) for x in parents ] |
160 (i1, i2) = [ self.repo.changelog.rev(x) for x in parents ] | 156 (i1, i2) = [ self.repo.changelog.rev(x) for x in parents ] |
161 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0]))) | 157 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0]))) |
162 mf = self.repo.manifest.read(changes[0]) | 158 mf = self.repo.manifest.read(changes[0]) |
163 print '<table summary="" width="100%" border="1">' | 159 files = [] |
164 print '\t<tr><td>revision:</td><td colspan="3">%d:' % (i, ), | 160 for f in changes[3]: |
165 print '<a href="?cmd=chkin;nd=%s">%s</a></td></tr>' % \ | 161 files.append('<a href="?cmd=file;nd=%s;fn=%s">%s</a> ' \ |
166 (self.nodestr, self.nodestr, ) | 162 % (hg.hex(mf[f]), f, cgi.escape(f))) |
167 print '\t<tr><td>parent(s):</td><td colspan="3">%d:' % (i1, ) | 163 p2link = h2 |
168 print '<a href="?cmd=chkin;nd=%s">%s</a>' % (h1, h1, ), | |
169 if i2 != -1: | 164 if i2 != -1: |
170 print ' %d:<a href="?cmd=chkin;nd=%s">%s</a>' % \ | 165 p2link = '<a href="?cmd=chkin;nd=%s">%s</a>' % (h2, h2) |
171 (i2, h2, h2, ), | 166 |
172 else: | 167 print self.tmpl.do_page('checkin.tmpl', revnum=i, revnode=self.nodestr, |
173 print ' %d:%s' % (i2, h2, ), | 168 p1num=i1, p1node=h1, p2num=i2, p2node=h2, p2link=p2link, |
174 print '</td></tr>' | 169 mfnum=self.repo.manifest.rev(changes[0]), |
175 print '\t<tr><td>manifest:</td><td colspan="3">%d:' % \ | 170 mfnode=hg.hex(changes[0]), author=obfuscate(changes[1]), |
176 (self.repo.manifest.rev(changes[0]), ), | 171 desc=nl2br(cgi.escape(changes[4])), date=datestr) |
177 print '<a href="?cmd=mf;nd=%s">%s</a></td></tr>' % \ | |
178 (hg.hex(changes[0]), hg.hex(changes[0]), ) | |
179 print '\t<tr><td valign="top" width="10%">author:</td>' + \ | |
180 '<td valign="top" width="20%%">%s</td>' % \ | |
181 (obfuscate(changes[1]), ) | |
182 print '\t\t<td valign="top" width="10%">description:</td>' + \ | |
183 '<td width="60%">' + \ | |
184 '<a href="?cmd=chkin;nd=%s">%s</a></td></tr>' % \ | |
185 (self.nodestr, nl2br(cgi.escape(changes[4])), ) | |
186 print '\t<tr><td>date:</td><td>%s UTC</td>' % (datestr, ) | |
187 print '\t\t<td valign="top">files:</td><td valign="top">' | |
188 for f in changes[3]: | |
189 print '\t\t<a href="?cmd=file;nd=%s&fn=%s">%s</a>' % \ | |
190 (hg.hex(mf[f]), f, cgi.escape(f), ), | |
191 print ' ' | |
192 print '\t</td></tr>' | |
193 print '</table><br />' | |
194 | 172 |
195 (c, a, d) = self.repo.diffrevs(parents[0], self.node) | 173 (c, a, d) = self.repo.diffrevs(parents[0], self.node) |
196 change = self.repo.changelog.read(parents[0]) | 174 change = self.repo.changelog.read(parents[0]) |
197 mf2 = self.repo.manifest.read(change[0]) | 175 mf2 = self.repo.manifest.read(change[0]) |
198 for f in c: | 176 for f in c: |
202 self.show_diff('', self.repo.file(f).read(mf[f]), f) | 180 self.show_diff('', self.repo.file(f).read(mf[f]), f) |
203 for f in d: | 181 for f in d: |
204 self.show_diff(self.repo.file(f).read(mf2[f]), '', f) | 182 self.show_diff(self.repo.file(f).read(mf2[f]), '', f) |
205 | 183 |
206 class filepage(page): | 184 class filepage(page): |
207 def __init__(self, repo, fn, node=None, cs=None): | 185 def __init__(self, repo, tmpl_dir, fn, node=None, cs=None): |
208 page.__init__(self) | 186 page.__init__(self, tmpl_dir) |
209 self.repo = repo | 187 self.repo = repo |
210 self.fn = fn | 188 self.fn = fn |
211 if cs: | 189 if cs: |
212 chng = self.repo.changelog.read(hg.bin(cs)) | 190 chng = self.repo.changelog.read(hg.bin(cs)) |
213 mf = self.repo.manifest.read(chng[0]) | 191 mf = self.repo.manifest.read(chng[0]) |
224 print '<pre>' | 202 print '<pre>' |
225 print cgi.escape(self.repo.file(self.fn).read(self.node)) | 203 print cgi.escape(self.repo.file(self.fn).read(self.node)) |
226 print '</pre>' | 204 print '</pre>' |
227 | 205 |
228 class mfpage(page): | 206 class mfpage(page): |
229 def __init__(self, repo, node): | 207 def __init__(self, repo, tmpl_dir, node): |
230 page.__init__(self) | 208 page.__init__(self, tmpl_dir) |
231 self.repo = repo | 209 self.repo = repo |
232 self.nodestr = node | 210 self.nodestr = node |
233 self.node = hg.bin(node) | 211 self.node = hg.bin(node) |
234 | 212 |
235 def content(self): | 213 def content(self): |
236 mf = self.repo.manifest.read(self.node) | 214 mf = self.repo.manifest.read(self.node) |
237 fns = mf.keys() | 215 fns = mf.keys() |
238 fns.sort() | 216 fns.sort() |
239 print '<div class="manifest">Manifest (%s)</div>' % self.nodestr | 217 print self.tmpl.do_page('mftitle.tmpl', node = self.nodestr) |
240 for f in fns: | 218 for f in fns: |
241 print '<a href="?cmd=file;fn=%s;nd=%s">%s</a><br />' % \ | 219 print self.tmpl.do_page('mfentry.tmpl', fn=f, node=hg.hex(mf[f])) |
242 (f, hg.hex(mf[f]), f) | |
243 | 220 |
244 class histpage(page): | 221 class histpage(page): |
245 def __init__(self, repo, fn): | 222 def __init__(self, repo, tmpl_dir, fn): |
246 page.__init__(self) | 223 page.__init__(self, tmpl_dir) |
247 self.repo = repo | 224 self.repo = repo |
248 self.fn = fn | 225 self.fn = fn |
249 | 226 |
250 def content(self): | 227 def content(self): |
251 print '<div class="filehist">File History: %s</div>' % self.fn | 228 print '<div class="filehist">File History: %s</div>' % self.fn |
252 r = self.repo.file(self.fn) | 229 r = self.repo.file(self.fn) |
253 print '<br />' | 230 print '<br />' |
254 print '<table summary="" width="100%" align="center">' | 231 print '<table summary="" width="100%" align="center">' |
255 for i in xrange(r.count()-1, -1, -1): | 232 for i in xrange(r.count()-1, -1, -1): |
256 n = r.node(i) | |
257 (p1, p2) = r.parents(n) | |
258 (h, h1, h2) = map(hg.hex, (n, p1, p2)) | |
259 (i1, i2) = map(r.rev, (p1, p2)) | |
260 ci = r.linkrev(n) | |
261 cn = self.repo.changelog.node(ci) | |
262 cs = hg.hex(cn) | |
263 changes = self.repo.changelog.read(cn) | |
264 print '<tr><td>' | 233 print '<tr><td>' |
265 self.hist_ent(i, h, i1, h1, i2, h2, ci, cs, changes) | 234 self.hist_ent(i, r) |
266 print '</tr></td>' | 235 print '</tr></td>' |
267 print '</table>' | 236 print '</table>' |
268 | 237 |
269 def hist_ent(self, revi, revs, p1i, p1s, p2i, p2s, ci, cs, changes): | 238 def hist_ent(self, i, r): |
239 n = r.node(i) | |
240 (p1, p2) = r.parents(n) | |
241 (h, h1, h2) = map(hg.hex, (n, p1, p2)) | |
242 (i1, i2) = map(r.rev, (p1, p2)) | |
243 ci = r.linkrev(n) | |
244 cn = self.repo.changelog.node(ci) | |
245 cs = hg.hex(cn) | |
246 changes = self.repo.changelog.read(cn) | |
270 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0]))) | 247 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0]))) |
271 print '<table summary="" width="100%" border="1">' | 248 p2entry = '' |
272 print '\t<tr><td valign="top" width="10%">author:</td>' + \ | 249 if i2 != -1: |
273 '<td valign="top" width="20%%">%s</td>' % \ | 250 p2entry = ' %d:<a href="?cmd=file;nd=%s;fn=%s">%s</a>' \ |
274 (obfuscate(changes[1]), ) | 251 % (i2, h2, self.fn, h2 ), |
275 print '\t\t<td valign="top" width="10%">description:</td>' + \ | 252 print self.tmpl.do_page('hist_ent.tmpl', author=obfuscate(changes[1]), |
276 '<td width="60%">' + \ | 253 csnode=cs, desc=nl2br(cgi.escape(changes[4])), |
277 '<a href="?cmd=chkin;nd=%s">%s</a></td></tr>' % \ | 254 date = datestr, fn=self.fn, revnode=h, p1num = i1, |
278 (cs, nl2br(cgi.escape(changes[4])), ) | 255 p1node=h1, p2entry=p2entry) |
279 print '\t<tr><td>date:</td><td>%s UTC</td>' % (datestr, ) | 256 |
280 print '\t\t<td>revision:</td><td>%d:<a ' % (revi, ) + \ | |
281 'href="?cmd=file;cs=%s;fn=%s">%s</a></td></tr>' % \ | |
282 (cs, self.fn, revs ) | |
283 print '\t<tr><td>parent(s):</td><td colspan="3">%d:' % (p1i, ) | |
284 print '<a href="?cmd=file;nd=%s;fn=%s">%s</a>' % (p1s, self.fn, p1s, ), | |
285 if p2i != -1: | |
286 print ' %d:<a href="?cmd=file;nd=%s;fn=%s">%s</a>' % \ | |
287 (p2i, p2s, self.fn, p2s ), | |
288 print '</td></tr>' | |
289 print '</table><br />' | |
290 | |
291 class hgweb: | 257 class hgweb: |
292 repo_path = "." | 258 repo_path = "." |
293 numchanges = 50 | 259 numchanges = 50 |
260 tmpl_dir = "templates" | |
294 | 261 |
295 def __init__(self): | 262 def __init__(self): |
296 pass | 263 pass |
297 | 264 |
298 def run(self): | 265 def run(self): |
301 | 268 |
302 ui = hg.ui() | 269 ui = hg.ui() |
303 repo = hg.repository(ui, self.repo_path) | 270 repo = hg.repository(ui, self.repo_path) |
304 | 271 |
305 if not args.has_key('cmd') or args['cmd'][0] == 'changes': | 272 if not args.has_key('cmd') or args['cmd'][0] == 'changes': |
306 page = change_list(repo, 'Mercurial') | 273 page = change_list(repo, self.tmpl_dir, 'Mercurial', |
274 self.numchanges) | |
307 hi = args.get('hi', ( repo.changelog.count(), )) | 275 hi = args.get('hi', ( repo.changelog.count(), )) |
308 page.content(hi = int(hi[0])) | 276 page.content(hi = int(hi[0])) |
309 page.endpage() | 277 page.endpage() |
310 | 278 |
311 elif args['cmd'][0] == 'chkin': | 279 elif args['cmd'][0] == 'chkin': |
312 if not args.has_key('nd'): | 280 if not args.has_key('nd'): |
313 page = errpage() | 281 page = errpage() |
314 print '<div class="errmsg">No Node!</div>' | 282 print '<div class="errmsg">No Node!</div>' |
315 else: | 283 else: |
316 page = checkin(repo, args['nd'][0]) | 284 page = checkin(repo, self.tmpl_dir, args['nd'][0]) |
317 page.content() | 285 page.content() |
318 page.endpage() | 286 page.endpage() |
319 | 287 |
320 elif args['cmd'][0] == 'file': | 288 elif args['cmd'][0] == 'file': |
321 if not (args.has_key('nd') and args.has_key('fn')) and \ | 289 if not (args.has_key('nd') and args.has_key('fn')) and \ |
322 not (args.has_key('cs') and args.has_key('fn')): | 290 not (args.has_key('cs') and args.has_key('fn')): |
323 page = errpage() | 291 page = errpage() |
324 print '<div class="errmsg">Invalid Args!</div>' | 292 print '<div class="errmsg">Invalid Args!</div>' |
325 else: | 293 else: |
326 if args.has_key('nd'): | 294 if args.has_key('nd'): |
327 page = filepage(repo, args['fn'][0], node=args['nd'][0]) | 295 page = filepage(repo, self.tmpl_dir, |
296 args['fn'][0], node=args['nd'][0]) | |
328 else: | 297 else: |
329 page = filepage(repo, args['fn'][0], cs=args['cs'][0]) | 298 page = filepage(repo, self.tmpl_dir, |
299 args['fn'][0], cs=args['cs'][0]) | |
330 page.content() | 300 page.content() |
331 page.endpage() | 301 page.endpage() |
332 | 302 |
333 elif args['cmd'][0] == 'mf': | 303 elif args['cmd'][0] == 'mf': |
334 if not args.has_key('nd'): | 304 if not args.has_key('nd'): |
335 page = errpage() | 305 page = errpage() |
336 print '<div class="errmsg">No Node!</div>' | 306 print '<div class="errmsg">No Node!</div>' |
337 else: | 307 else: |
338 page = mfpage(repo, args['nd'][0]) | 308 page = mfpage(repo, self.tmpl_dir, args['nd'][0]) |
339 page.content() | 309 page.content() |
340 page.endpage() | 310 page.endpage() |
341 | 311 |
342 elif args['cmd'][0] == 'hist': | 312 elif args['cmd'][0] == 'hist': |
343 if not args.has_key('fn'): | 313 if not args.has_key('fn'): |
344 page = errpage() | 314 page = errpage() |
345 print '<div class="errmsg">No Filename!</div>' | 315 print '<div class="errmsg">No Filename!</div>' |
346 else: | 316 else: |
347 page = histpage(repo, args['fn'][0]) | 317 page = histpage(repo, self.tmpl_dir, args['fn'][0]) |
348 page.content() | 318 page.content() |
349 page.endpage() | 319 page.endpage() |
350 | 320 |
351 elif args['cmd'][0] == 'branches': | 321 elif args['cmd'][0] == 'branches': |
352 httphdr("text/plain") | 322 httphdr("text/plain") |