comparison mercurial/hgweb/webcommands.py @ 25602:85fb416f2fa7

hgweb: provide symrev (symbolic revision) property to the templates One of the features of hgweb is that current position in repo history is remembered between separate requests. That is, links from /rev/<node_hash> lead to /file/<node_hash> or /log/<node_hash>, so it's easy to dig deep into the history. However, such links could only use node hashes and local revision numbers, so while staying at one exact revision is easy, staying on top of the changes is not, because hashes presumably can't change (local revision numbers can, but probably not in a way you'd find useful for navigating). So while you could use 'tip' or 'default' in a url, links on that page would be permanent. This is not always desired (think /rev/tip or /graph/stable or /log/@) and is sometimes just confusing (i.e. /log/<not the tip hash>, when recent history is not displayed). And if user changed url deliberately to say default instead of <some node hash>, the page ignores that fact and uses node hash in its links, which means that navigation is, in a way, broken. This new property, symrev, is used for storing current revision the way it was specified, so then templates can use it in links and thus "not dereference" the symbolic revision. It is an additional way to produce links, so not every link needs to drop {node|short} in favor of {symrev}, many will still use node hash (log and filelog entries, annotate lines, etc). Some pages (e.g. summary, tags) always use the tip changeset for their context, in such cases symrev is set to 'tip'. This is needed in case the pages want to provide archive links. highlight extension needs to be updated, since _filerevision now takes an additional positional argument (signature "web, req, tmpl" is used by most of webcommands.py functions). More references to symbolic revisions and related gripes: issue2296, issue2826, issue3594, issue3634.
author Anton Shestakov <av6@dwimlabs.net>
date Tue, 16 Jun 2015 02:07:25 +0800
parents 235f6490550c
children 328739ea70c3
comparison
equal deleted inserted replaced
25601:3ec8351fa6ed 25602:85fb416f2fa7
98 mt += '; charset="%s"' % encoding.encoding 98 mt += '; charset="%s"' % encoding.encoding
99 99
100 req.respond(HTTP_OK, mt, path, body=text) 100 req.respond(HTTP_OK, mt, path, body=text)
101 return [] 101 return []
102 102
103 def _filerevision(web, tmpl, fctx): 103 def _filerevision(web, req, tmpl, fctx):
104 f = fctx.path() 104 f = fctx.path()
105 text = fctx.data() 105 text = fctx.data()
106 parity = paritygen(web.stripecount) 106 parity = paritygen(web.stripecount)
107 107
108 if util.binary(text): 108 if util.binary(text):
119 return tmpl("filerevision", 119 return tmpl("filerevision",
120 file=f, 120 file=f,
121 path=webutil.up(f), 121 path=webutil.up(f),
122 text=lines(), 122 text=lines(),
123 rev=fctx.rev(), 123 rev=fctx.rev(),
124 symrev=webutil.symrevorshortnode(req, fctx),
124 node=fctx.hex(), 125 node=fctx.hex(),
125 author=fctx.user(), 126 author=fctx.user(),
126 date=fctx.date(), 127 date=fctx.date(),
127 desc=fctx.description(), 128 desc=fctx.description(),
128 extra=fctx.extra(), 129 extra=fctx.extra(),
156 """ 157 """
157 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0]) 158 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
158 if not path: 159 if not path:
159 return manifest(web, req, tmpl) 160 return manifest(web, req, tmpl)
160 try: 161 try:
161 return _filerevision(web, tmpl, webutil.filectx(web.repo, req)) 162 return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
162 except error.LookupError, inst: 163 except error.LookupError, inst:
163 try: 164 try:
164 return manifest(web, req, tmpl) 165 return manifest(web, req, tmpl)
165 except ErrorResponse: 166 except ErrorResponse:
166 raise inst 167 raise inst
314 searchfunc = searchfuncs[mode] 315 searchfunc = searchfuncs[mode]
315 316
316 tip = web.repo['tip'] 317 tip = web.repo['tip']
317 parity = paritygen(web.stripecount) 318 parity = paritygen(web.stripecount)
318 319
319 return tmpl('search', query=query, node=tip.hex(), 320 return tmpl('search', query=query, node=tip.hex(), symrev='tip',
320 entries=changelist, archives=web.archivelist("tip"), 321 entries=changelist, archives=web.archivelist("tip"),
321 morevars=morevars, lessvars=lessvars, 322 morevars=morevars, lessvars=lessvars,
322 modedesc=searchfunc[1], 323 modedesc=searchfunc[1],
323 showforcekw=showforcekw, showunforcekw=showunforcekw) 324 showforcekw=showforcekw, showunforcekw=showunforcekw)
324 325
349 """ 350 """
350 351
351 query = '' 352 query = ''
352 if 'node' in req.form: 353 if 'node' in req.form:
353 ctx = webutil.changectx(web.repo, req) 354 ctx = webutil.changectx(web.repo, req)
355 symrev = webutil.symrevorshortnode(req, ctx)
354 elif 'rev' in req.form: 356 elif 'rev' in req.form:
355 return _search(web, req, tmpl) 357 return _search(web, req, tmpl)
356 else: 358 else:
357 ctx = web.repo['tip'] 359 ctx = web.repo['tip']
360 symrev = 'tip'
358 361
359 def changelist(): 362 def changelist():
360 revs = [] 363 revs = []
361 if pos != -1: 364 if pos != -1:
362 revs = web.repo.changelog.revs(pos, 0) 365 revs = web.repo.changelog.revs(pos, 0)
401 entries = entries[:-1] 404 entries = entries[:-1]
402 else: 405 else:
403 nextentry = [] 406 nextentry = []
404 407
405 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav, 408 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
406 node=ctx.hex(), rev=pos, changesets=count, 409 node=ctx.hex(), rev=pos, symrev=symrev, changesets=count,
407 entries=entries, 410 entries=entries,
408 latestentry=latestentry, nextentry=nextentry, 411 latestentry=latestentry, nextentry=nextentry,
409 archives=web.archivelist("tip"), revcount=revcount, 412 archives=web.archivelist("tip"), revcount=revcount,
410 morevars=morevars, lessvars=lessvars, query=query) 413 morevars=morevars, lessvars=lessvars, query=query)
411 414
468 is recommended to use the ``file`` handler instead, as it can handle both 471 is recommended to use the ``file`` handler instead, as it can handle both
469 directories and files. 472 directories and files.
470 473
471 The ``manifest`` template will be rendered for this handler. 474 The ``manifest`` template will be rendered for this handler.
472 """ 475 """
473 ctx = webutil.changectx(web.repo, req) 476 if 'node' in req.form:
477 ctx = webutil.changectx(web.repo, req)
478 symrev = webutil.symrevorshortnode(req, ctx)
479 else:
480 ctx = web.repo['tip']
481 symrev = 'tip'
474 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0]) 482 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
475 mf = ctx.manifest() 483 mf = ctx.manifest()
476 node = ctx.node() 484 node = ctx.node()
477 485
478 files = {} 486 files = {}
537 "emptydirs": "/".join(emptydirs), 545 "emptydirs": "/".join(emptydirs),
538 "basename": d} 546 "basename": d}
539 547
540 return tmpl("manifest", 548 return tmpl("manifest",
541 rev=ctx.rev(), 549 rev=ctx.rev(),
550 symrev=symrev,
542 node=hex(node), 551 node=hex(node),
543 path=abspath, 552 path=abspath,
544 up=webutil.up(abspath), 553 up=webutil.up(abspath),
545 upparity=parity.next(), 554 upparity=parity.next(),
546 fentries=filelist, 555 fentries=filelist,
753 tags=tagentries, 762 tags=tagentries,
754 bookmarks=bookmarks, 763 bookmarks=bookmarks,
755 branches=branches, 764 branches=branches,
756 shortlog=changelist, 765 shortlog=changelist,
757 node=tip.hex(), 766 node=tip.hex(),
767 symrev='tip',
758 archives=web.archivelist("tip")) 768 archives=web.archivelist("tip"))
759 769
760 @webcommand('filediff') 770 @webcommand('filediff')
761 def filediff(web, req, tmpl): 771 def filediff(web, req, tmpl):
762 """ 772 """
801 ctx = ctx 811 ctx = ctx
802 return tmpl("filediff", 812 return tmpl("filediff",
803 file=path, 813 file=path,
804 node=hex(n), 814 node=hex(n),
805 rev=ctx.rev(), 815 rev=ctx.rev(),
816 symrev=webutil.symrevorshortnode(req, ctx),
806 date=ctx.date(), 817 date=ctx.date(),
807 desc=ctx.description(), 818 desc=ctx.description(),
808 extra=ctx.extra(), 819 extra=ctx.extra(),
809 author=ctx.user(), 820 author=ctx.user(),
810 rename=rename, 821 rename=rename,
875 comparison = webutil.compare(tmpl, context, leftlines, rightlines) 886 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
876 return tmpl('filecomparison', 887 return tmpl('filecomparison',
877 file=path, 888 file=path,
878 node=hex(ctx.node()), 889 node=hex(ctx.node()),
879 rev=ctx.rev(), 890 rev=ctx.rev(),
891 symrev=webutil.symrevorshortnode(req, ctx),
880 date=ctx.date(), 892 date=ctx.date(),
881 desc=ctx.description(), 893 desc=ctx.description(),
882 extra=ctx.extra(), 894 extra=ctx.extra(),
883 author=ctx.user(), 895 author=ctx.user(),
884 rename=rename, 896 rename=rename,
942 return tmpl("fileannotate", 954 return tmpl("fileannotate",
943 file=f, 955 file=f,
944 annotate=annotate, 956 annotate=annotate,
945 path=webutil.up(f), 957 path=webutil.up(f),
946 rev=fctx.rev(), 958 rev=fctx.rev(),
959 symrev=webutil.symrevorshortnode(req, fctx),
947 node=fctx.hex(), 960 node=fctx.hex(),
948 author=fctx.user(), 961 author=fctx.user(),
949 date=fctx.date(), 962 date=fctx.date(),
950 desc=fctx.description(), 963 desc=fctx.description(),
951 extra=fctx.extra(), 964 extra=fctx.extra(),
1041 latestentry = entries[:1] 1054 latestentry = entries[:1]
1042 1055
1043 revnav = webutil.filerevnav(web.repo, fctx.path()) 1056 revnav = webutil.filerevnav(web.repo, fctx.path())
1044 nav = revnav.gen(end - 1, revcount, count) 1057 nav = revnav.gen(end - 1, revcount, count)
1045 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav, 1058 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
1059 symrev=webutil.symrevorshortnode(req, fctx),
1046 entries=entries, 1060 entries=entries,
1047 latestentry=latestentry, 1061 latestentry=latestentry,
1048 revcount=revcount, morevars=morevars, lessvars=lessvars) 1062 revcount=revcount, morevars=morevars, lessvars=lessvars)
1049 1063
1050 @webcommand('archive') 1064 @webcommand('archive')
1147 to show information for. 1161 to show information for.
1148 1162
1149 This handler will render the ``graph`` template. 1163 This handler will render the ``graph`` template.
1150 """ 1164 """
1151 1165
1152 ctx = webutil.changectx(web.repo, req) 1166 if 'node' in req.form:
1167 ctx = webutil.changectx(web.repo, req)
1168 symrev = webutil.symrevorshortnode(req, ctx)
1169 else:
1170 ctx = web.repo['tip']
1171 symrev = 'tip'
1153 rev = ctx.rev() 1172 rev = ctx.rev()
1154 1173
1155 bg_height = 39 1174 bg_height = 39
1156 revcount = web.maxshortchanges 1175 revcount = web.maxshortchanges
1157 if 'revcount' in req.form: 1176 if 'revcount' in req.form:
1250 1269
1251 cols = getcolumns(tree) 1270 cols = getcolumns(tree)
1252 rows = len(tree) 1271 rows = len(tree)
1253 canvasheight = (rows + 1) * bg_height - 27 1272 canvasheight = (rows + 1) * bg_height - 27
1254 1273
1255 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev, 1274 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
1275 uprev=uprev,
1256 lessvars=lessvars, morevars=morevars, downrev=downrev, 1276 lessvars=lessvars, morevars=morevars, downrev=downrev,
1257 cols=cols, rows=rows, 1277 cols=cols, rows=rows,
1258 canvaswidth=(cols + 1) * bg_height, 1278 canvaswidth=(cols + 1) * bg_height,
1259 truecanvasheight=rows * bg_height, 1279 truecanvasheight=rows * bg_height,
1260 canvasheight=canvasheight, bg_height=bg_height, 1280 canvasheight=canvasheight, bg_height=bg_height,