mercurial/hgweb/webcommands.py
changeset 36880 67fb0dca29bc
parent 36876 97f44b0720e2
child 36882 66f62d120ba2
equal deleted inserted replaced
36879:9675147aec06 36880:67fb0dca29bc
    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}]
   453         revcount=revcount,
   450         revcount=revcount,
   454         morevars=morevars,
   451         morevars=morevars,
   455         lessvars=lessvars,
   452         lessvars=lessvars,
   456         query=query))
   453         query=query))
   457 
   454 
   458     return web.res
   455     return web.res.sendresponse()
   459 
   456 
   460 @webcommand('shortlog')
   457 @webcommand('shortlog')
   461 def shortlog(web, req, tmpl):
   458 def shortlog(web, req, tmpl):
   462     """
   459     """
   463     /shortlog
   460     /shortlog
   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]:
  1478         web.res.setbodygen(tmpl(
  1475         web.res.setbodygen(tmpl(
  1479             'helptopics',
  1476             'helptopics',
  1480             topics=topics,
  1477             topics=topics,
  1481             title=topicname,
  1478             title=topicname,
  1482             subindex=True))
  1479             subindex=True))
  1483         return web.res
  1480         return web.res.sendresponse()
  1484 
  1481 
  1485     u = webutil.wsgiui.load()
  1482     u = webutil.wsgiui.load()
  1486     u.verbose = True
  1483     u.verbose = True
  1487 
  1484 
  1488     # Render a page from a sub-topic.
  1485     # Render a page from a sub-topic.
  1504     web.res.setbodygen(tmpl(
  1501     web.res.setbodygen(tmpl(
  1505         'help',
  1502         'help',
  1506         topic=topicname,
  1503         topic=topicname,
  1507         doc=doc))
  1504         doc=doc))
  1508 
  1505 
  1509     return web.res
  1506     return web.res.sendresponse()
  1510 
  1507 
  1511 # tell hggettext to extract docstrings from these functions:
  1508 # tell hggettext to extract docstrings from these functions:
  1512 i18nfunctions = commands.values()
  1509 i18nfunctions = commands.values()