mercurial/hgweb/webcommands.py
changeset 36871 9fc3d814646e
parent 36870 1f42d621f090
child 36872 89002d07a114
equal deleted inserted replaced
36870:1f42d621f090 36871: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()