Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/hgweb/hgweb_mod.py @ 2356:2db831b33e8f
Final stage of the hgweb split up.
hgweb and hgwebdir now have their own modules.
author | Eric Hopper <hopper@omnifarious.org> |
---|---|
date | Wed, 31 May 2006 10:42:44 -0700 |
parents | mercurial/hgweb/__init__.py@eb08fb4d41e1 |
children | 8819fc1dcf4b |
comparison
equal
deleted
inserted
replaced
2355:eb08fb4d41e1 | 2356:2db831b33e8f |
---|---|
1 # hgweb.py - web interface to a mercurial repository | |
2 # | |
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | |
4 # Copyright 2005 Matt Mackall <mpm@selenic.com> | |
5 # | |
6 # This software may be used and distributed according to the terms | |
7 # of the GNU General Public License, incorporated herein by reference. | |
8 | |
9 import os | |
10 import os.path | |
11 import mimetypes | |
12 from mercurial.demandload import demandload | |
13 demandload(globals(), "re zlib ConfigParser") | |
14 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater") | |
15 demandload(globals(), "mercurial.hgweb.request:hgrequest") | |
16 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") | |
17 from mercurial.node import * | |
18 from mercurial.i18n import gettext as _ | |
19 | |
20 def _up(p): | |
21 if p[0] != "/": | |
22 p = "/" + p | |
23 if p[-1] == "/": | |
24 p = p[:-1] | |
25 up = os.path.dirname(p) | |
26 if up == "/": | |
27 return "/" | |
28 return up + "/" | |
29 | |
30 class hgweb(object): | |
31 def __init__(self, repo, name=None): | |
32 if type(repo) == type(""): | |
33 self.repo = hg.repository(ui.ui(), repo) | |
34 else: | |
35 self.repo = repo | |
36 | |
37 self.mtime = -1 | |
38 self.reponame = name | |
39 self.archives = 'zip', 'gz', 'bz2' | |
40 | |
41 def refresh(self): | |
42 mtime = get_mtime(self.repo.root) | |
43 if mtime != self.mtime: | |
44 self.mtime = mtime | |
45 self.repo = hg.repository(self.repo.ui, self.repo.root) | |
46 self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10)) | |
47 self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10)) | |
48 self.allowpull = self.repo.ui.configbool("web", "allowpull", True) | |
49 | |
50 def archivelist(self, nodeid): | |
51 for i in self.archives: | |
52 if self.repo.ui.configbool("web", "allow" + i, False): | |
53 yield {"type" : i, "node" : nodeid, "url": ""} | |
54 | |
55 def listfiles(self, files, mf): | |
56 for f in files[:self.maxfiles]: | |
57 yield self.t("filenodelink", node=hex(mf[f]), file=f) | |
58 if len(files) > self.maxfiles: | |
59 yield self.t("fileellipses") | |
60 | |
61 def listfilediffs(self, files, changeset): | |
62 for f in files[:self.maxfiles]: | |
63 yield self.t("filedifflink", node=hex(changeset), file=f) | |
64 if len(files) > self.maxfiles: | |
65 yield self.t("fileellipses") | |
66 | |
67 def siblings(self, siblings=[], rev=None, hiderev=None, **args): | |
68 if not rev: | |
69 rev = lambda x: "" | |
70 siblings = [s for s in siblings if s != nullid] | |
71 if len(siblings) == 1 and rev(siblings[0]) == hiderev: | |
72 return | |
73 for s in siblings: | |
74 yield dict(node=hex(s), rev=rev(s), **args) | |
75 | |
76 def renamelink(self, fl, node): | |
77 r = fl.renamed(node) | |
78 if r: | |
79 return [dict(file=r[0], node=hex(r[1]))] | |
80 return [] | |
81 | |
82 def showtag(self, t1, node=nullid, **args): | |
83 for t in self.repo.nodetags(node): | |
84 yield self.t(t1, tag=t, **args) | |
85 | |
86 def diff(self, node1, node2, files): | |
87 def filterfiles(filters, files): | |
88 l = [x for x in files if x in filters] | |
89 | |
90 for t in filters: | |
91 if t and t[-1] != os.sep: | |
92 t += os.sep | |
93 l += [x for x in files if x.startswith(t)] | |
94 return l | |
95 | |
96 parity = [0] | |
97 def diffblock(diff, f, fn): | |
98 yield self.t("diffblock", | |
99 lines=prettyprintlines(diff), | |
100 parity=parity[0], | |
101 file=f, | |
102 filenode=hex(fn or nullid)) | |
103 parity[0] = 1 - parity[0] | |
104 | |
105 def prettyprintlines(diff): | |
106 for l in diff.splitlines(1): | |
107 if l.startswith('+'): | |
108 yield self.t("difflineplus", line=l) | |
109 elif l.startswith('-'): | |
110 yield self.t("difflineminus", line=l) | |
111 elif l.startswith('@'): | |
112 yield self.t("difflineat", line=l) | |
113 else: | |
114 yield self.t("diffline", line=l) | |
115 | |
116 r = self.repo | |
117 cl = r.changelog | |
118 mf = r.manifest | |
119 change1 = cl.read(node1) | |
120 change2 = cl.read(node2) | |
121 mmap1 = mf.read(change1[0]) | |
122 mmap2 = mf.read(change2[0]) | |
123 date1 = util.datestr(change1[2]) | |
124 date2 = util.datestr(change2[2]) | |
125 | |
126 modified, added, removed, deleted, unknown = r.changes(node1, node2) | |
127 if files: | |
128 modified, added, removed = map(lambda x: filterfiles(files, x), | |
129 (modified, added, removed)) | |
130 | |
131 diffopts = self.repo.ui.diffopts() | |
132 showfunc = diffopts['showfunc'] | |
133 ignorews = diffopts['ignorews'] | |
134 for f in modified: | |
135 to = r.file(f).read(mmap1[f]) | |
136 tn = r.file(f).read(mmap2[f]) | |
137 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, | |
138 showfunc=showfunc, ignorews=ignorews), f, tn) | |
139 for f in added: | |
140 to = None | |
141 tn = r.file(f).read(mmap2[f]) | |
142 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, | |
143 showfunc=showfunc, ignorews=ignorews), f, tn) | |
144 for f in removed: | |
145 to = r.file(f).read(mmap1[f]) | |
146 tn = None | |
147 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, | |
148 showfunc=showfunc, ignorews=ignorews), f, tn) | |
149 | |
150 def changelog(self, pos): | |
151 def changenav(**map): | |
152 def seq(factor, maxchanges=None): | |
153 if maxchanges: | |
154 yield maxchanges | |
155 if maxchanges >= 20 and maxchanges <= 40: | |
156 yield 50 | |
157 else: | |
158 yield 1 * factor | |
159 yield 3 * factor | |
160 for f in seq(factor * 10): | |
161 yield f | |
162 | |
163 l = [] | |
164 last = 0 | |
165 for f in seq(1, self.maxchanges): | |
166 if f < self.maxchanges or f <= last: | |
167 continue | |
168 if f > count: | |
169 break | |
170 last = f | |
171 r = "%d" % f | |
172 if pos + f < count: | |
173 l.append(("+" + r, pos + f)) | |
174 if pos - f >= 0: | |
175 l.insert(0, ("-" + r, pos - f)) | |
176 | |
177 yield {"rev": 0, "label": "(0)"} | |
178 | |
179 for label, rev in l: | |
180 yield {"label": label, "rev": rev} | |
181 | |
182 yield {"label": "tip", "rev": "tip"} | |
183 | |
184 def changelist(**map): | |
185 parity = (start - end) & 1 | |
186 cl = self.repo.changelog | |
187 l = [] # build a list in forward order for efficiency | |
188 for i in range(start, end): | |
189 n = cl.node(i) | |
190 changes = cl.read(n) | |
191 hn = hex(n) | |
192 | |
193 l.insert(0, {"parity": parity, | |
194 "author": changes[1], | |
195 "parent": self.siblings(cl.parents(n), cl.rev, | |
196 cl.rev(n) - 1), | |
197 "child": self.siblings(cl.children(n), cl.rev, | |
198 cl.rev(n) + 1), | |
199 "changelogtag": self.showtag("changelogtag",n), | |
200 "manifest": hex(changes[0]), | |
201 "desc": changes[4], | |
202 "date": changes[2], | |
203 "files": self.listfilediffs(changes[3], n), | |
204 "rev": i, | |
205 "node": hn}) | |
206 parity = 1 - parity | |
207 | |
208 for e in l: | |
209 yield e | |
210 | |
211 cl = self.repo.changelog | |
212 mf = cl.read(cl.tip())[0] | |
213 count = cl.count() | |
214 start = max(0, pos - self.maxchanges + 1) | |
215 end = min(count, start + self.maxchanges) | |
216 pos = end - 1 | |
217 | |
218 yield self.t('changelog', | |
219 changenav=changenav, | |
220 manifest=hex(mf), | |
221 rev=pos, changesets=count, entries=changelist, | |
222 archives=self.archivelist("tip")) | |
223 | |
224 def search(self, query): | |
225 | |
226 def changelist(**map): | |
227 cl = self.repo.changelog | |
228 count = 0 | |
229 qw = query.lower().split() | |
230 | |
231 def revgen(): | |
232 for i in range(cl.count() - 1, 0, -100): | |
233 l = [] | |
234 for j in range(max(0, i - 100), i): | |
235 n = cl.node(j) | |
236 changes = cl.read(n) | |
237 l.append((n, j, changes)) | |
238 l.reverse() | |
239 for e in l: | |
240 yield e | |
241 | |
242 for n, i, changes in revgen(): | |
243 miss = 0 | |
244 for q in qw: | |
245 if not (q in changes[1].lower() or | |
246 q in changes[4].lower() or | |
247 q in " ".join(changes[3][:20]).lower()): | |
248 miss = 1 | |
249 break | |
250 if miss: | |
251 continue | |
252 | |
253 count += 1 | |
254 hn = hex(n) | |
255 | |
256 yield self.t('searchentry', | |
257 parity=count & 1, | |
258 author=changes[1], | |
259 parent=self.siblings(cl.parents(n), cl.rev), | |
260 child=self.siblings(cl.children(n), cl.rev), | |
261 changelogtag=self.showtag("changelogtag",n), | |
262 manifest=hex(changes[0]), | |
263 desc=changes[4], | |
264 date=changes[2], | |
265 files=self.listfilediffs(changes[3], n), | |
266 rev=i, | |
267 node=hn) | |
268 | |
269 if count >= self.maxchanges: | |
270 break | |
271 | |
272 cl = self.repo.changelog | |
273 mf = cl.read(cl.tip())[0] | |
274 | |
275 yield self.t('search', | |
276 query=query, | |
277 manifest=hex(mf), | |
278 entries=changelist) | |
279 | |
280 def changeset(self, nodeid): | |
281 cl = self.repo.changelog | |
282 n = self.repo.lookup(nodeid) | |
283 nodeid = hex(n) | |
284 changes = cl.read(n) | |
285 p1 = cl.parents(n)[0] | |
286 | |
287 files = [] | |
288 mf = self.repo.manifest.read(changes[0]) | |
289 for f in changes[3]: | |
290 files.append(self.t("filenodelink", | |
291 filenode=hex(mf.get(f, nullid)), file=f)) | |
292 | |
293 def diff(**map): | |
294 yield self.diff(p1, n, None) | |
295 | |
296 yield self.t('changeset', | |
297 diff=diff, | |
298 rev=cl.rev(n), | |
299 node=nodeid, | |
300 parent=self.siblings(cl.parents(n), cl.rev), | |
301 child=self.siblings(cl.children(n), cl.rev), | |
302 changesettag=self.showtag("changesettag",n), | |
303 manifest=hex(changes[0]), | |
304 author=changes[1], | |
305 desc=changes[4], | |
306 date=changes[2], | |
307 files=files, | |
308 archives=self.archivelist(nodeid)) | |
309 | |
310 def filelog(self, f, filenode): | |
311 cl = self.repo.changelog | |
312 fl = self.repo.file(f) | |
313 filenode = hex(fl.lookup(filenode)) | |
314 count = fl.count() | |
315 | |
316 def entries(**map): | |
317 l = [] | |
318 parity = (count - 1) & 1 | |
319 | |
320 for i in range(count): | |
321 n = fl.node(i) | |
322 lr = fl.linkrev(n) | |
323 cn = cl.node(lr) | |
324 cs = cl.read(cl.node(lr)) | |
325 | |
326 l.insert(0, {"parity": parity, | |
327 "filenode": hex(n), | |
328 "filerev": i, | |
329 "file": f, | |
330 "node": hex(cn), | |
331 "author": cs[1], | |
332 "date": cs[2], | |
333 "rename": self.renamelink(fl, n), | |
334 "parent": self.siblings(fl.parents(n), | |
335 fl.rev, file=f), | |
336 "child": self.siblings(fl.children(n), | |
337 fl.rev, file=f), | |
338 "desc": cs[4]}) | |
339 parity = 1 - parity | |
340 | |
341 for e in l: | |
342 yield e | |
343 | |
344 yield self.t("filelog", file=f, filenode=filenode, entries=entries) | |
345 | |
346 def filerevision(self, f, node): | |
347 fl = self.repo.file(f) | |
348 n = fl.lookup(node) | |
349 node = hex(n) | |
350 text = fl.read(n) | |
351 changerev = fl.linkrev(n) | |
352 cl = self.repo.changelog | |
353 cn = cl.node(changerev) | |
354 cs = cl.read(cn) | |
355 mfn = cs[0] | |
356 | |
357 mt = mimetypes.guess_type(f)[0] | |
358 rawtext = text | |
359 if util.binary(text): | |
360 mt = mt or 'application/octet-stream' | |
361 text = "(binary:%s)" % mt | |
362 mt = mt or 'text/plain' | |
363 | |
364 def lines(): | |
365 for l, t in enumerate(text.splitlines(1)): | |
366 yield {"line": t, | |
367 "linenumber": "% 6d" % (l + 1), | |
368 "parity": l & 1} | |
369 | |
370 yield self.t("filerevision", | |
371 file=f, | |
372 filenode=node, | |
373 path=_up(f), | |
374 text=lines(), | |
375 raw=rawtext, | |
376 mimetype=mt, | |
377 rev=changerev, | |
378 node=hex(cn), | |
379 manifest=hex(mfn), | |
380 author=cs[1], | |
381 date=cs[2], | |
382 parent=self.siblings(fl.parents(n), fl.rev, file=f), | |
383 child=self.siblings(fl.children(n), fl.rev, file=f), | |
384 rename=self.renamelink(fl, n), | |
385 permissions=self.repo.manifest.readflags(mfn)[f]) | |
386 | |
387 def fileannotate(self, f, node): | |
388 bcache = {} | |
389 ncache = {} | |
390 fl = self.repo.file(f) | |
391 n = fl.lookup(node) | |
392 node = hex(n) | |
393 changerev = fl.linkrev(n) | |
394 | |
395 cl = self.repo.changelog | |
396 cn = cl.node(changerev) | |
397 cs = cl.read(cn) | |
398 mfn = cs[0] | |
399 | |
400 def annotate(**map): | |
401 parity = 1 | |
402 last = None | |
403 for r, l in fl.annotate(n): | |
404 try: | |
405 cnode = ncache[r] | |
406 except KeyError: | |
407 cnode = ncache[r] = self.repo.changelog.node(r) | |
408 | |
409 try: | |
410 name = bcache[r] | |
411 except KeyError: | |
412 cl = self.repo.changelog.read(cnode) | |
413 bcache[r] = name = self.repo.ui.shortuser(cl[1]) | |
414 | |
415 if last != cnode: | |
416 parity = 1 - parity | |
417 last = cnode | |
418 | |
419 yield {"parity": parity, | |
420 "node": hex(cnode), | |
421 "rev": r, | |
422 "author": name, | |
423 "file": f, | |
424 "line": l} | |
425 | |
426 yield self.t("fileannotate", | |
427 file=f, | |
428 filenode=node, | |
429 annotate=annotate, | |
430 path=_up(f), | |
431 rev=changerev, | |
432 node=hex(cn), | |
433 manifest=hex(mfn), | |
434 author=cs[1], | |
435 date=cs[2], | |
436 rename=self.renamelink(fl, n), | |
437 parent=self.siblings(fl.parents(n), fl.rev, file=f), | |
438 child=self.siblings(fl.children(n), fl.rev, file=f), | |
439 permissions=self.repo.manifest.readflags(mfn)[f]) | |
440 | |
441 def manifest(self, mnode, path): | |
442 man = self.repo.manifest | |
443 mn = man.lookup(mnode) | |
444 mnode = hex(mn) | |
445 mf = man.read(mn) | |
446 rev = man.rev(mn) | |
447 changerev = man.linkrev(mn) | |
448 node = self.repo.changelog.node(changerev) | |
449 mff = man.readflags(mn) | |
450 | |
451 files = {} | |
452 | |
453 p = path[1:] | |
454 if p and p[-1] != "/": | |
455 p += "/" | |
456 l = len(p) | |
457 | |
458 for f,n in mf.items(): | |
459 if f[:l] != p: | |
460 continue | |
461 remain = f[l:] | |
462 if "/" in remain: | |
463 short = remain[:remain.find("/") + 1] # bleah | |
464 files[short] = (f, None) | |
465 else: | |
466 short = os.path.basename(remain) | |
467 files[short] = (f, n) | |
468 | |
469 def filelist(**map): | |
470 parity = 0 | |
471 fl = files.keys() | |
472 fl.sort() | |
473 for f in fl: | |
474 full, fnode = files[f] | |
475 if not fnode: | |
476 continue | |
477 | |
478 yield {"file": full, | |
479 "manifest": mnode, | |
480 "filenode": hex(fnode), | |
481 "parity": parity, | |
482 "basename": f, | |
483 "permissions": mff[full]} | |
484 parity = 1 - parity | |
485 | |
486 def dirlist(**map): | |
487 parity = 0 | |
488 fl = files.keys() | |
489 fl.sort() | |
490 for f in fl: | |
491 full, fnode = files[f] | |
492 if fnode: | |
493 continue | |
494 | |
495 yield {"parity": parity, | |
496 "path": os.path.join(path, f), | |
497 "manifest": mnode, | |
498 "basename": f[:-1]} | |
499 parity = 1 - parity | |
500 | |
501 yield self.t("manifest", | |
502 manifest=mnode, | |
503 rev=rev, | |
504 node=hex(node), | |
505 path=path, | |
506 up=_up(path), | |
507 fentries=filelist, | |
508 dentries=dirlist, | |
509 archives=self.archivelist(hex(node))) | |
510 | |
511 def tags(self): | |
512 cl = self.repo.changelog | |
513 mf = cl.read(cl.tip())[0] | |
514 | |
515 i = self.repo.tagslist() | |
516 i.reverse() | |
517 | |
518 def entries(notip=False, **map): | |
519 parity = 0 | |
520 for k,n in i: | |
521 if notip and k == "tip": continue | |
522 yield {"parity": parity, | |
523 "tag": k, | |
524 "tagmanifest": hex(cl.read(n)[0]), | |
525 "date": cl.read(n)[2], | |
526 "node": hex(n)} | |
527 parity = 1 - parity | |
528 | |
529 yield self.t("tags", | |
530 manifest=hex(mf), | |
531 entries=lambda **x: entries(False, **x), | |
532 entriesnotip=lambda **x: entries(True, **x)) | |
533 | |
534 def summary(self): | |
535 cl = self.repo.changelog | |
536 mf = cl.read(cl.tip())[0] | |
537 | |
538 i = self.repo.tagslist() | |
539 i.reverse() | |
540 | |
541 def tagentries(**map): | |
542 parity = 0 | |
543 count = 0 | |
544 for k,n in i: | |
545 if k == "tip": # skip tip | |
546 continue; | |
547 | |
548 count += 1 | |
549 if count > 10: # limit to 10 tags | |
550 break; | |
551 | |
552 c = cl.read(n) | |
553 m = c[0] | |
554 t = c[2] | |
555 | |
556 yield self.t("tagentry", | |
557 parity = parity, | |
558 tag = k, | |
559 node = hex(n), | |
560 date = t, | |
561 tagmanifest = hex(m)) | |
562 parity = 1 - parity | |
563 | |
564 def changelist(**map): | |
565 parity = 0 | |
566 cl = self.repo.changelog | |
567 l = [] # build a list in forward order for efficiency | |
568 for i in range(start, end): | |
569 n = cl.node(i) | |
570 changes = cl.read(n) | |
571 hn = hex(n) | |
572 t = changes[2] | |
573 | |
574 l.insert(0, self.t( | |
575 'shortlogentry', | |
576 parity = parity, | |
577 author = changes[1], | |
578 manifest = hex(changes[0]), | |
579 desc = changes[4], | |
580 date = t, | |
581 rev = i, | |
582 node = hn)) | |
583 parity = 1 - parity | |
584 | |
585 yield l | |
586 | |
587 cl = self.repo.changelog | |
588 mf = cl.read(cl.tip())[0] | |
589 count = cl.count() | |
590 start = max(0, count - self.maxchanges) | |
591 end = min(count, start + self.maxchanges) | |
592 pos = end - 1 | |
593 | |
594 yield self.t("summary", | |
595 desc = self.repo.ui.config("web", "description", "unknown"), | |
596 owner = (self.repo.ui.config("ui", "username") or # preferred | |
597 self.repo.ui.config("web", "contact") or # deprecated | |
598 self.repo.ui.config("web", "author", "unknown")), # also | |
599 lastchange = (0, 0), # FIXME | |
600 manifest = hex(mf), | |
601 tags = tagentries, | |
602 shortlog = changelist) | |
603 | |
604 def filediff(self, file, changeset): | |
605 cl = self.repo.changelog | |
606 n = self.repo.lookup(changeset) | |
607 changeset = hex(n) | |
608 p1 = cl.parents(n)[0] | |
609 cs = cl.read(n) | |
610 mf = self.repo.manifest.read(cs[0]) | |
611 | |
612 def diff(**map): | |
613 yield self.diff(p1, n, [file]) | |
614 | |
615 yield self.t("filediff", | |
616 file=file, | |
617 filenode=hex(mf.get(file, nullid)), | |
618 node=changeset, | |
619 rev=self.repo.changelog.rev(n), | |
620 parent=self.siblings(cl.parents(n), cl.rev), | |
621 child=self.siblings(cl.children(n), cl.rev), | |
622 diff=diff) | |
623 | |
624 archive_specs = { | |
625 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', 'x-bzip2'), | |
626 'gz': ('application/x-tar', 'tgz', '.tar.gz', 'x-gzip'), | |
627 'zip': ('application/zip', 'zip', '.zip', None), | |
628 } | |
629 | |
630 def archive(self, req, cnode, type): | |
631 reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame)) | |
632 name = "%s-%s" % (reponame, short(cnode)) | |
633 mimetype, artype, extension, encoding = self.archive_specs[type] | |
634 headers = [('Content-type', mimetype), | |
635 ('Content-disposition', 'attachment; filename=%s%s' % | |
636 (name, extension))] | |
637 if encoding: | |
638 headers.append(('Content-encoding', encoding)) | |
639 req.header(headers) | |
640 archival.archive(self.repo, req.out, cnode, artype, prefix=name) | |
641 | |
642 # add tags to things | |
643 # tags -> list of changesets corresponding to tags | |
644 # find tag, changeset, file | |
645 | |
646 def run(self, req=hgrequest()): | |
647 def clean(path): | |
648 p = util.normpath(path) | |
649 if p[:2] == "..": | |
650 raise "suspicious path" | |
651 return p | |
652 | |
653 def header(**map): | |
654 yield self.t("header", **map) | |
655 | |
656 def footer(**map): | |
657 yield self.t("footer", | |
658 motd=self.repo.ui.config("web", "motd", ""), | |
659 **map) | |
660 | |
661 def expand_form(form): | |
662 shortcuts = { | |
663 'cl': [('cmd', ['changelog']), ('rev', None)], | |
664 'cs': [('cmd', ['changeset']), ('node', None)], | |
665 'f': [('cmd', ['file']), ('filenode', None)], | |
666 'fl': [('cmd', ['filelog']), ('filenode', None)], | |
667 'fd': [('cmd', ['filediff']), ('node', None)], | |
668 'fa': [('cmd', ['annotate']), ('filenode', None)], | |
669 'mf': [('cmd', ['manifest']), ('manifest', None)], | |
670 'ca': [('cmd', ['archive']), ('node', None)], | |
671 'tags': [('cmd', ['tags'])], | |
672 'tip': [('cmd', ['changeset']), ('node', ['tip'])], | |
673 'static': [('cmd', ['static']), ('file', None)] | |
674 } | |
675 | |
676 for k in shortcuts.iterkeys(): | |
677 if form.has_key(k): | |
678 for name, value in shortcuts[k]: | |
679 if value is None: | |
680 value = form[k] | |
681 form[name] = value | |
682 del form[k] | |
683 | |
684 self.refresh() | |
685 | |
686 expand_form(req.form) | |
687 | |
688 t = self.repo.ui.config("web", "templates", templater.templatepath()) | |
689 static = self.repo.ui.config("web", "static", os.path.join(t,"static")) | |
690 m = os.path.join(t, "map") | |
691 style = self.repo.ui.config("web", "style", "") | |
692 if req.form.has_key('style'): | |
693 style = req.form['style'][0] | |
694 if style: | |
695 b = os.path.basename("map-" + style) | |
696 p = os.path.join(t, b) | |
697 if os.path.isfile(p): | |
698 m = p | |
699 | |
700 port = req.env["SERVER_PORT"] | |
701 port = port != "80" and (":" + port) or "" | |
702 uri = req.env["REQUEST_URI"] | |
703 if "?" in uri: | |
704 uri = uri.split("?")[0] | |
705 url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri) | |
706 if not self.reponame: | |
707 self.reponame = (self.repo.ui.config("web", "name") | |
708 or uri.strip('/') or self.repo.root) | |
709 | |
710 self.t = templater.templater(m, templater.common_filters, | |
711 defaults={"url": url, | |
712 "repo": self.reponame, | |
713 "header": header, | |
714 "footer": footer, | |
715 }) | |
716 | |
717 if not req.form.has_key('cmd'): | |
718 req.form['cmd'] = [self.t.cache['default'],] | |
719 | |
720 cmd = req.form['cmd'][0] | |
721 if cmd == 'changelog': | |
722 hi = self.repo.changelog.count() - 1 | |
723 if req.form.has_key('rev'): | |
724 hi = req.form['rev'][0] | |
725 try: | |
726 hi = self.repo.changelog.rev(self.repo.lookup(hi)) | |
727 except hg.RepoError: | |
728 req.write(self.search(hi)) # XXX redirect to 404 page? | |
729 return | |
730 | |
731 req.write(self.changelog(hi)) | |
732 | |
733 elif cmd == 'changeset': | |
734 req.write(self.changeset(req.form['node'][0])) | |
735 | |
736 elif cmd == 'manifest': | |
737 req.write(self.manifest(req.form['manifest'][0], | |
738 clean(req.form['path'][0]))) | |
739 | |
740 elif cmd == 'tags': | |
741 req.write(self.tags()) | |
742 | |
743 elif cmd == 'summary': | |
744 req.write(self.summary()) | |
745 | |
746 elif cmd == 'filediff': | |
747 req.write(self.filediff(clean(req.form['file'][0]), | |
748 req.form['node'][0])) | |
749 | |
750 elif cmd == 'file': | |
751 req.write(self.filerevision(clean(req.form['file'][0]), | |
752 req.form['filenode'][0])) | |
753 | |
754 elif cmd == 'annotate': | |
755 req.write(self.fileannotate(clean(req.form['file'][0]), | |
756 req.form['filenode'][0])) | |
757 | |
758 elif cmd == 'filelog': | |
759 req.write(self.filelog(clean(req.form['file'][0]), | |
760 req.form['filenode'][0])) | |
761 | |
762 elif cmd == 'heads': | |
763 req.httphdr("application/mercurial-0.1") | |
764 h = self.repo.heads() | |
765 req.write(" ".join(map(hex, h)) + "\n") | |
766 | |
767 elif cmd == 'branches': | |
768 req.httphdr("application/mercurial-0.1") | |
769 nodes = [] | |
770 if req.form.has_key('nodes'): | |
771 nodes = map(bin, req.form['nodes'][0].split(" ")) | |
772 for b in self.repo.branches(nodes): | |
773 req.write(" ".join(map(hex, b)) + "\n") | |
774 | |
775 elif cmd == 'between': | |
776 req.httphdr("application/mercurial-0.1") | |
777 nodes = [] | |
778 if req.form.has_key('pairs'): | |
779 pairs = [map(bin, p.split("-")) | |
780 for p in req.form['pairs'][0].split(" ")] | |
781 for b in self.repo.between(pairs): | |
782 req.write(" ".join(map(hex, b)) + "\n") | |
783 | |
784 elif cmd == 'changegroup': | |
785 req.httphdr("application/mercurial-0.1") | |
786 nodes = [] | |
787 if not self.allowpull: | |
788 return | |
789 | |
790 if req.form.has_key('roots'): | |
791 nodes = map(bin, req.form['roots'][0].split(" ")) | |
792 | |
793 z = zlib.compressobj() | |
794 f = self.repo.changegroup(nodes, 'serve') | |
795 while 1: | |
796 chunk = f.read(4096) | |
797 if not chunk: | |
798 break | |
799 req.write(z.compress(chunk)) | |
800 | |
801 req.write(z.flush()) | |
802 | |
803 elif cmd == 'archive': | |
804 changeset = self.repo.lookup(req.form['node'][0]) | |
805 type = req.form['type'][0] | |
806 if (type in self.archives and | |
807 self.repo.ui.configbool("web", "allow" + type, False)): | |
808 self.archive(req, changeset, type) | |
809 return | |
810 | |
811 req.write(self.t("error")) | |
812 | |
813 elif cmd == 'static': | |
814 fname = req.form['file'][0] | |
815 req.write(staticfile(static, fname) | |
816 or self.t("error", error="%r not found" % fname)) | |
817 | |
818 else: | |
819 req.write(self.t("error")) |