mercurial/hgweb/webcommands.py
changeset 36882 66f62d120ba2
parent 36880 67fb0dca29bc
child 36883 061635d4221c
equal deleted inserted replaced
36881:96a93625a824 36882:66f62d120ba2
    91 
    91 
    92     For URLs of the form ``/log/{revision}/{file}``, the history for a specific
    92     For URLs of the form ``/log/{revision}/{file}``, the history for a specific
    93     file will be shown. This form is equivalent to the ``filelog`` handler.
    93     file will be shown. This form is equivalent to the ``filelog`` handler.
    94     """
    94     """
    95 
    95 
    96     if req.req.qsparams.get('file'):
    96     if web.req.qsparams.get('file'):
    97         return filelog(web, req, tmpl)
    97         return filelog(web, req, tmpl)
    98     else:
    98     else:
    99         return changelog(web, req, tmpl)
    99         return changelog(web, req, tmpl)
   100 
   100 
   101 @webcommand('rawfile')
   101 @webcommand('rawfile')
   102 def rawfile(web, req, tmpl):
   102 def rawfile(web, req, tmpl):
   103     guessmime = web.configbool('web', 'guessmime')
   103     guessmime = web.configbool('web', 'guessmime')
   104 
   104 
   105     path = webutil.cleanpath(web.repo, req.req.qsparams.get('file', ''))
   105     path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
   106     if not path:
   106     if not path:
   107         return manifest(web, req, tmpl)
   107         return manifest(web, req, tmpl)
   108 
   108 
   109     try:
   109     try:
   110         fctx = webutil.filectx(web.repo, req)
   110         fctx = webutil.filectx(web.repo, req)
   185     be rendered.
   185     be rendered.
   186     """
   186     """
   187     if web.req.qsparams.get('style') == 'raw':
   187     if web.req.qsparams.get('style') == 'raw':
   188         return rawfile(web, req, tmpl)
   188         return rawfile(web, req, tmpl)
   189 
   189 
   190     path = webutil.cleanpath(web.repo, req.req.qsparams.get('file', ''))
   190     path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
   191     if not path:
   191     if not path:
   192         return manifest(web, req, tmpl)
   192         return manifest(web, req, tmpl)
   193     try:
   193     try:
   194         return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
   194         return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
   195     except error.LookupError as inst:
   195     except error.LookupError as inst:
   196         try:
   196         try:
   197             return manifest(web, req, tmpl)
   197             return manifest(web, req, tmpl)
   198         except ErrorResponse:
   198         except ErrorResponse:
   199             raise inst
   199             raise inst
   200 
   200 
   201 def _search(web, req, tmpl):
   201 def _search(web, tmpl):
   202     MODE_REVISION = 'rev'
   202     MODE_REVISION = 'rev'
   203     MODE_KEYWORD = 'keyword'
   203     MODE_KEYWORD = 'keyword'
   204     MODE_REVSET = 'revset'
   204     MODE_REVSET = 'revset'
   205 
   205 
   206     def revsearch(ctx):
   206     def revsearch(ctx):
   301                        **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))
   301                        **pycompat.strkwargs(webutil.commonentry(web.repo, ctx)))
   302 
   302 
   303             if count >= revcount:
   303             if count >= revcount:
   304                 break
   304                 break
   305 
   305 
   306     query = req.req.qsparams['rev']
   306     query = web.req.qsparams['rev']
   307     revcount = web.maxchanges
   307     revcount = web.maxchanges
   308     if 'revcount' in req.req.qsparams:
   308     if 'revcount' in web.req.qsparams:
   309         try:
   309         try:
   310             revcount = int(req.req.qsparams.get('revcount', revcount))
   310             revcount = int(web.req.qsparams.get('revcount', revcount))
   311             revcount = max(revcount, 1)
   311             revcount = max(revcount, 1)
   312             tmpl.defaults['sessionvars']['revcount'] = revcount
   312             tmpl.defaults['sessionvars']['revcount'] = revcount
   313         except ValueError:
   313         except ValueError:
   314             pass
   314             pass
   315 
   315 
   320     morevars['revcount'] = revcount * 2
   320     morevars['revcount'] = revcount * 2
   321     morevars['rev'] = query
   321     morevars['rev'] = query
   322 
   322 
   323     mode, funcarg = getsearchmode(query)
   323     mode, funcarg = getsearchmode(query)
   324 
   324 
   325     if 'forcekw' in req.req.qsparams:
   325     if 'forcekw' in web.req.qsparams:
   326         showforcekw = ''
   326         showforcekw = ''
   327         showunforcekw = searchfuncs[mode][1]
   327         showunforcekw = searchfuncs[mode][1]
   328         mode = MODE_KEYWORD
   328         mode = MODE_KEYWORD
   329         funcarg = query
   329         funcarg = query
   330     else:
   330     else:
   379 
   379 
   380     For non-searches, the ``changelog`` template will be rendered.
   380     For non-searches, the ``changelog`` template will be rendered.
   381     """
   381     """
   382 
   382 
   383     query = ''
   383     query = ''
   384     if 'node' in req.req.qsparams:
   384     if 'node' in web.req.qsparams:
   385         ctx = webutil.changectx(web.repo, req)
   385         ctx = webutil.changectx(web.repo, req)
   386         symrev = webutil.symrevorshortnode(req, ctx)
   386         symrev = webutil.symrevorshortnode(req, ctx)
   387     elif 'rev' in req.req.qsparams:
   387     elif 'rev' in web.req.qsparams:
   388         return _search(web, req, tmpl)
   388         return _search(web, tmpl)
   389     else:
   389     else:
   390         ctx = web.repo['tip']
   390         ctx = web.repo['tip']
   391         symrev = 'tip'
   391         symrev = 'tip'
   392 
   392 
   393     def changelist():
   393     def changelist():
   407     if shortlog:
   407     if shortlog:
   408         revcount = web.maxshortchanges
   408         revcount = web.maxshortchanges
   409     else:
   409     else:
   410         revcount = web.maxchanges
   410         revcount = web.maxchanges
   411 
   411 
   412     if 'revcount' in req.req.qsparams:
   412     if 'revcount' in web.req.qsparams:
   413         try:
   413         try:
   414             revcount = int(req.req.qsparams.get('revcount', revcount))
   414             revcount = int(web.req.qsparams.get('revcount', revcount))
   415             revcount = max(revcount, 1)
   415             revcount = max(revcount, 1)
   416             tmpl.defaults['sessionvars']['revcount'] = revcount
   416             tmpl.defaults['sessionvars']['revcount'] = revcount
   417         except ValueError:
   417         except ValueError:
   418             pass
   418             pass
   419 
   419 
   514     is recommended to use the ``file`` handler instead, as it can handle both
   514     is recommended to use the ``file`` handler instead, as it can handle both
   515     directories and files.
   515     directories and files.
   516 
   516 
   517     The ``manifest`` template will be rendered for this handler.
   517     The ``manifest`` template will be rendered for this handler.
   518     """
   518     """
   519     if 'node' in req.req.qsparams:
   519     if 'node' in web.req.qsparams:
   520         ctx = webutil.changectx(web.repo, req)
   520         ctx = webutil.changectx(web.repo, req)
   521         symrev = webutil.symrevorshortnode(req, ctx)
   521         symrev = webutil.symrevorshortnode(req, ctx)
   522     else:
   522     else:
   523         ctx = web.repo['tip']
   523         ctx = web.repo['tip']
   524         symrev = 'tip'
   524         symrev = 'tip'
   525     path = webutil.cleanpath(web.repo, req.req.qsparams.get('file', ''))
   525     path = webutil.cleanpath(web.repo, web.req.qsparams.get('file', ''))
   526     mf = ctx.manifest()
   526     mf = ctx.manifest()
   527     node = ctx.node()
   527     node = ctx.node()
   528 
   528 
   529     files = {}
   529     files = {}
   530     dirs = {}
   530     dirs = {}
   804     fctx, ctx = None, None
   804     fctx, ctx = None, None
   805     try:
   805     try:
   806         fctx = webutil.filectx(web.repo, req)
   806         fctx = webutil.filectx(web.repo, req)
   807     except LookupError:
   807     except LookupError:
   808         ctx = webutil.changectx(web.repo, req)
   808         ctx = webutil.changectx(web.repo, req)
   809         path = webutil.cleanpath(web.repo, req.req.qsparams['file'])
   809         path = webutil.cleanpath(web.repo, web.req.qsparams['file'])
   810         if path not in ctx.files():
   810         if path not in ctx.files():
   811             raise
   811             raise
   812 
   812 
   813     if fctx is not None:
   813     if fctx is not None:
   814         path = fctx.path()
   814         path = fctx.path()
   815         ctx = fctx.changectx()
   815         ctx = fctx.changectx()
   816     basectx = ctx.p1()
   816     basectx = ctx.p1()
   817 
   817 
   818     style = web.config('web', 'style')
   818     style = web.config('web', 'style')
   819     if 'style' in req.req.qsparams:
   819     if 'style' in web.req.qsparams:
   820         style = req.req.qsparams['style']
   820         style = web.req.qsparams['style']
   821 
   821 
   822     diffs = webutil.diffs(web, tmpl, ctx, basectx, [path], style)
   822     diffs = webutil.diffs(web, tmpl, ctx, basectx, [path], style)
   823     if fctx is not None:
   823     if fctx is not None:
   824         rename = webutil.renamelink(fctx)
   824         rename = webutil.renamelink(fctx)
   825         ctx = fctx
   825         ctx = fctx
   855     context in the diff.
   855     context in the diff.
   856 
   856 
   857     The ``filecomparison`` template is rendered.
   857     The ``filecomparison`` template is rendered.
   858     """
   858     """
   859     ctx = webutil.changectx(web.repo, req)
   859     ctx = webutil.changectx(web.repo, req)
   860     if 'file' not in req.req.qsparams:
   860     if 'file' not in web.req.qsparams:
   861         raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
   861         raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
   862     path = webutil.cleanpath(web.repo, req.req.qsparams['file'])
   862     path = webutil.cleanpath(web.repo, web.req.qsparams['file'])
   863 
   863 
   864     parsecontext = lambda v: v == 'full' and -1 or int(v)
   864     parsecontext = lambda v: v == 'full' and -1 or int(v)
   865     if 'context' in req.req.qsparams:
   865     if 'context' in web.req.qsparams:
   866         context = parsecontext(req.req.qsparams['context'])
   866         context = parsecontext(web.req.qsparams['context'])
   867     else:
   867     else:
   868         context = parsecontext(web.config('web', 'comparisoncontext', '5'))
   868         context = parsecontext(web.config('web', 'comparisoncontext', '5'))
   869 
   869 
   870     def filelines(f):
   870     def filelines(f):
   871         if f.isbinary():
   871         if f.isbinary():
  1027     try:
  1027     try:
  1028         fctx = webutil.filectx(web.repo, req)
  1028         fctx = webutil.filectx(web.repo, req)
  1029         f = fctx.path()
  1029         f = fctx.path()
  1030         fl = fctx.filelog()
  1030         fl = fctx.filelog()
  1031     except error.LookupError:
  1031     except error.LookupError:
  1032         f = webutil.cleanpath(web.repo, req.req.qsparams['file'])
  1032         f = webutil.cleanpath(web.repo, web.req.qsparams['file'])
  1033         fl = web.repo.file(f)
  1033         fl = web.repo.file(f)
  1034         numrevs = len(fl)
  1034         numrevs = len(fl)
  1035         if not numrevs: # file doesn't exist at all
  1035         if not numrevs: # file doesn't exist at all
  1036             raise
  1036             raise
  1037         rev = webutil.changectx(web.repo, req).rev()
  1037         rev = webutil.changectx(web.repo, req).rev()
  1042         while fl.linkrev(frev) > rev:
  1042         while fl.linkrev(frev) > rev:
  1043             frev -= 1
  1043             frev -= 1
  1044         fctx = web.repo.filectx(f, fl.linkrev(frev))
  1044         fctx = web.repo.filectx(f, fl.linkrev(frev))
  1045 
  1045 
  1046     revcount = web.maxshortchanges
  1046     revcount = web.maxshortchanges
  1047     if 'revcount' in req.req.qsparams:
  1047     if 'revcount' in web.req.qsparams:
  1048         try:
  1048         try:
  1049             revcount = int(req.req.qsparams.get('revcount', revcount))
  1049             revcount = int(web.req.qsparams.get('revcount', revcount))
  1050             revcount = max(revcount, 1)
  1050             revcount = max(revcount, 1)
  1051             tmpl.defaults['sessionvars']['revcount'] = revcount
  1051             tmpl.defaults['sessionvars']['revcount'] = revcount
  1052         except ValueError:
  1052         except ValueError:
  1053             pass
  1053             pass
  1054 
  1054 
  1057     lessvars = copy.copy(tmpl.defaults['sessionvars'])
  1057     lessvars = copy.copy(tmpl.defaults['sessionvars'])
  1058     lessvars['revcount'] = max(revcount // 2, 1)
  1058     lessvars['revcount'] = max(revcount // 2, 1)
  1059     morevars = copy.copy(tmpl.defaults['sessionvars'])
  1059     morevars = copy.copy(tmpl.defaults['sessionvars'])
  1060     morevars['revcount'] = revcount * 2
  1060     morevars['revcount'] = revcount * 2
  1061 
  1061 
  1062     patch = 'patch' in req.req.qsparams
  1062     patch = 'patch' in web.req.qsparams
  1063     if patch:
  1063     if patch:
  1064         lessvars['patch'] = morevars['patch'] = req.req.qsparams['patch']
  1064         lessvars['patch'] = morevars['patch'] = web.req.qsparams['patch']
  1065     descend = 'descend' in req.req.qsparams
  1065     descend = 'descend' in web.req.qsparams
  1066     if descend:
  1066     if descend:
  1067         lessvars['descend'] = morevars['descend'] = req.req.qsparams['descend']
  1067         lessvars['descend'] = morevars['descend'] = web.req.qsparams['descend']
  1068 
  1068 
  1069     count = fctx.filerev() + 1
  1069     count = fctx.filerev() + 1
  1070     start = max(0, count - revcount) # first rev on this page
  1070     start = max(0, count - revcount) # first rev on this page
  1071     end = min(count, start + revcount) # last rev on this page
  1071     end = min(count, start + revcount) # last rev on this page
  1072     parity = paritygen(web.stripecount, offset=start - end)
  1072     parity = paritygen(web.stripecount, offset=start - end)
  1074     repo = web.repo
  1074     repo = web.repo
  1075     revs = fctx.filelog().revs(start, end - 1)
  1075     revs = fctx.filelog().revs(start, end - 1)
  1076     entries = []
  1076     entries = []
  1077 
  1077 
  1078     diffstyle = web.config('web', 'style')
  1078     diffstyle = web.config('web', 'style')
  1079     if 'style' in req.req.qsparams:
  1079     if 'style' in web.req.qsparams:
  1080         diffstyle = req.req.qsparams['style']
  1080         diffstyle = web.req.qsparams['style']
  1081 
  1081 
  1082     def diff(fctx, linerange=None):
  1082     def diff(fctx, linerange=None):
  1083         ctx = fctx.changectx()
  1083         ctx = fctx.changectx()
  1084         basectx = ctx.p1()
  1084         basectx = ctx.p1()
  1085         path = fctx.path()
  1085         path = fctx.path()
  1169     directory will be included in the archive.
  1169     directory will be included in the archive.
  1170 
  1170 
  1171     No template is used for this handler. Raw, binary content is generated.
  1171     No template is used for this handler. Raw, binary content is generated.
  1172     """
  1172     """
  1173 
  1173 
  1174     type_ = req.req.qsparams.get('type')
  1174     type_ = web.req.qsparams.get('type')
  1175     allowed = web.configlist("web", "allow_archive")
  1175     allowed = web.configlist("web", "allow_archive")
  1176     key = req.req.qsparams['node']
  1176     key = web.req.qsparams['node']
  1177 
  1177 
  1178     if type_ not in web.archivespecs:
  1178     if type_ not in web.archivespecs:
  1179         msg = 'Unsupported archive type: %s' % type_
  1179         msg = 'Unsupported archive type: %s' % type_
  1180         raise ErrorResponse(HTTP_NOT_FOUND, msg)
  1180         raise ErrorResponse(HTTP_NOT_FOUND, msg)
  1181 
  1181 
  1192     name = "%s-%s" % (reponame, arch_version)
  1192     name = "%s-%s" % (reponame, arch_version)
  1193 
  1193 
  1194     ctx = webutil.changectx(web.repo, req)
  1194     ctx = webutil.changectx(web.repo, req)
  1195     pats = []
  1195     pats = []
  1196     match = scmutil.match(ctx, [])
  1196     match = scmutil.match(ctx, [])
  1197     file = req.req.qsparams.get('file')
  1197     file = web.req.qsparams.get('file')
  1198     if file:
  1198     if file:
  1199         pats = ['path:' + file]
  1199         pats = ['path:' + file]
  1200         match = scmutil.match(ctx, pats, default='path')
  1200         match = scmutil.match(ctx, pats, default='path')
  1201         if pats:
  1201         if pats:
  1202             files = [f for f in ctx.manifest().keys() if match(f)]
  1202             files = [f for f in ctx.manifest().keys() if match(f)]
  1224 
  1224 
  1225     return []
  1225     return []
  1226 
  1226 
  1227 @webcommand('static')
  1227 @webcommand('static')
  1228 def static(web, req, tmpl):
  1228 def static(web, req, tmpl):
  1229     fname = req.req.qsparams['file']
  1229     fname = web.req.qsparams['file']
  1230     # 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
  1231     # readable by the user running the CGI script
  1231     # readable by the user running the CGI script
  1232     static = web.config("web", "static", None, untrusted=False)
  1232     static = web.config("web", "static", None, untrusted=False)
  1233     if not static:
  1233     if not static:
  1234         tp = web.templatepath or templater.templatepaths()
  1234         tp = web.templatepath or templater.templatepaths()
  1261     JavaScript. By default it has the same value as ``revision``.
  1261     JavaScript. By default it has the same value as ``revision``.
  1262 
  1262 
  1263     This handler will render the ``graph`` template.
  1263     This handler will render the ``graph`` template.
  1264     """
  1264     """
  1265 
  1265 
  1266     if 'node' in req.req.qsparams:
  1266     if 'node' in web.req.qsparams:
  1267         ctx = webutil.changectx(web.repo, req)
  1267         ctx = webutil.changectx(web.repo, req)
  1268         symrev = webutil.symrevorshortnode(req, ctx)
  1268         symrev = webutil.symrevorshortnode(req, ctx)
  1269     else:
  1269     else:
  1270         ctx = web.repo['tip']
  1270         ctx = web.repo['tip']
  1271         symrev = 'tip'
  1271         symrev = 'tip'
  1272     rev = ctx.rev()
  1272     rev = ctx.rev()
  1273 
  1273 
  1274     bg_height = 39
  1274     bg_height = 39
  1275     revcount = web.maxshortchanges
  1275     revcount = web.maxshortchanges
  1276     if 'revcount' in req.req.qsparams:
  1276     if 'revcount' in web.req.qsparams:
  1277         try:
  1277         try:
  1278             revcount = int(req.req.qsparams.get('revcount', revcount))
  1278             revcount = int(web.req.qsparams.get('revcount', revcount))
  1279             revcount = max(revcount, 1)
  1279             revcount = max(revcount, 1)
  1280             tmpl.defaults['sessionvars']['revcount'] = revcount
  1280             tmpl.defaults['sessionvars']['revcount'] = revcount
  1281         except ValueError:
  1281         except ValueError:
  1282             pass
  1282             pass
  1283 
  1283 
  1284     lessvars = copy.copy(tmpl.defaults['sessionvars'])
  1284     lessvars = copy.copy(tmpl.defaults['sessionvars'])
  1285     lessvars['revcount'] = max(revcount // 2, 1)
  1285     lessvars['revcount'] = max(revcount // 2, 1)
  1286     morevars = copy.copy(tmpl.defaults['sessionvars'])
  1286     morevars = copy.copy(tmpl.defaults['sessionvars'])
  1287     morevars['revcount'] = revcount * 2
  1287     morevars['revcount'] = revcount * 2
  1288 
  1288 
  1289     graphtop = req.req.qsparams.get('graphtop', ctx.hex())
  1289     graphtop = web.req.qsparams.get('graphtop', ctx.hex())
  1290     graphvars = copy.copy(tmpl.defaults['sessionvars'])
  1290     graphvars = copy.copy(tmpl.defaults['sessionvars'])
  1291     graphvars['graphtop'] = graphtop
  1291     graphvars['graphtop'] = graphtop
  1292 
  1292 
  1293     count = len(web.repo)
  1293     count = len(web.repo)
  1294     pos = rev
  1294     pos = rev
  1423     The ``help`` template will be rendered when requesting help for a topic.
  1423     The ``help`` template will be rendered when requesting help for a topic.
  1424     ``helptopics`` will be rendered for the index of help topics.
  1424     ``helptopics`` will be rendered for the index of help topics.
  1425     """
  1425     """
  1426     from .. import commands, help as helpmod  # avoid cycle
  1426     from .. import commands, help as helpmod  # avoid cycle
  1427 
  1427 
  1428     topicname = req.req.qsparams.get('node')
  1428     topicname = web.req.qsparams.get('node')
  1429     if not topicname:
  1429     if not topicname:
  1430         def topics(**map):
  1430         def topics(**map):
  1431             for entries, summary, _doc in helpmod.helptable:
  1431             for entries, summary, _doc in helpmod.helptable:
  1432                 yield {'topic': entries[0], 'summary': summary}
  1432                 yield {'topic': entries[0], 'summary': summary}
  1433 
  1433