55 When called, functions receive as arguments a ``requestcontext``, |
55 When called, functions receive as arguments a ``requestcontext``, |
56 ``wsgirequest``, and a templater instance for generatoring output. |
56 ``wsgirequest``, and a templater instance for generatoring output. |
57 The functions should populate the ``rctx.res`` object with details |
57 The functions should populate the ``rctx.res`` object with details |
58 about the HTTP response. |
58 about the HTTP response. |
59 |
59 |
60 The function can return the ``requestcontext.res`` instance to signal |
60 The function returns a generator to be consumed by the WSGI application. |
61 that it wants to use this object to generate the response. If an iterable |
61 For most commands, this should be the result from |
62 is returned, the ``wsgirequest`` instance will be used and the returned |
62 ``web.res.sendresponse()``. |
63 content will constitute the response body. ``True`` can be returned to |
|
64 indicate that the function already sent output and the caller doesn't |
|
65 need to do anything more to send the response. |
|
66 |
63 |
67 Usage: |
64 Usage: |
68 |
65 |
69 @webcommand('mycommand') |
66 @webcommand('mycommand') |
70 def mycommand(web, req, tmpl): |
67 def mycommand(web, req, tmpl): |
133 web.res.headers['Content-Type'] = mt |
130 web.res.headers['Content-Type'] = mt |
134 filename = (path.rpartition('/')[-1] |
131 filename = (path.rpartition('/')[-1] |
135 .replace('\\', '\\\\').replace('"', '\\"')) |
132 .replace('\\', '\\\\').replace('"', '\\"')) |
136 web.res.headers['Content-Disposition'] = 'inline; filename="%s"' % filename |
133 web.res.headers['Content-Disposition'] = 'inline; filename="%s"' % filename |
137 web.res.setbodybytes(text) |
134 web.res.setbodybytes(text) |
138 return web.res |
135 return web.res.sendresponse() |
139 |
136 |
140 def _filerevision(web, req, tmpl, fctx): |
137 def _filerevision(web, req, tmpl, fctx): |
141 f = fctx.path() |
138 f = fctx.path() |
142 text = fctx.data() |
139 text = fctx.data() |
143 parity = paritygen(web.stripecount) |
140 parity = paritygen(web.stripecount) |
163 rename=webutil.renamelink(fctx), |
160 rename=webutil.renamelink(fctx), |
164 permissions=fctx.manifest().flags(f), |
161 permissions=fctx.manifest().flags(f), |
165 ishead=int(ishead), |
162 ishead=int(ishead), |
166 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))) |
163 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))) |
167 |
164 |
168 return web.res |
165 return web.res.sendresponse() |
169 |
166 |
170 @webcommand('file') |
167 @webcommand('file') |
171 def file(web, req, tmpl): |
168 def file(web, req, tmpl): |
172 """ |
169 """ |
173 /file/{revision}[/{path}] |
170 /file/{revision}[/{path}] |
353 lessvars=lessvars, |
350 lessvars=lessvars, |
354 modedesc=searchfunc[1], |
351 modedesc=searchfunc[1], |
355 showforcekw=showforcekw, |
352 showforcekw=showforcekw, |
356 showunforcekw=showunforcekw)) |
353 showunforcekw=showunforcekw)) |
357 |
354 |
358 return web.res |
355 return web.res.sendresponse() |
359 |
356 |
360 @webcommand('changelog') |
357 @webcommand('changelog') |
361 def changelog(web, req, tmpl, shortlog=False): |
358 def changelog(web, req, tmpl, shortlog=False): |
362 """ |
359 """ |
363 /changelog[/{revision}] |
360 /changelog[/{revision}] |
488 templates related to diffs may all be used to produce the output. |
485 templates related to diffs may all be used to produce the output. |
489 """ |
486 """ |
490 ctx = webutil.changectx(web.repo, req) |
487 ctx = webutil.changectx(web.repo, req) |
491 web.res.setbodygen(tmpl('changeset', |
488 web.res.setbodygen(tmpl('changeset', |
492 **webutil.changesetentry(web, req, tmpl, ctx))) |
489 **webutil.changesetentry(web, req, tmpl, ctx))) |
493 return web.res |
490 return web.res.sendresponse() |
494 |
491 |
495 rev = webcommand('rev')(changeset) |
492 rev = webcommand('rev')(changeset) |
496 |
493 |
497 def decodepath(path): |
494 def decodepath(path): |
498 """Hook for mapping a path in the repository to a path in the |
495 """Hook for mapping a path in the repository to a path in the |
600 fentries=filelist, |
597 fentries=filelist, |
601 dentries=dirlist, |
598 dentries=dirlist, |
602 archives=web.archivelist(hex(node)), |
599 archives=web.archivelist(hex(node)), |
603 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
600 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
604 |
601 |
605 return web.res |
602 return web.res.sendresponse() |
606 |
603 |
607 @webcommand('tags') |
604 @webcommand('tags') |
608 def tags(web, req, tmpl): |
605 def tags(web, req, tmpl): |
609 """ |
606 """ |
610 /tags |
607 /tags |
636 node=hex(web.repo.changelog.tip()), |
633 node=hex(web.repo.changelog.tip()), |
637 entries=lambda **x: entries(False, False, **x), |
634 entries=lambda **x: entries(False, False, **x), |
638 entriesnotip=lambda **x: entries(True, False, **x), |
635 entriesnotip=lambda **x: entries(True, False, **x), |
639 latestentry=lambda **x: entries(True, True, **x))) |
636 latestentry=lambda **x: entries(True, True, **x))) |
640 |
637 |
641 return web.res |
638 return web.res.sendresponse() |
642 |
639 |
643 @webcommand('bookmarks') |
640 @webcommand('bookmarks') |
644 def bookmarks(web, req, tmpl): |
641 def bookmarks(web, req, tmpl): |
645 """ |
642 """ |
646 /bookmarks |
643 /bookmarks |
677 node=hex(web.repo.changelog.tip()), |
674 node=hex(web.repo.changelog.tip()), |
678 lastchange=[{'date': web.repo[latestrev].date()}], |
675 lastchange=[{'date': web.repo[latestrev].date()}], |
679 entries=lambda **x: entries(latestonly=False, **x), |
676 entries=lambda **x: entries(latestonly=False, **x), |
680 latestentry=lambda **x: entries(latestonly=True, **x))) |
677 latestentry=lambda **x: entries(latestonly=True, **x))) |
681 |
678 |
682 return web.res |
679 return web.res.sendresponse() |
683 |
680 |
684 @webcommand('branches') |
681 @webcommand('branches') |
685 def branches(web, req, tmpl): |
682 def branches(web, req, tmpl): |
686 """ |
683 """ |
687 /branches |
684 /branches |
702 'branches', |
699 'branches', |
703 node=hex(web.repo.changelog.tip()), |
700 node=hex(web.repo.changelog.tip()), |
704 entries=entries, |
701 entries=entries, |
705 latestentry=latestentry)) |
702 latestentry=latestentry)) |
706 |
703 |
707 return web.res |
704 return web.res.sendresponse() |
708 |
705 |
709 @webcommand('summary') |
706 @webcommand('summary') |
710 def summary(web, req, tmpl): |
707 def summary(web, req, tmpl): |
711 """ |
708 """ |
712 /summary |
709 /summary |
787 node=tip.hex(), |
784 node=tip.hex(), |
788 symrev='tip', |
785 symrev='tip', |
789 archives=web.archivelist('tip'), |
786 archives=web.archivelist('tip'), |
790 labels=web.configlist('web', 'labels'))) |
787 labels=web.configlist('web', 'labels'))) |
791 |
788 |
792 return web.res |
789 return web.res.sendresponse() |
793 |
790 |
794 @webcommand('filediff') |
791 @webcommand('filediff') |
795 def filediff(web, req, tmpl): |
792 def filediff(web, req, tmpl): |
796 """ |
793 """ |
797 /diff/{revision}/{path} |
794 /diff/{revision}/{path} |
836 symrev=webutil.symrevorshortnode(req, ctx), |
833 symrev=webutil.symrevorshortnode(req, ctx), |
837 rename=rename, |
834 rename=rename, |
838 diff=diffs, |
835 diff=diffs, |
839 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
836 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
840 |
837 |
841 return web.res |
838 return web.res.sendresponse() |
842 |
839 |
843 diff = webcommand('diff')(filediff) |
840 diff = webcommand('diff')(filediff) |
844 |
841 |
845 @webcommand('comparison') |
842 @webcommand('comparison') |
846 def comparison(web, req, tmpl): |
843 def comparison(web, req, tmpl): |
915 rightrev=rightrev, |
912 rightrev=rightrev, |
916 rightnode=hex(rightnode), |
913 rightnode=hex(rightnode), |
917 comparison=comparison, |
914 comparison=comparison, |
918 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
915 **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))) |
919 |
916 |
920 return web.res |
917 return web.res.sendresponse() |
921 |
918 |
922 @webcommand('annotate') |
919 @webcommand('annotate') |
923 def annotate(web, req, tmpl): |
920 def annotate(web, req, tmpl): |
924 """ |
921 """ |
925 /annotate/{revision}/{path} |
922 /annotate/{revision}/{path} |
1009 permissions=fctx.manifest().flags(f), |
1006 permissions=fctx.manifest().flags(f), |
1010 ishead=int(ishead), |
1007 ishead=int(ishead), |
1011 diffopts=diffopts, |
1008 diffopts=diffopts, |
1012 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))) |
1009 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))) |
1013 |
1010 |
1014 return web.res |
1011 return web.res.sendresponse() |
1015 |
1012 |
1016 @webcommand('filelog') |
1013 @webcommand('filelog') |
1017 def filelog(web, req, tmpl): |
1014 def filelog(web, req, tmpl): |
1018 """ |
1015 """ |
1019 /filelog/{revision}/{path} |
1016 /filelog/{revision}/{path} |
1149 revcount=revcount, |
1146 revcount=revcount, |
1150 morevars=morevars, |
1147 morevars=morevars, |
1151 lessvars=lessvars, |
1148 lessvars=lessvars, |
1152 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))) |
1149 **pycompat.strkwargs(webutil.commonentry(web.repo, fctx)))) |
1153 |
1150 |
1154 return web.res |
1151 return web.res.sendresponse() |
1155 |
1152 |
1156 @webcommand('archive') |
1153 @webcommand('archive') |
1157 def archive(web, req, tmpl): |
1154 def archive(web, req, tmpl): |
1158 """ |
1155 """ |
1159 /archive/{revision}.{format}[/{path}] |
1156 /archive/{revision}.{format}[/{path}] |
1223 |
1220 |
1224 archival.archive(web.repo, bodyfh, cnode, artype, prefix=name, |
1221 archival.archive(web.repo, bodyfh, cnode, artype, prefix=name, |
1225 matchfn=match, |
1222 matchfn=match, |
1226 subrepos=web.configbool("web", "archivesubrepos")) |
1223 subrepos=web.configbool("web", "archivesubrepos")) |
1227 |
1224 |
1228 return True |
1225 return [] |
1229 |
1226 |
1230 @webcommand('static') |
1227 @webcommand('static') |
1231 def static(web, req, tmpl): |
1228 def static(web, req, tmpl): |
1232 fname = req.req.qsparams['file'] |
1229 fname = req.req.qsparams['file'] |
1233 # a repo owner may set web.static in .hg/hgrc to get any file |
1230 # a repo owner may set web.static in .hg/hgrc to get any file |
1238 if isinstance(tp, str): |
1235 if isinstance(tp, str): |
1239 tp = [tp] |
1236 tp = [tp] |
1240 static = [os.path.join(p, 'static') for p in tp] |
1237 static = [os.path.join(p, 'static') for p in tp] |
1241 |
1238 |
1242 staticfile(static, fname, web.res) |
1239 staticfile(static, fname, web.res) |
1243 return web.res |
1240 return web.res.sendresponse() |
1244 |
1241 |
1245 @webcommand('graph') |
1242 @webcommand('graph') |
1246 def graph(web, req, tmpl): |
1243 def graph(web, req, tmpl): |
1247 """ |
1244 """ |
1248 /graph[/{revision}] |
1245 /graph[/{revision}] |
1399 jsdata=lambda **x: jsdata(), |
1396 jsdata=lambda **x: jsdata(), |
1400 nodes=lambda **x: nodes(), |
1397 nodes=lambda **x: nodes(), |
1401 node=ctx.hex(), |
1398 node=ctx.hex(), |
1402 changenav=changenav)) |
1399 changenav=changenav)) |
1403 |
1400 |
1404 return web.res |
1401 return web.res.sendresponse() |
1405 |
1402 |
1406 def _getdoc(e): |
1403 def _getdoc(e): |
1407 doc = e[0].__doc__ |
1404 doc = e[0].__doc__ |
1408 if doc: |
1405 if doc: |
1409 doc = _(doc).partition('\n')[0] |
1406 doc = _(doc).partition('\n')[0] |
1461 'helptopics', |
1458 'helptopics', |
1462 topics=topics, |
1459 topics=topics, |
1463 earlycommands=earlycommands, |
1460 earlycommands=earlycommands, |
1464 othercommands=othercommands, |
1461 othercommands=othercommands, |
1465 title='Index')) |
1462 title='Index')) |
1466 return web.res |
1463 return web.res.sendresponse() |
1467 |
1464 |
1468 # Render an index of sub-topics. |
1465 # Render an index of sub-topics. |
1469 if topicname in helpmod.subtopics: |
1466 if topicname in helpmod.subtopics: |
1470 topics = [] |
1467 topics = [] |
1471 for entries, summary, _doc in helpmod.subtopics[topicname]: |
1468 for entries, summary, _doc in helpmod.subtopics[topicname]: |