104 def rawfile(web, req, tmpl): |
104 def rawfile(web, req, tmpl): |
105 guessmime = web.configbool('web', 'guessmime') |
105 guessmime = web.configbool('web', 'guessmime') |
106 |
106 |
107 path = webutil.cleanpath(web.repo, req.req.qsparams.get('file', '')) |
107 path = webutil.cleanpath(web.repo, req.req.qsparams.get('file', '')) |
108 if not path: |
108 if not path: |
109 content = manifest(web, req, tmpl) |
109 return manifest(web, req, tmpl) |
110 req.respond(HTTP_OK, web.ctype) |
|
111 return content |
|
112 |
110 |
113 try: |
111 try: |
114 fctx = webutil.filectx(web.repo, req) |
112 fctx = webutil.filectx(web.repo, req) |
115 except error.LookupError as inst: |
113 except error.LookupError as inst: |
116 try: |
114 try: |
117 content = manifest(web, req, tmpl) |
115 return manifest(web, req, tmpl) |
118 req.respond(HTTP_OK, web.ctype) |
|
119 return content |
|
120 except ErrorResponse: |
116 except ErrorResponse: |
121 raise inst |
117 raise inst |
122 |
118 |
123 path = fctx.path() |
119 path = fctx.path() |
124 text = fctx.data() |
120 text = fctx.data() |
131 else: |
127 else: |
132 mt = 'text/plain' |
128 mt = 'text/plain' |
133 if mt.startswith('text/'): |
129 if mt.startswith('text/'): |
134 mt += '; charset="%s"' % encoding.encoding |
130 mt += '; charset="%s"' % encoding.encoding |
135 |
131 |
136 req.respond(HTTP_OK, mt, path, body=text) |
132 web.res.headers['Content-Type'] = mt |
137 return [] |
133 filename = (path.rpartition('/')[-1] |
|
134 .replace('\\', '\\\\').replace('"', '\\"')) |
|
135 web.res.headers['Content-Disposition'] = 'inline; filename="%s"' % filename |
|
136 web.res.setbodybytes(text) |
|
137 return web.res |
138 |
138 |
139 def _filerevision(web, req, tmpl, fctx): |
139 def _filerevision(web, req, tmpl, fctx): |
140 f = fctx.path() |
140 f = fctx.path() |
141 text = fctx.data() |
141 text = fctx.data() |
142 parity = paritygen(web.stripecount) |
142 parity = paritygen(web.stripecount) |
151 yield {"line": t, |
151 yield {"line": t, |
152 "lineid": "l%d" % (lineno + 1), |
152 "lineid": "l%d" % (lineno + 1), |
153 "linenumber": "% 6d" % (lineno + 1), |
153 "linenumber": "% 6d" % (lineno + 1), |
154 "parity": next(parity)} |
154 "parity": next(parity)} |
155 |
155 |
156 return tmpl("filerevision", |
156 web.res.setbodygen(tmpl( |
157 file=f, |
157 'filerevision', |
158 path=webutil.up(f), |
158 file=f, |
159 text=lines(), |
159 path=webutil.up(f), |
160 symrev=webutil.symrevorshortnode(req, fctx), |
160 text=lines(), |
161 rename=webutil.renamelink(fctx), |
161 symrev=webutil.symrevorshortnode(req, fctx), |
162 permissions=fctx.manifest().flags(f), |
162 rename=webutil.renamelink(fctx), |
163 ishead=int(ishead), |
163 permissions=fctx.manifest().flags(f), |
164 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) |
164 ishead=int(ishead), |
|
165 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))) |
|
166 |
|
167 return web.res |
165 |
168 |
166 @webcommand('file') |
169 @webcommand('file') |
167 def file(web, req, tmpl): |
170 def file(web, req, tmpl): |
168 """ |
171 """ |
169 /file/{revision}[/{path}] |
172 /file/{revision}[/{path}] |
333 searchfunc = searchfuncs[mode] |
336 searchfunc = searchfuncs[mode] |
334 |
337 |
335 tip = web.repo['tip'] |
338 tip = web.repo['tip'] |
336 parity = paritygen(web.stripecount) |
339 parity = paritygen(web.stripecount) |
337 |
340 |
338 return tmpl('search', query=query, node=tip.hex(), symrev='tip', |
341 web.res.setbodygen(tmpl( |
339 entries=changelist, archives=web.archivelist("tip"), |
342 'search', |
340 morevars=morevars, lessvars=lessvars, |
343 query=query, |
341 modedesc=searchfunc[1], |
344 node=tip.hex(), |
342 showforcekw=showforcekw, showunforcekw=showunforcekw) |
345 symrev='tip', |
|
346 entries=changelist, |
|
347 archives=web.archivelist('tip'), |
|
348 morevars=morevars, |
|
349 lessvars=lessvars, |
|
350 modedesc=searchfunc[1], |
|
351 showforcekw=showforcekw, |
|
352 showunforcekw=showunforcekw)) |
|
353 |
|
354 return web.res |
343 |
355 |
344 @webcommand('changelog') |
356 @webcommand('changelog') |
345 def changelog(web, req, tmpl, shortlog=False): |
357 def changelog(web, req, tmpl, shortlog=False): |
346 """ |
358 """ |
347 /changelog[/{revision}] |
359 /changelog[/{revision}] |
421 nextentry = entries[-1:] |
433 nextentry = entries[-1:] |
422 entries = entries[:-1] |
434 entries = entries[:-1] |
423 else: |
435 else: |
424 nextentry = [] |
436 nextentry = [] |
425 |
437 |
426 return tmpl('shortlog' if shortlog else 'changelog', changenav=changenav, |
438 web.res.setbodygen(tmpl( |
427 node=ctx.hex(), rev=pos, symrev=symrev, changesets=count, |
439 'shortlog' if shortlog else 'changelog', |
428 entries=entries, |
440 changenav=changenav, |
429 latestentry=latestentry, nextentry=nextentry, |
441 node=ctx.hex(), |
430 archives=web.archivelist("tip"), revcount=revcount, |
442 rev=pos, |
431 morevars=morevars, lessvars=lessvars, query=query) |
443 symrev=symrev, |
|
444 changesets=count, |
|
445 entries=entries, |
|
446 latestentry=latestentry, |
|
447 nextentry=nextentry, |
|
448 archives=web.archivelist('tip'), |
|
449 revcount=revcount, |
|
450 morevars=morevars, |
|
451 lessvars=lessvars, |
|
452 query=query)) |
|
453 |
|
454 return web.res |
432 |
455 |
433 @webcommand('shortlog') |
456 @webcommand('shortlog') |
434 def shortlog(web, req, tmpl): |
457 def shortlog(web, req, tmpl): |
435 """ |
458 """ |
436 /shortlog |
459 /shortlog |
459 The ``changeset`` template is rendered. Contents of the ``changesettag``, |
482 The ``changeset`` template is rendered. Contents of the ``changesettag``, |
460 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many |
483 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many |
461 templates related to diffs may all be used to produce the output. |
484 templates related to diffs may all be used to produce the output. |
462 """ |
485 """ |
463 ctx = webutil.changectx(web.repo, req) |
486 ctx = webutil.changectx(web.repo, req) |
464 |
487 web.res.setbodygen(tmpl('changeset', |
465 return tmpl('changeset', **webutil.changesetentry(web, req, tmpl, ctx)) |
488 **webutil.changesetentry(web, req, tmpl, ctx))) |
|
489 return web.res |
466 |
490 |
467 rev = webcommand('rev')(changeset) |
491 rev = webcommand('rev')(changeset) |
468 |
492 |
469 def decodepath(path): |
493 def decodepath(path): |
470 """Hook for mapping a path in the repository to a path in the |
494 """Hook for mapping a path in the repository to a path in the |
561 yield {"parity": next(parity), |
585 yield {"parity": next(parity), |
562 "path": path, |
586 "path": path, |
563 "emptydirs": "/".join(emptydirs), |
587 "emptydirs": "/".join(emptydirs), |
564 "basename": d} |
588 "basename": d} |
565 |
589 |
566 return tmpl("manifest", |
590 web.res.setbodygen(tmpl( |
567 symrev=symrev, |
591 'manifest', |
568 path=abspath, |
592 symrev=symrev, |
569 up=webutil.up(abspath), |
593 path=abspath, |
570 upparity=next(parity), |
594 up=webutil.up(abspath), |
571 fentries=filelist, |
595 upparity=next(parity), |
572 dentries=dirlist, |
596 fentries=filelist, |
573 archives=web.archivelist(hex(node)), |
597 dentries=dirlist, |
574 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) |
598 archives=web.archivelist(hex(node)), |
|
599 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
|
600 |
|
601 return web.res |
575 |
602 |
576 @webcommand('tags') |
603 @webcommand('tags') |
577 def tags(web, req, tmpl): |
604 def tags(web, req, tmpl): |
578 """ |
605 """ |
579 /tags |
606 /tags |
598 yield {"parity": next(parity), |
625 yield {"parity": next(parity), |
599 "tag": k, |
626 "tag": k, |
600 "date": web.repo[n].date(), |
627 "date": web.repo[n].date(), |
601 "node": hex(n)} |
628 "node": hex(n)} |
602 |
629 |
603 return tmpl("tags", |
630 web.res.setbodygen(tmpl( |
604 node=hex(web.repo.changelog.tip()), |
631 'tags', |
605 entries=lambda **x: entries(False, False, **x), |
632 node=hex(web.repo.changelog.tip()), |
606 entriesnotip=lambda **x: entries(True, False, **x), |
633 entries=lambda **x: entries(False, False, **x), |
607 latestentry=lambda **x: entries(True, True, **x)) |
634 entriesnotip=lambda **x: entries(True, False, **x), |
|
635 latestentry=lambda **x: entries(True, True, **x))) |
|
636 |
|
637 return web.res |
608 |
638 |
609 @webcommand('bookmarks') |
639 @webcommand('bookmarks') |
610 def bookmarks(web, req, tmpl): |
640 def bookmarks(web, req, tmpl): |
611 """ |
641 """ |
612 /bookmarks |
642 /bookmarks |
636 if i: |
666 if i: |
637 latestrev = i[0][1] |
667 latestrev = i[0][1] |
638 else: |
668 else: |
639 latestrev = -1 |
669 latestrev = -1 |
640 |
670 |
641 return tmpl("bookmarks", |
671 web.res.setbodygen(tmpl( |
642 node=hex(web.repo.changelog.tip()), |
672 'bookmarks', |
643 lastchange=[{"date": web.repo[latestrev].date()}], |
673 node=hex(web.repo.changelog.tip()), |
644 entries=lambda **x: entries(latestonly=False, **x), |
674 lastchange=[{'date': web.repo[latestrev].date()}], |
645 latestentry=lambda **x: entries(latestonly=True, **x)) |
675 entries=lambda **x: entries(latestonly=False, **x), |
|
676 latestentry=lambda **x: entries(latestonly=True, **x))) |
|
677 |
|
678 return web.res |
646 |
679 |
647 @webcommand('branches') |
680 @webcommand('branches') |
648 def branches(web, req, tmpl): |
681 def branches(web, req, tmpl): |
649 """ |
682 """ |
650 /branches |
683 /branches |
658 |
691 |
659 The ``branches`` template is rendered. |
692 The ``branches`` template is rendered. |
660 """ |
693 """ |
661 entries = webutil.branchentries(web.repo, web.stripecount) |
694 entries = webutil.branchentries(web.repo, web.stripecount) |
662 latestentry = webutil.branchentries(web.repo, web.stripecount, 1) |
695 latestentry = webutil.branchentries(web.repo, web.stripecount, 1) |
663 return tmpl('branches', node=hex(web.repo.changelog.tip()), |
696 |
664 entries=entries, latestentry=latestentry) |
697 web.res.setbodygen(tmpl( |
|
698 'branches', |
|
699 node=hex(web.repo.changelog.tip()), |
|
700 entries=entries, |
|
701 latestentry=latestentry)) |
|
702 |
|
703 return web.res |
665 |
704 |
666 @webcommand('summary') |
705 @webcommand('summary') |
667 def summary(web, req, tmpl): |
706 def summary(web, req, tmpl): |
668 """ |
707 """ |
669 /summary |
708 /summary |
729 end = min(count, start + web.maxchanges) |
768 end = min(count, start + web.maxchanges) |
730 |
769 |
731 desc = web.config("web", "description") |
770 desc = web.config("web", "description") |
732 if not desc: |
771 if not desc: |
733 desc = 'unknown' |
772 desc = 'unknown' |
734 return tmpl("summary", |
773 |
735 desc=desc, |
774 web.res.setbodygen(tmpl( |
736 owner=get_contact(web.config) or "unknown", |
775 'summary', |
737 lastchange=tip.date(), |
776 desc=desc, |
738 tags=tagentries, |
777 owner=get_contact(web.config) or 'unknown', |
739 bookmarks=bookmarks, |
778 lastchange=tip.date(), |
740 branches=webutil.branchentries(web.repo, web.stripecount, 10), |
779 tags=tagentries, |
741 shortlog=changelist, |
780 bookmarks=bookmarks, |
742 node=tip.hex(), |
781 branches=webutil.branchentries(web.repo, web.stripecount, 10), |
743 symrev='tip', |
782 shortlog=changelist, |
744 archives=web.archivelist("tip"), |
783 node=tip.hex(), |
745 labels=web.configlist('web', 'labels')) |
784 symrev='tip', |
|
785 archives=web.archivelist('tip'), |
|
786 labels=web.configlist('web', 'labels'))) |
|
787 |
|
788 return web.res |
746 |
789 |
747 @webcommand('filediff') |
790 @webcommand('filediff') |
748 def filediff(web, req, tmpl): |
791 def filediff(web, req, tmpl): |
749 """ |
792 """ |
750 /diff/{revision}/{path} |
793 /diff/{revision}/{path} |
780 rename = webutil.renamelink(fctx) |
823 rename = webutil.renamelink(fctx) |
781 ctx = fctx |
824 ctx = fctx |
782 else: |
825 else: |
783 rename = [] |
826 rename = [] |
784 ctx = ctx |
827 ctx = ctx |
785 return tmpl("filediff", |
828 |
786 file=path, |
829 web.res.setbodygen(tmpl( |
787 symrev=webutil.symrevorshortnode(req, ctx), |
830 'filediff', |
788 rename=rename, |
831 file=path, |
789 diff=diffs, |
832 symrev=webutil.symrevorshortnode(req, ctx), |
790 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) |
833 rename=rename, |
|
834 diff=diffs, |
|
835 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
|
836 |
|
837 return web.res |
791 |
838 |
792 diff = webcommand('diff')(filediff) |
839 diff = webcommand('diff')(filediff) |
793 |
840 |
794 @webcommand('comparison') |
841 @webcommand('comparison') |
795 def comparison(web, req, tmpl): |
842 def comparison(web, req, tmpl): |
851 rename = webutil.renamelink(fctx) |
898 rename = webutil.renamelink(fctx) |
852 ctx = fctx |
899 ctx = fctx |
853 else: |
900 else: |
854 rename = [] |
901 rename = [] |
855 ctx = ctx |
902 ctx = ctx |
856 return tmpl('filecomparison', |
903 |
857 file=path, |
904 web.res.setbodygen(tmpl( |
858 symrev=webutil.symrevorshortnode(req, ctx), |
905 'filecomparison', |
859 rename=rename, |
906 file=path, |
860 leftrev=leftrev, |
907 symrev=webutil.symrevorshortnode(req, ctx), |
861 leftnode=hex(leftnode), |
908 rename=rename, |
862 rightrev=rightrev, |
909 leftrev=leftrev, |
863 rightnode=hex(rightnode), |
910 leftnode=hex(leftnode), |
864 comparison=comparison, |
911 rightrev=rightrev, |
865 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx))) |
912 rightnode=hex(rightnode), |
|
913 comparison=comparison, |
|
914 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
|
915 |
|
916 return web.res |
866 |
917 |
867 @webcommand('annotate') |
918 @webcommand('annotate') |
868 def annotate(web, req, tmpl): |
919 def annotate(web, req, tmpl): |
869 """ |
920 """ |
870 /annotate/{revision}/{path} |
921 /annotate/{revision}/{path} |
942 "revdate": f.date()} |
993 "revdate": f.date()} |
943 |
994 |
944 diffopts = webutil.difffeatureopts(req, web.repo.ui, 'annotate') |
995 diffopts = webutil.difffeatureopts(req, web.repo.ui, 'annotate') |
945 diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults} |
996 diffopts = {k: getattr(diffopts, k) for k in diffopts.defaults} |
946 |
997 |
947 return tmpl("fileannotate", |
998 web.res.setbodygen(tmpl( |
948 file=f, |
999 'fileannotate', |
949 annotate=annotate, |
1000 file=f, |
950 path=webutil.up(f), |
1001 annotate=annotate, |
951 symrev=webutil.symrevorshortnode(req, fctx), |
1002 path=webutil.up(f), |
952 rename=webutil.renamelink(fctx), |
1003 symrev=webutil.symrevorshortnode(req, fctx), |
953 permissions=fctx.manifest().flags(f), |
1004 rename=webutil.renamelink(fctx), |
954 ishead=int(ishead), |
1005 permissions=fctx.manifest().flags(f), |
955 diffopts=diffopts, |
1006 ishead=int(ishead), |
956 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx))) |
1007 diffopts=diffopts, |
|
1008 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))) |
|
1009 |
|
1010 return web.res |
957 |
1011 |
958 @webcommand('filelog') |
1012 @webcommand('filelog') |
959 def filelog(web, req, tmpl): |
1013 def filelog(web, req, tmpl): |
960 """ |
1014 """ |
961 /filelog/{revision}/{path} |
1015 /filelog/{revision}/{path} |
1316 |
1370 |
1317 yield entry |
1371 yield entry |
1318 |
1372 |
1319 rows = len(tree) |
1373 rows = len(tree) |
1320 |
1374 |
1321 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount, |
1375 web.res.setbodygen(tmpl( |
1322 uprev=uprev, |
1376 'graph', |
1323 lessvars=lessvars, morevars=morevars, downrev=downrev, |
1377 rev=rev, |
1324 graphvars=graphvars, |
1378 symrev=symrev, |
1325 rows=rows, |
1379 revcount=revcount, |
1326 bg_height=bg_height, |
1380 uprev=uprev, |
1327 changesets=count, |
1381 lessvars=lessvars, |
1328 nextentry=nextentry, |
1382 morevars=morevars, |
1329 jsdata=lambda **x: jsdata(), |
1383 downrev=downrev, |
1330 nodes=lambda **x: nodes(), |
1384 graphvars=graphvars, |
1331 node=ctx.hex(), changenav=changenav) |
1385 rows=rows, |
|
1386 bg_height=bg_height, |
|
1387 changesets=count, |
|
1388 nextentry=nextentry, |
|
1389 jsdata=lambda **x: jsdata(), |
|
1390 nodes=lambda **x: nodes(), |
|
1391 node=ctx.hex(), |
|
1392 changenav=changenav)) |
|
1393 |
|
1394 return web.res |
1332 |
1395 |
1333 def _getdoc(e): |
1396 def _getdoc(e): |
1334 doc = e[0].__doc__ |
1397 doc = e[0].__doc__ |
1335 if doc: |
1398 if doc: |
1336 doc = _(doc).partition('\n')[0] |
1399 doc = _(doc).partition('\n')[0] |
1382 |
1445 |
1383 def othercommands(**map): |
1446 def othercommands(**map): |
1384 for c, doc in other: |
1447 for c, doc in other: |
1385 yield {'topic': c, 'summary': doc} |
1448 yield {'topic': c, 'summary': doc} |
1386 |
1449 |
1387 return tmpl('helptopics', topics=topics, earlycommands=earlycommands, |
1450 web.res.setbodygen(tmpl( |
1388 othercommands=othercommands, title='Index') |
1451 'helptopics', |
|
1452 topics=topics, |
|
1453 earlycommands=earlycommands, |
|
1454 othercommands=othercommands, |
|
1455 title='Index')) |
|
1456 return web.res |
1389 |
1457 |
1390 # Render an index of sub-topics. |
1458 # Render an index of sub-topics. |
1391 if topicname in helpmod.subtopics: |
1459 if topicname in helpmod.subtopics: |
1392 topics = [] |
1460 topics = [] |
1393 for entries, summary, _doc in helpmod.subtopics[topicname]: |
1461 for entries, summary, _doc in helpmod.subtopics[topicname]: |
1395 'topic': '%s.%s' % (topicname, entries[0]), |
1463 'topic': '%s.%s' % (topicname, entries[0]), |
1396 'basename': entries[0], |
1464 'basename': entries[0], |
1397 'summary': summary, |
1465 'summary': summary, |
1398 }) |
1466 }) |
1399 |
1467 |
1400 return tmpl('helptopics', topics=topics, title=topicname, |
1468 web.res.setbodygen(tmpl( |
1401 subindex=True) |
1469 'helptopics', |
|
1470 topics=topics, |
|
1471 title=topicname, |
|
1472 subindex=True)) |
|
1473 return web.res |
1402 |
1474 |
1403 u = webutil.wsgiui.load() |
1475 u = webutil.wsgiui.load() |
1404 u.verbose = True |
1476 u.verbose = True |
1405 |
1477 |
1406 # Render a page from a sub-topic. |
1478 # Render a page from a sub-topic. |
1416 |
1488 |
1417 try: |
1489 try: |
1418 doc = helpmod.help_(u, commands, topic, subtopic=subtopic) |
1490 doc = helpmod.help_(u, commands, topic, subtopic=subtopic) |
1419 except error.Abort: |
1491 except error.Abort: |
1420 raise ErrorResponse(HTTP_NOT_FOUND) |
1492 raise ErrorResponse(HTTP_NOT_FOUND) |
1421 return tmpl('help', topic=topicname, doc=doc) |
1493 |
|
1494 web.res.setbodygen(tmpl( |
|
1495 'help', |
|
1496 topic=topicname, |
|
1497 doc=doc)) |
|
1498 |
|
1499 return web.res |
1422 |
1500 |
1423 # tell hggettext to extract docstrings from these functions: |
1501 # tell hggettext to extract docstrings from these functions: |
1424 i18nfunctions = commands.values() |
1502 i18nfunctions = commands.values() |