comparison mercurial/hgweb.py @ 138:c77a679e9cfa

Revamped templated hgweb
author mpm@selenic.com
date Mon, 23 May 2005 16:00:02 -0800
parents b45b1b00fc9e
children 529bf610092e
comparison
equal deleted inserted replaced
137:b45b1b00fc9e 138:c77a679e9cfa
9 # useful for debugging 9 # useful for debugging
10 import cgitb 10 import cgitb
11 cgitb.enable() 11 cgitb.enable()
12 12
13 import os, cgi, time, re, difflib, sys, zlib 13 import os, cgi, time, re, difflib, sys, zlib
14 from mercurial import hg, mdiff 14 from mercurial.hg import *
15
16 def age(t):
17 def plural(t, c):
18 if c == 1: return t
19 return t + "s"
20 def fmt(t, c):
21 return "%d %s" % (c, plural(t, c))
22
23 now = time.time()
24 delta = max(1, int(now - t))
25
26 scales = [["second", 1],
27 ["minute", 60],
28 ["hour", 3600],
29 ["day", 3600 * 24],
30 ["week", 3600 * 24 * 7],
31 ["month", 3600 * 24 * 30],
32 ["year", 3600 * 24 * 365]]
33
34 scales.reverse()
35
36 for t, s in scales:
37 n = delta / s
38 if n >= 1: return fmt(t, n)
15 39
16 def nl2br(text): 40 def nl2br(text):
17 return re.sub('\n', '<br />', text) 41 return text.replace('\n', '<br/>')
18 42
19 def obfuscate(text): 43 def obfuscate(text):
20 l = [] 44 return ''.join([ '&#%d' % ord(c) for c in text ])
21 for c in text: 45
22 l.append('&#%d;' % ord(c)) 46 def up(p):
23 return ''.join(l) 47 if p[0] != "/": p = "/" + p
48 if p[-1] == "/": p = p[:-1]
49 up = os.path.dirname(p)
50 if up == "/":
51 return "/"
52 return up + "/"
24 53
25 def httphdr(type): 54 def httphdr(type):
26 print 'Content-type: %s\n' % type 55 print 'Content-type: %s\n' % type
27 56
28 def write(*things): 57 def write(*things):
31 for part in thing: 60 for part in thing:
32 write(part) 61 write(part)
33 else: 62 else:
34 sys.stdout.write(str(thing)) 63 sys.stdout.write(str(thing))
35 64
36 class template: 65 def template(tmpl, **map):
37 def __init__(self, tmpl_dir): 66 while tmpl:
38 self.tmpl_dir = tmpl_dir 67 m = re.search(r"#([a-zA-Z0-9]+)#", tmpl)
39 def do_page(self, tmpl_fn, **map): 68 if m:
40 txt = file(os.path.join(self.tmpl_dir, tmpl_fn)).read() 69 yield tmpl[:m.start(0)]
41 while txt: 70 v = map.get(m.group(1), "")
42 m = re.search(r"#([a-zA-Z0-9]+)#", txt) 71 yield callable(v) and v() or v
72 tmpl = tmpl[m.end(0):]
73 else:
74 yield tmpl
75 return
76
77 class templater:
78 def __init__(self, mapfile):
79 self.cache = {}
80 self.map = {}
81 self.base = os.path.dirname(mapfile)
82
83 for l in file(mapfile):
84 m = re.match(r'(\S+)\s*=\s*"(.*)"$', l)
43 if m: 85 if m:
44 yield txt[:m.start(0)] 86 self.cache[m.group(1)] = m.group(2)
45 v = map.get(m.group(1), "") 87 else:
46 if callable(v): 88 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
47 for y in v(**map): yield y 89 if m:
90 self.map[m.group(1)] = os.path.join(self.base, m.group(2))
48 else: 91 else:
49 yield v 92 raise "unknown map entry '%s'" % l
50 txt = txt[m.end(0):] 93
94 def __call__(self, t, **map):
95 try:
96 tmpl = self.cache[t]
97 except KeyError:
98 tmpl = self.cache[t] = file(self.map[t]).read()
99 return template(tmpl, **map)
100
101 class hgweb:
102 maxchanges = 20
103 maxfiles = 10
104
105 def __init__(self, path, name, templatemap):
106 self.reponame = name
107 self.repo = repository(ui(), path)
108 self.t = templater(templatemap)
109
110 def date(self, cs):
111 return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
112
113 def listfiles(self, files, mf):
114 for f in files[:self.maxfiles]:
115 yield self.t("filenodelink", node = hex(mf[f]), file = f)
116 if len(files) > self.maxfiles:
117 yield self.t("fileellipses")
118
119 def listfilediffs(self, files, changeset):
120 for f in files[:self.maxfiles]:
121 yield self.t("filedifflink", node = hex(changeset), file = f)
122 if len(files) > self.maxfiles:
123 yield self.t("fileellipses")
124
125 def diff(self, node1, node2, files):
126 def filterfiles(list, files):
127 l = [ x for x in list if x in files ]
128
129 for f in files:
130 if f[-1] != os.sep: f += os.sep
131 l += [ x for x in list if x.startswith(f) ]
132 return l
133
134 def prettyprint(diff):
135 for l in diff.splitlines(1):
136 line = cgi.escape(l)
137 if line.startswith('+'):
138 yield self.t("difflineplus", line = line)
139 elif line.startswith('-'):
140 yield self.t("difflineminus", line = line)
141 elif line.startswith('@'):
142 yield self.t("difflineat", line = line)
143 else:
144 yield self.t("diffline", line = line)
145
146 r = self.repo
147 cl = r.changelog
148 mf = r.manifest
149 change1 = cl.read(node1)
150 change2 = cl.read(node2)
151 mmap1 = mf.read(change1[0])
152 mmap2 = mf.read(change2[0])
153 date1 = self.date(change1)
154 date2 = self.date(change2)
155
156 c, a, d = r.diffrevs(node1, node2)
157 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
158
159 for f in c:
160 to = r.file(f).read(mmap1[f])
161 tn = r.file(f).read(mmap2[f])
162 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
163 for f in a:
164 to = ""
165 tn = r.file(f).read(mmap2[f])
166 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
167 for f in d:
168 to = r.file(f).read(mmap1[f])
169 tn = ""
170 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
171
172 def changelog(self, pos=None):
173 def changenav():
174 def seq(factor = 1):
175 yield 1 * factor
176 yield 2 * factor
177 yield 5 * factor
178 for f in seq(factor * 10):
179 yield f
180
181 linear = range(0, count - 2, self.maxchanges)[0:8]
182
183 for i in linear:
184 yield self.t("naventry", rev = max(i, 1))
185
186 for s in seq():
187 if s > count - 2: break
188 if s > linear[-1]:
189 yield self.t("naventry", rev = s)
190
191 yield self.t("naventry", rev = count - 1)
192
193 def changelist():
194 cl = self.repo.changelog
195 l = [] # build a list in forward order for efficiency
196 for i in range(start, end + 1):
197 n = cl.node(i)
198 changes = cl.read(n)
199 hn = hex(n)
200 p1, p2 = cl.parents(n)
201 t = float(changes[2].split(' ')[0])
202
203 l.insert(0, self.t(
204 'changelogentry',
205 author = obfuscate(changes[1]),
206 shortdesc = cgi.escape(changes[4].splitlines()[0]),
207 age = age(t),
208 p1 = hex(p1), p2 = hex(p2),
209 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
210 manifest = hex(changes[0]),
211 desc = nl2br(cgi.escape(changes[4])),
212 date = time.asctime(time.gmtime(t)),
213 files = self.listfilediffs(changes[3], n),
214 rev = i,
215 node = hn))
216
217 yield l
218
219 count = self.repo.changelog.count()
220 pos = pos or count - 1
221 end = min(pos, count - 1)
222 start = max(0, pos - self.maxchanges)
223 end = min(count - 1, start + self.maxchanges)
224
225 yield self.t('changelog', repo = self.reponame, changenav = changenav,
226 rev = pos, changesets = count, changelist = changelist)
227
228 def changeset(self, nodeid):
229 n = bin(nodeid)
230 cl = self.repo.changelog
231 changes = cl.read(n)
232 p1, p2 = cl.parents(n)
233 p1rev, p2rev = cl.rev(p1), cl.rev(p2)
234 t = float(changes[2].split(' ')[0])
235
236 files = []
237 mf = self.repo.manifest.read(changes[0])
238 for f in changes[3]:
239 files.append(self.t("filenodelink",
240 filenode = hex(mf[f]), file = f))
241
242 def diff():
243 yield self.diff(p1, n, changes[3])
244
245 yield self.t('changeset',
246 diff = diff,
247 rev = cl.rev(n),
248 node = nodeid,
249 shortdesc = cgi.escape(changes[4].splitlines()[0]),
250 p1 = hex(p1), p2 = hex(p2),
251 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
252 manifest = hex(changes[0]),
253 author = obfuscate(changes[1]),
254 desc = nl2br(cgi.escape(changes[4])),
255 date = time.asctime(time.gmtime(t)),
256 files = files)
257
258 def filelog(self, f, filenode):
259 cl = self.repo.changelog
260 fl = self.repo.file(f)
261 count = fl.count()
262
263 def entries():
264 l = []
265 for i in range(count):
266
267 n = fl.node(i)
268 lr = fl.linkrev(n)
269 cn = cl.node(lr)
270 cs = cl.read(cl.node(lr))
271 p1, p2 = fl.parents(n)
272 t = float(cs[2].split(' ')[0])
273
274 l.insert(0, self.t("filelogentry",
275 filenode = hex(n),
276 filerev = i,
277 file = f,
278 node = hex(cn),
279 author = obfuscate(cs[1]),
280 age = age(t),
281 date = time.asctime(time.gmtime(t)),
282 shortdesc = cgi.escape(cs[4].splitlines()[0]),
283 p1 = hex(p1), p2 = hex(p2),
284 p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
285
286 yield l
287
288 yield self.t("filelog",
289 file = f,
290 filenode = filenode,
291 entries = entries)
292
293 def filerevision(self, f, node):
294 fl = self.repo.file(f)
295 n = bin(node)
296 text = cgi.escape(fl.read(n))
297 changerev = fl.linkrev(n)
298 cl = self.repo.changelog
299 cn = cl.node(changerev)
300 cs = cl.read(cn)
301 p1, p2 = fl.parents(n)
302 t = float(cs[2].split(' ')[0])
303 mfn = cs[0]
304
305 yield self.t("filerevision", file = f,
306 filenode = node,
307 path = up(f),
308 text = text,
309 rev = changerev,
310 node = hex(cn),
311 manifest = hex(mfn),
312 author = obfuscate(cs[1]),
313 age = age(t),
314 date = time.asctime(time.gmtime(t)),
315 shortdesc = cgi.escape(cs[4].splitlines()[0]),
316 p1 = hex(p1), p2 = hex(p2),
317 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
318
319
320 def fileannotate(self, f, node):
321 bcache = {}
322 ncache = {}
323 fl = self.repo.file(f)
324 n = bin(node)
325 changerev = fl.linkrev(n)
326
327 cl = self.repo.changelog
328 cn = cl.node(changerev)
329 cs = cl.read(cn)
330 p1, p2 = fl.parents(n)
331 t = float(cs[2].split(' ')[0])
332 mfn = cs[0]
333
334 def annotate():
335 for r, l in fl.annotate(n):
336 try:
337 cnode = ncache[r]
338 except KeyError:
339 cnode = ncache[r] = self.repo.changelog.node(r)
340
341 try:
342 name = bcache[r]
343 except KeyError:
344 cl = self.repo.changelog.read(cnode)
345 name = cl[1]
346 f = name.find('@')
347 if f >= 0:
348 name = name[:f]
349 bcache[r] = name
350
351 yield self.t("annotateline",
352 node = hex(cnode),
353 rev = r,
354 author = name,
355 file = f,
356 line = cgi.escape(l))
357
358 yield self.t("fileannotate",
359 file = f,
360 filenode = node,
361 annotate = annotate,
362 path = up(f),
363 rev = changerev,
364 node = hex(cn),
365 manifest = hex(mfn),
366 author = obfuscate(cs[1]),
367 age = age(t),
368 date = time.asctime(time.gmtime(t)),
369 shortdesc = cgi.escape(cs[4].splitlines()[0]),
370 p1 = hex(p1), p2 = hex(p2),
371 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
372
373 def manifest(self, mnode, path):
374 mf = self.repo.manifest.read(bin(mnode))
375 rev = self.repo.manifest.rev(bin(mnode))
376 node = self.repo.changelog.node(rev)
377
378 dirs = {}
379 files = {}
380 short = {}
381
382 p = path[1:]
383 l = len(p)
384
385 for f,n in mf.items():
386 if f[:l] != p:
387 continue
388 remain = f[l:]
389 if "/" in remain:
390 short = remain[:remain.find("/") + 1] # bleah
391 dirs[short] = 1
51 else: 392 else:
52 yield txt 393 short = os.path.basename(remain)
53 txt = '' 394 files[short] = (f, n)
54 395
55 class page: 396 def dirlist():
56 def __init__(self, tmpl_dir = "", type="text/html", title="Mercurial Web", 397 dl = dirs.keys()
57 charset="ISO-8859-1"): 398 dl.sort()
58 self.tmpl = template(tmpl_dir) 399
59 400 for d in dl:
60 print 'Content-type: %s; charset=%s\n' % (type, charset) 401 yield self.t("manifestdirentry",
61 write(self.tmpl.do_page('htmlstart.tmpl', title = title)) 402 path = os.path.join(path, d),
62 403 manifest = mnode, basename = d[:-1])
63 def endpage(self): 404
64 print '</BODY>' 405 def filelist():
65 print '</HTML>' 406 fl = files.keys()
66 407 fl.sort()
67 def show_diff(self, a, b, fn): 408 for f in fl:
68 a = a.splitlines(1) 409 full, fnode = files[f]
69 b = b.splitlines(1) 410 yield self.t("manifestfileentry",
70 l = difflib.unified_diff(a, b, fn, fn) 411 file = full, manifest = mnode, filenode = hex(fnode),
71 print '<pre>' 412 basename = f)
72 for line in l: 413
73 line = cgi.escape(line[:-1]) 414 yield self.t("manifest",
74 if line.startswith('+'): 415 manifest = mnode,
75 print '<span class="plusline">%s</span>' % (line, ) 416 rev = rev,
76 elif line.startswith('-'): 417 node = hex(node),
77 print '<span class="minusline">%s</span>' % (line, ) 418 path = path,
78 elif line.startswith('@'): 419 up = up(path),
79 print '<span class="atline">%s</span>' % (line, ) 420 dirs = dirlist,
80 else: 421 files = filelist)
81 print line 422
82 print '</pre>' 423 def filediff(self, file, changeset):
83 424 n = bin(changeset)
84 class errpage(page): 425 cl = self.repo.changelog
85 def __init__(self, tmpl_dir): 426 p1 = cl.parents(n)[0]
86 page.__init__(self, tmpl_dir, title="Mercurial Web Error Page") 427 cs = cl.read(n)
87 428 mf = self.repo.manifest.read(cs[0])
88 class change_list(page): 429
89 def __init__(self, repo, tmpl_dir, reponame, numchanges = 50): 430 def diff():
90 page.__init__(self, tmpl_dir) 431 yield self.diff(p1, n, file)
91 self.repo = repo 432
92 self.numchanges = numchanges 433 yield self.t("filediff",
93 write(self.tmpl.do_page('changestitle.tmpl', reponame=reponame)) 434 file = file,
94 435 filenode = hex(mf[file]),
95 def content(self, hi=None): 436 node = changeset,
96 cl = [] 437 rev = self.repo.changelog.rev(n),
97 count = self.repo.changelog.count() 438 p1 = hex(p1),
98 if not hi: 439 p1rev = self.repo.changelog.rev(p1),
99 hi = count 440 diff = diff)
100 elif hi < self.numchanges: 441
101 hi = self.numchanges 442 # header and footer, css
102 443 # add tags to things
103 start = 0 444 # show parents
104 if hi - self.numchanges >= 0: 445 # diff between rev and parent in changeset and file
105 start = hi - self.numchanges 446 # manifest links
106 447 # browse at top
107 nav = "Displaying Revisions: %d-%d" % (start, hi-1) 448 # tags -> list of changesets corresponding to tags
108 if start != 0: 449 # find tag, changeset, file
109 nav = ('<a href="?cmd=changes;hi=%d">Previous %d</a>&nbsp;&nbsp;' \
110 % (start, self.numchanges)) + nav
111 if hi != count:
112 if hi + self.numchanges <= count:
113 nav += '&nbsp;&nbsp;<a href="?cmd=changes;hi=%d">Next %d</a>' \
114 % (hi + self.numchanges, self.numchanges)
115 else:
116 nav += '&nbsp;&nbsp;<a href="?cmd=changes">Next %d</a>' % \
117 self.numchanges
118
119 print '<center>%s</center>' % nav
120
121 for i in xrange(start, hi):
122 n = self.repo.changelog.node(i)
123 cl.append((n, self.repo.changelog.read(n)))
124 cl.reverse()
125
126 print '<table summary="" width="100%" align="center">'
127 for n, ch in cl:
128 print '<tr><td>'
129 self.change_table(n, ch)
130 print '</td></tr>'
131 print '</table>'
132
133 print '<center>%s</center>' % nav
134
135 def change_table(self, nodeid, changes):
136 hn = hg.hex(nodeid)
137 i = self.repo.changelog.rev(nodeid)
138 (h1, h2) = [ hg.hex(x) for x in self.repo.changelog.parents(nodeid) ]
139 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0])))
140 files = []
141 for f in changes[3]:
142 files.append('<a href="?cmd=file;cs=%s;fn=%s">%s</a>&nbsp;&nbsp;' \
143 % (hn, f, cgi.escape(f)))
144 write(self.tmpl.do_page('change_table.tmpl',
145 author=obfuscate(changes[1]),
146 desc=nl2br(cgi.escape(changes[4])), date=datestr,
147 files=' '.join(files), revnum=i, revnode=hn))
148
149 class checkin(page):
150 def __init__(self, repo, tmpl_dir, nodestr):
151 page.__init__(self, tmpl_dir)
152 self.repo = repo
153 self.node = hg.bin(nodestr)
154 self.nodestr = nodestr
155 print '<h3>Checkin: %s</h3>' % nodestr
156
157 def content(self):
158 changes = self.repo.changelog.read(self.node)
159 i = self.repo.changelog.rev(self.node)
160 parents = self.repo.changelog.parents(self.node)
161 (h1, h2) = [ hg.hex(x) for x in parents ]
162 (i1, i2) = [ self.repo.changelog.rev(x) for x in parents ]
163 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0])))
164 mf = self.repo.manifest.read(changes[0])
165 files = []
166 for f in changes[3]:
167 files.append('<a href="?cmd=file;nd=%s;fn=%s">%s</a>&nbsp;&nbsp;' \
168 % (hg.hex(mf[f]), f, cgi.escape(f)))
169 p2link = h2
170 if i2 != -1:
171 p2link = '<a href="?cmd=chkin;nd=%s">%s</a>' % (h2, h2)
172
173 write(self.tmpl.do_page('checkin.tmpl', revnum=i, revnode=self.nodestr,
174 p1num=i1, p1node=h1, p2num=i2, p2node=h2, p2link=p2link,
175 mfnum=self.repo.manifest.rev(changes[0]),
176 mfnode=hg.hex(changes[0]), author=obfuscate(changes[1]),
177 desc=nl2br(cgi.escape(changes[4])), date=datestr,
178 files=' '.join(files)))
179
180 (c, a, d) = self.repo.diffrevs(parents[0], self.node)
181 change = self.repo.changelog.read(parents[0])
182 mf2 = self.repo.manifest.read(change[0])
183 for f in c:
184 self.show_diff(self.repo.file(f).read(mf2[f]), \
185 self.repo.file(f).read(mf[f]), f)
186 for f in a:
187 self.show_diff('', self.repo.file(f).read(mf[f]), f)
188 for f in d:
189 self.show_diff(self.repo.file(f).read(mf2[f]), '', f)
190
191 class filepage(page):
192 def __init__(self, repo, tmpl_dir, fn, node=None, cs=None):
193 page.__init__(self, tmpl_dir)
194 self.repo = repo
195 self.fn = fn
196 if cs:
197 chng = self.repo.changelog.read(hg.bin(cs))
198 mf = self.repo.manifest.read(chng[0])
199 self.node = mf[self.fn]
200 self.nodestr = hg.hex(self.node)
201 else:
202 self.nodestr = node
203 self.node = hg.bin(node)
204 print '<div class="filename">%s (%s)</div>' % \
205 (cgi.escape(self.fn), self.nodestr, )
206 print '<a href="?cmd=hist;fn=%s">history</a><br />' % self.fn
207 print '<a href="?cmd=ann;fn=%s;nd=%s">annotate</a><br />' % \
208 (self.fn, self.nodestr)
209
210 def content(self):
211 print '<pre>'
212 print cgi.escape(self.repo.file(self.fn).read(self.node))
213 print '</pre>'
214
215 class annpage(page):
216 def __init__(self, repo, tmpl_dir, fn, node):
217 page.__init__(self, tmpl_dir)
218 self.repo = repo
219 self.fn = fn
220 self.nodestr = node
221 self.node = hg.bin(node)
222 print '<div class="annotation">Annotated: %s (%s)</div>' % \
223 (cgi.escape(self.fn), self.nodestr, )
224
225 def content(self):
226 print '<pre>'
227 for n, l in self.repo.file(self.fn).annotate(self.node):
228 cnode = self.repo.changelog.lookup(n)
229 write(self.tmpl.do_page('annline.tmpl', cnode=hg.hex(cnode),
230 cnum='% 6s' % n, fn=self.fn, line=cgi.escape(l[:-1])))
231 print '</pre>'
232
233 class mfpage(page):
234 def __init__(self, repo, tmpl_dir, node):
235 page.__init__(self, tmpl_dir)
236 self.repo = repo
237 self.nodestr = node
238 self.node = hg.bin(node)
239
240 def content(self):
241 mf = self.repo.manifest.read(self.node)
242 fns = mf.keys()
243 fns.sort()
244 write(self.tmpl.do_page('mftitle.tmpl', node = self.nodestr))
245 for f in fns:
246 write(self.tmpl.do_page('mfentry.tmpl', fn=f, node=hg.hex(mf[f])))
247
248 class histpage(page):
249 def __init__(self, repo, tmpl_dir, fn):
250 page.__init__(self, tmpl_dir)
251 self.repo = repo
252 self.fn = fn
253
254 def content(self):
255 print '<div class="filehist">File History: %s</div>' % self.fn
256 r = self.repo.file(self.fn)
257 print '<br />'
258 print '<table summary="" width="100%" align="center">'
259 for i in xrange(r.count()-1, -1, -1):
260 print '<tr><td>'
261 self.hist_ent(i, r)
262 print '</tr></td>'
263 print '</table>'
264
265 def hist_ent(self, i, r):
266 n = r.node(i)
267 (p1, p2) = r.parents(n)
268 (h, h1, h2) = map(hg.hex, (n, p1, p2))
269 (i1, i2) = map(r.rev, (p1, p2))
270 ci = r.linkrev(n)
271 cn = self.repo.changelog.node(ci)
272 cs = hg.hex(cn)
273 changes = self.repo.changelog.read(cn)
274 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0])))
275 p2entry = ''
276 if i2 != -1:
277 p2entry = '&nbsp;&nbsp;%d:<a href="?cmd=file;nd=%s;fn=%s">%s</a>' \
278 % (i2, h2, self.fn, h2 ),
279 write(self.tmpl.do_page('hist_ent.tmpl', author=obfuscate(changes[1]),
280 csnode=cs, desc=nl2br(cgi.escape(changes[4])),
281 date = datestr, fn=self.fn, revnode=h, p1num = i1,
282 p1node=h1, p2entry=p2entry))
283
284 class hgweb:
285 repo_path = "."
286 numchanges = 50
287 tmpl_dir = "templates"
288
289 def __init__(self):
290 pass
291 450
292 def run(self): 451 def run(self):
293
294 args = cgi.parse() 452 args = cgi.parse()
295 453
296 ui = hg.ui() 454 if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
297 repo = hg.repository(ui, self.repo_path) 455 hi = self.repo.changelog.count()
298 456 if args.has_key('pos'):
299 if not args.has_key('cmd') or args['cmd'][0] == 'changes': 457 hi = int(args['pos'][0])
300 page = change_list(repo, self.tmpl_dir, 'Mercurial', 458
301 self.numchanges) 459 write(self.changelog(hi))
302 hi = args.get('hi', ( repo.changelog.count(), ))
303 page.content(hi = int(hi[0]))
304 page.endpage()
305 460
306 elif args['cmd'][0] == 'chkin': 461 elif args['cmd'][0] == 'changeset':
307 if not args.has_key('nd'): 462 write(self.changeset(args['node'][0]))
308 page = errpage(self.tmpl_dir) 463
309 print '<div class="errmsg">No Node!</div>' 464 elif args['cmd'][0] == 'manifest':
310 else: 465 write(self.manifest(args['manifest'][0], args['path'][0]))
311 page = checkin(repo, self.tmpl_dir, args['nd'][0]) 466
312 page.content() 467 elif args['cmd'][0] == 'filediff':
313 page.endpage() 468 write(self.filediff(args['file'][0], args['node'][0]))
314 469
315 elif args['cmd'][0] == 'file': 470 elif args['cmd'][0] == 'file':
316 if not (args.has_key('nd') and args.has_key('fn')) and \ 471 write(self.filerevision(args['file'][0], args['filenode'][0]))
317 not (args.has_key('cs') and args.has_key('fn')): 472
318 page = errpage(self.tmpl_dir) 473 elif args['cmd'][0] == 'annotate':
319 print '<div class="errmsg">Invalid Args!</div>' 474 write(self.fileannotate(args['file'][0], args['filenode'][0]))
320 else: 475
321 if args.has_key('nd'): 476 elif args['cmd'][0] == 'filelog':
322 page = filepage(repo, self.tmpl_dir, 477 write(self.filelog(args['file'][0], args['filenode'][0]))
323 args['fn'][0], node=args['nd'][0])
324 else:
325 page = filepage(repo, self.tmpl_dir,
326 args['fn'][0], cs=args['cs'][0])
327 page.content()
328 page.endpage()
329
330 elif args['cmd'][0] == 'mf':
331 if not args.has_key('nd'):
332 page = errpage(self.tmpl_dir)
333 print '<div class="errmsg">No Node!</div>'
334 else:
335 page = mfpage(repo, self.tmpl_dir, args['nd'][0])
336 page.content()
337 page.endpage()
338
339 elif args['cmd'][0] == 'hist':
340 if not args.has_key('fn'):
341 page = errpage(self.tmpl_dir)
342 print '<div class="errmsg">No Filename!</div>'
343 else:
344 page = histpage(repo, self.tmpl_dir, args['fn'][0])
345 page.content()
346 page.endpage()
347
348 elif args['cmd'][0] == 'ann':
349 if not args.has_key('fn'):
350 page = errpage(self.tmpl_dir)
351 print '<div class="errmsg">No Filename!</div>'
352 elif not args.has_key('nd'):
353 page = errpage(self.tmpl_dir)
354 print '<div class="errmsg">No Node!</div>'
355 else:
356 page = annpage(repo, self.tmpl_dir, args['fn'][0],
357 args['nd'][0])
358 page.content()
359 page.endpage()
360 478
361 elif args['cmd'][0] == 'branches': 479 elif args['cmd'][0] == 'branches':
362 httphdr("text/plain") 480 httphdr("text/plain")
363 nodes = [] 481 nodes = []
364 if args.has_key('nodes'): 482 if args.has_key('nodes'):
365 nodes = map(hg.bin, args['nodes'][0].split(" ")) 483 nodes = map(bin, args['nodes'][0].split(" "))
366 for b in repo.branches(nodes): 484 for b in self.repo.branches(nodes):
367 print " ".join(map(hg.hex, b)) 485 sys.stdout.write(" ".join(map(hex, b)) + "\n")
368 486
369 elif args['cmd'][0] == 'between': 487 elif args['cmd'][0] == 'between':
370 httphdr("text/plain") 488 httphdr("text/plain")
371 nodes = [] 489 nodes = []
372 if args.has_key('pairs'): 490 if args.has_key('pairs'):
373 pairs = [ map(hg.bin, p.split("-")) 491 pairs = [ map(bin, p.split("-"))
374 for p in args['pairs'][0].split(" ") ] 492 for p in args['pairs'][0].split(" ") ]
375 for b in repo.between(pairs): 493 for b in self.repo.between(pairs):
376 print " ".join(map(hg.hex, b)) 494 sys.stdout.write(" ".join(map(hex, b)) + "\n")
377 495
378 elif args['cmd'][0] == 'changegroup': 496 elif args['cmd'][0] == 'changegroup':
379 httphdr("application/hg-changegroup") 497 httphdr("application/hg-changegroup")
380 nodes = [] 498 nodes = []
381 if args.has_key('roots'): 499 if args.has_key('roots'):
382 nodes = map(hg.bin, args['roots'][0].split(" ")) 500 nodes = map(bin, args['roots'][0].split(" "))
383 501
384 z = zlib.compressobj() 502 z = zlib.compressobj()
385 for chunk in repo.changegroup(nodes): 503 for chunk in self.repo.changegroup(nodes):
386 sys.stdout.write(z.compress(chunk)) 504 sys.stdout.write(z.compress(chunk))
387 505
388 sys.stdout.write(z.flush()) 506 sys.stdout.write(z.flush())
389 507
390 else: 508 else:
391 page = errpage(self.tmpl_dir) 509 write(self.t("error"))
392 print '<div class="errmsg">unknown command: %s</div>' % \
393 cgi.escape(args['cmd'][0])
394 page.endpage()
395 510
396 if __name__ == "__main__": 511 if __name__ == "__main__":
397 hgweb().run() 512 hgweb().run()