Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/hgweb/webcommands.py @ 36877:9fc3d814646e
hgweb: port most @webcommand to use modern response type
This only focused on porting the return value.
raw file requests are wonky because they go through a separate code
path at the dispatch layer. Now that everyone is using the same
API, we could clean this up.
It's worth noting that wsgirequest.respond() allows sending the
Content-Disposition header, but the only user of that feature was
removed as part of this change (with the setting of the header
now being performed inline).
A few @webcommand are not as straightforward as the others and
they have not been ported yet.
Differential Revision: https://phab.mercurial-scm.org/D2787
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sat, 10 Mar 2018 20:36:34 -0800 |
parents | 1f42d621f090 |
children | 89002d07a114 |
comparison
equal
deleted
inserted
replaced
36876:1f42d621f090 | 36877:9fc3d814646e |
---|---|
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() |