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> ' \ |
|
110 % (start, self.numchanges)) + nav |
|
111 if hi != count: |
|
112 if hi + self.numchanges <= count: |
|
113 nav += ' <a href="?cmd=changes;hi=%d">Next %d</a>' \ |
|
114 % (hi + self.numchanges, self.numchanges) |
|
115 else: |
|
116 nav += ' <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> ' \ |
|
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> ' \ |
|
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 = ' %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() |