comparison mercurial/hgweb/webutil.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 6ccf539aec71
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
39 templateutil, 39 templateutil,
40 ui as uimod, 40 ui as uimod,
41 util, 41 util,
42 ) 42 )
43 43
44 from ..utils import ( 44 from ..utils import stringutil
45 stringutil, 45
46 archivespecs = util.sortdict(
47 (
48 ('zip', ('application/zip', 'zip', '.zip', None)),
49 ('gz', ('application/x-gzip', 'tgz', '.tar.gz', None)),
50 ('bz2', ('application/x-bzip2', 'tbz2', '.tar.bz2', None)),
51 )
46 ) 52 )
47 53
48 archivespecs = util.sortdict((
49 ('zip', ('application/zip', 'zip', '.zip', None)),
50 ('gz', ('application/x-gzip', 'tgz', '.tar.gz', None)),
51 ('bz2', ('application/x-bzip2', 'tbz2', '.tar.bz2', None)),
52 ))
53 54
54 def archivelist(ui, nodeid, url=None): 55 def archivelist(ui, nodeid, url=None):
55 allowed = ui.configlist('web', 'allow-archive', untrusted=True) 56 allowed = ui.configlist('web', 'allow-archive', untrusted=True)
56 archives = [] 57 archives = []
57 58
58 for typ, spec in archivespecs.iteritems(): 59 for typ, spec in archivespecs.iteritems():
59 if typ in allowed or ui.configbool('web', 'allow' + typ, 60 if typ in allowed or ui.configbool(
60 untrusted=True): 61 'web', 'allow' + typ, untrusted=True
61 archives.append({ 62 ):
62 'type': typ, 63 archives.append(
63 'extension': spec[2], 64 {'type': typ, 'extension': spec[2], 'node': nodeid, 'url': url,}
64 'node': nodeid, 65 )
65 'url': url,
66 })
67 66
68 return templateutil.mappinglist(archives) 67 return templateutil.mappinglist(archives)
68
69 69
70 def up(p): 70 def up(p):
71 if p[0:1] != "/": 71 if p[0:1] != "/":
72 p = "/" + p 72 p = "/" + p
73 if p[-1:] == "/": 73 if p[-1:] == "/":
74 p = p[:-1] 74 p = p[:-1]
75 up = os.path.dirname(p) 75 up = os.path.dirname(p)
76 if up == "/": 76 if up == "/":
77 return "/" 77 return "/"
78 return up + "/" 78 return up + "/"
79
79 80
80 def _navseq(step, firststep=None): 81 def _navseq(step, firststep=None):
81 if firststep: 82 if firststep:
82 yield firststep 83 yield firststep
83 if firststep >= 20 and firststep <= 40: 84 if firststep >= 20 and firststep <= 40:
90 while True: 91 while True:
91 yield 1 * step 92 yield 1 * step
92 yield 3 * step 93 yield 3 * step
93 step *= 10 94 step *= 10
94 95
96
95 class revnav(object): 97 class revnav(object):
96
97 def __init__(self, repo): 98 def __init__(self, repo):
98 """Navigation generation object 99 """Navigation generation object
99 100
100 :repo: repo object we generate nav for 101 :repo: repo object we generate nav for
101 """ 102 """
130 - containing a dictionary with a `before` and `after` key 131 - containing a dictionary with a `before` and `after` key
131 - values are dictionaries with `label` and `node` keys 132 - values are dictionaries with `label` and `node` keys
132 """ 133 """
133 if not self: 134 if not self:
134 # empty repo 135 # empty repo
135 return templateutil.mappinglist([ 136 return templateutil.mappinglist(
136 {'before': templateutil.mappinglist([]), 137 [
137 'after': templateutil.mappinglist([])}, 138 {
138 ]) 139 'before': templateutil.mappinglist([]),
140 'after': templateutil.mappinglist([]),
141 },
142 ]
143 )
139 144
140 targets = [] 145 targets = []
141 for f in _navseq(1, pagelen): 146 for f in _navseq(1, pagelen):
142 if f > limit: 147 if f > limit:
143 break 148 break
150 navafter = [] 155 navafter = []
151 for rev in targets: 156 for rev in targets:
152 if rev not in self._revlog: 157 if rev not in self._revlog:
153 continue 158 continue
154 if pos < rev < limit: 159 if pos < rev < limit:
155 navafter.append({'label': '+%d' % abs(rev - pos), 160 navafter.append(
156 'node': self.hex(rev)}) 161 {'label': '+%d' % abs(rev - pos), 'node': self.hex(rev)}
162 )
157 if 0 < rev < pos: 163 if 0 < rev < pos:
158 navbefore.append({'label': '-%d' % abs(rev - pos), 164 navbefore.append(
159 'node': self.hex(rev)}) 165 {'label': '-%d' % abs(rev - pos), 'node': self.hex(rev)}
166 )
160 167
161 navafter.append({'label': 'tip', 'node': 'tip'}) 168 navafter.append({'label': 'tip', 'node': 'tip'})
162 169
163 # TODO: maybe this can be a scalar object supporting tomap() 170 # TODO: maybe this can be a scalar object supporting tomap()
164 return templateutil.mappinglist([ 171 return templateutil.mappinglist(
165 {'before': templateutil.mappinglist(navbefore), 172 [
166 'after': templateutil.mappinglist(navafter)}, 173 {
167 ]) 174 'before': templateutil.mappinglist(navbefore),
175 'after': templateutil.mappinglist(navafter),
176 },
177 ]
178 )
179
168 180
169 class filerevnav(revnav): 181 class filerevnav(revnav):
170
171 def __init__(self, repo, path): 182 def __init__(self, repo, path):
172 """Navigation generation object 183 """Navigation generation object
173 184
174 :repo: repo object we generate nav for 185 :repo: repo object we generate nav for
175 :path: path of the file we generate nav for 186 :path: path of the file we generate nav for
179 # used for hex generation 190 # used for hex generation
180 self._revlog = repo.file(path) 191 self._revlog = repo.file(path)
181 192
182 def hex(self, rev): 193 def hex(self, rev):
183 return hex(self._changelog.node(self._revlog.linkrev(rev))) 194 return hex(self._changelog.node(self._revlog.linkrev(rev)))
195
184 196
185 # TODO: maybe this can be a wrapper class for changectx/filectx list, which 197 # TODO: maybe this can be a wrapper class for changectx/filectx list, which
186 # yields {'ctx': ctx} 198 # yields {'ctx': ctx}
187 def _ctxsgen(context, ctxs): 199 def _ctxsgen(context, ctxs):
188 for s in ctxs: 200 for s in ctxs:
196 } 208 }
197 if util.safehasattr(s, 'path'): 209 if util.safehasattr(s, 'path'):
198 d['file'] = s.path() 210 d['file'] = s.path()
199 yield d 211 yield d
200 212
213
201 def _siblings(siblings=None, hiderev=None): 214 def _siblings(siblings=None, hiderev=None):
202 if siblings is None: 215 if siblings is None:
203 siblings = [] 216 siblings = []
204 siblings = [s for s in siblings if s.node() != nullid] 217 siblings = [s for s in siblings if s.node() != nullid]
205 if len(siblings) == 1 and siblings[0].rev() == hiderev: 218 if len(siblings) == 1 and siblings[0].rev() == hiderev:
206 siblings = [] 219 siblings = []
207 return templateutil.mappinggenerator(_ctxsgen, args=(siblings,)) 220 return templateutil.mappinggenerator(_ctxsgen, args=(siblings,))
208 221
222
209 def difffeatureopts(req, ui, section): 223 def difffeatureopts(req, ui, section):
210 diffopts = diffutil.difffeatureopts(ui, untrusted=True, 224 diffopts = diffutil.difffeatureopts(
211 section=section, whitespace=True) 225 ui, untrusted=True, section=section, whitespace=True
226 )
212 227
213 for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'): 228 for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'):
214 v = req.qsparams.get(k) 229 v = req.qsparams.get(k)
215 if v is not None: 230 if v is not None:
216 v = stringutil.parsebool(v) 231 v = stringutil.parsebool(v)
217 setattr(diffopts, k, v if v is not None else True) 232 setattr(diffopts, k, v if v is not None else True)
218 233
219 return diffopts 234 return diffopts
220 235
236
221 def annotate(req, fctx, ui): 237 def annotate(req, fctx, ui):
222 diffopts = difffeatureopts(req, ui, 'annotate') 238 diffopts = difffeatureopts(req, ui, 'annotate')
223 return fctx.annotate(follow=True, diffopts=diffopts) 239 return fctx.annotate(follow=True, diffopts=diffopts)
240
224 241
225 def parents(ctx, hide=None): 242 def parents(ctx, hide=None):
226 if isinstance(ctx, context.basefilectx): 243 if isinstance(ctx, context.basefilectx):
227 introrev = ctx.introrev() 244 introrev = ctx.introrev()
228 if ctx.changectx().rev() != introrev: 245 if ctx.changectx().rev() != introrev:
229 return _siblings([ctx.repo()[introrev]], hide) 246 return _siblings([ctx.repo()[introrev]], hide)
230 return _siblings(ctx.parents(), hide) 247 return _siblings(ctx.parents(), hide)
231 248
249
232 def children(ctx, hide=None): 250 def children(ctx, hide=None):
233 return _siblings(ctx.children(), hide) 251 return _siblings(ctx.children(), hide)
252
234 253
235 def renamelink(fctx): 254 def renamelink(fctx):
236 r = fctx.renamed() 255 r = fctx.renamed()
237 if r: 256 if r:
238 return templateutil.mappinglist([{'file': r[0], 'node': hex(r[1])}]) 257 return templateutil.mappinglist([{'file': r[0], 'node': hex(r[1])}])
239 return templateutil.mappinglist([]) 258 return templateutil.mappinglist([])
240 259
260
241 def nodetagsdict(repo, node): 261 def nodetagsdict(repo, node):
242 return templateutil.hybridlist(repo.nodetags(node), name='name') 262 return templateutil.hybridlist(repo.nodetags(node), name='name')
243 263
264
244 def nodebookmarksdict(repo, node): 265 def nodebookmarksdict(repo, node):
245 return templateutil.hybridlist(repo.nodebookmarks(node), name='name') 266 return templateutil.hybridlist(repo.nodebookmarks(node), name='name')
267
246 268
247 def nodebranchdict(repo, ctx): 269 def nodebranchdict(repo, ctx):
248 branches = [] 270 branches = []
249 branch = ctx.branch() 271 branch = ctx.branch()
250 # If this is an empty repo, ctx.node() == nullid, 272 # If this is an empty repo, ctx.node() == nullid,
255 branchnode = None 277 branchnode = None
256 if branchnode == ctx.node(): 278 if branchnode == ctx.node():
257 branches.append(branch) 279 branches.append(branch)
258 return templateutil.hybridlist(branches, name='name') 280 return templateutil.hybridlist(branches, name='name')
259 281
282
260 def nodeinbranch(repo, ctx): 283 def nodeinbranch(repo, ctx):
261 branches = [] 284 branches = []
262 branch = ctx.branch() 285 branch = ctx.branch()
263 try: 286 try:
264 branchnode = repo.branchtip(branch) 287 branchnode = repo.branchtip(branch)
266 branchnode = None 289 branchnode = None
267 if branch != 'default' and branchnode != ctx.node(): 290 if branch != 'default' and branchnode != ctx.node():
268 branches.append(branch) 291 branches.append(branch)
269 return templateutil.hybridlist(branches, name='name') 292 return templateutil.hybridlist(branches, name='name')
270 293
294
271 def nodebranchnodefault(ctx): 295 def nodebranchnodefault(ctx):
272 branches = [] 296 branches = []
273 branch = ctx.branch() 297 branch = ctx.branch()
274 if branch != 'default': 298 if branch != 'default':
275 branches.append(branch) 299 branches.append(branch)
276 return templateutil.hybridlist(branches, name='name') 300 return templateutil.hybridlist(branches, name='name')
277 301
302
278 def _nodenamesgen(context, f, node, name): 303 def _nodenamesgen(context, f, node, name):
279 for t in f(node): 304 for t in f(node):
280 yield {name: t} 305 yield {name: t}
281 306
307
282 def showtag(repo, t1, node=nullid): 308 def showtag(repo, t1, node=nullid):
283 args = (repo.nodetags, node, 'tag') 309 args = (repo.nodetags, node, 'tag')
284 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1) 310 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
285 311
312
286 def showbookmark(repo, t1, node=nullid): 313 def showbookmark(repo, t1, node=nullid):
287 args = (repo.nodebookmarks, node, 'bookmark') 314 args = (repo.nodebookmarks, node, 'bookmark')
288 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1) 315 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
316
289 317
290 def branchentries(repo, stripecount, limit=0): 318 def branchentries(repo, stripecount, limit=0):
291 tips = [] 319 tips = []
292 heads = repo.heads() 320 heads = repo.heads()
293 parity = paritygen(stripecount) 321 parity = paritygen(stripecount)
311 yield { 339 yield {
312 'parity': next(parity), 340 'parity': next(parity),
313 'branch': ctx.branch(), 341 'branch': ctx.branch(),
314 'status': status, 342 'status': status,
315 'node': ctx.hex(), 343 'node': ctx.hex(),
316 'date': ctx.date() 344 'date': ctx.date(),
317 } 345 }
318 346
319 return templateutil.mappinggenerator(entries) 347 return templateutil.mappinggenerator(entries)
348
320 349
321 def cleanpath(repo, path): 350 def cleanpath(repo, path):
322 path = path.lstrip('/') 351 path = path.lstrip('/')
323 auditor = pathutil.pathauditor(repo.root, realfs=False) 352 auditor = pathutil.pathauditor(repo.root, realfs=False)
324 return pathutil.canonpath(repo.root, '', path, auditor=auditor) 353 return pathutil.canonpath(repo.root, '', path, auditor=auditor)
354
325 355
326 def changectx(repo, req): 356 def changectx(repo, req):
327 changeid = "tip" 357 changeid = "tip"
328 if 'node' in req.qsparams: 358 if 'node' in req.qsparams:
329 changeid = req.qsparams['node'] 359 changeid = req.qsparams['node']
330 ipos = changeid.find(':') 360 ipos = changeid.find(':')
331 if ipos != -1: 361 if ipos != -1:
332 changeid = changeid[(ipos + 1):] 362 changeid = changeid[(ipos + 1) :]
333 363
334 return scmutil.revsymbol(repo, changeid) 364 return scmutil.revsymbol(repo, changeid)
365
335 366
336 def basechangectx(repo, req): 367 def basechangectx(repo, req):
337 if 'node' in req.qsparams: 368 if 'node' in req.qsparams:
338 changeid = req.qsparams['node'] 369 changeid = req.qsparams['node']
339 ipos = changeid.find(':') 370 ipos = changeid.find(':')
340 if ipos != -1: 371 if ipos != -1:
341 changeid = changeid[:ipos] 372 changeid = changeid[:ipos]
342 return scmutil.revsymbol(repo, changeid) 373 return scmutil.revsymbol(repo, changeid)
343 374
344 return None 375 return None
376
345 377
346 def filectx(repo, req): 378 def filectx(repo, req):
347 if 'file' not in req.qsparams: 379 if 'file' not in req.qsparams:
348 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') 380 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
349 path = cleanpath(repo, req.qsparams['file']) 381 path = cleanpath(repo, req.qsparams['file'])
358 except error.RepoError: 390 except error.RepoError:
359 fctx = repo.filectx(path, fileid=changeid) 391 fctx = repo.filectx(path, fileid=changeid)
360 392
361 return fctx 393 return fctx
362 394
395
363 def linerange(req): 396 def linerange(req):
364 linerange = req.qsparams.getall('linerange') 397 linerange = req.qsparams.getall('linerange')
365 if not linerange: 398 if not linerange:
366 return None 399 return None
367 if len(linerange) > 1: 400 if len(linerange) > 1:
368 raise ErrorResponse(HTTP_BAD_REQUEST, 401 raise ErrorResponse(HTTP_BAD_REQUEST, 'redundant linerange parameter')
369 'redundant linerange parameter')
370 try: 402 try:
371 fromline, toline = map(int, linerange[0].split(':', 1)) 403 fromline, toline = map(int, linerange[0].split(':', 1))
372 except ValueError: 404 except ValueError:
373 raise ErrorResponse(HTTP_BAD_REQUEST, 405 raise ErrorResponse(HTTP_BAD_REQUEST, 'invalid linerange parameter')
374 'invalid linerange parameter')
375 try: 406 try:
376 return util.processlinerange(fromline, toline) 407 return util.processlinerange(fromline, toline)
377 except error.ParseError as exc: 408 except error.ParseError as exc:
378 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc)) 409 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc))
379 410
411
380 def formatlinerange(fromline, toline): 412 def formatlinerange(fromline, toline):
381 return '%d:%d' % (fromline + 1, toline) 413 return '%d:%d' % (fromline + 1, toline)
414
382 415
383 def _succsandmarkersgen(context, mapping): 416 def _succsandmarkersgen(context, mapping):
384 repo = context.resource(mapping, 'repo') 417 repo = context.resource(mapping, 'repo')
385 itemmappings = templatekw.showsuccsandmarkers(context, mapping) 418 itemmappings = templatekw.showsuccsandmarkers(context, mapping)
386 for item in itemmappings.tovalue(context, mapping): 419 for item in itemmappings.tovalue(context, mapping):
387 item['successors'] = _siblings(repo[successor] 420 item['successors'] = _siblings(
388 for successor in item['successors']) 421 repo[successor] for successor in item['successors']
422 )
389 yield item 423 yield item
424
390 425
391 def succsandmarkers(context, mapping): 426 def succsandmarkers(context, mapping):
392 return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,)) 427 return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,))
393 428
429
394 # teach templater succsandmarkers is switched to (context, mapping) API 430 # teach templater succsandmarkers is switched to (context, mapping) API
395 succsandmarkers._requires = {'repo', 'ctx'} 431 succsandmarkers._requires = {'repo', 'ctx'}
432
396 433
397 def _whyunstablegen(context, mapping): 434 def _whyunstablegen(context, mapping):
398 repo = context.resource(mapping, 'repo') 435 repo = context.resource(mapping, 'repo')
399 ctx = context.resource(mapping, 'ctx') 436 ctx = context.resource(mapping, 'ctx')
400 437
402 for entry in entries: 439 for entry in entries:
403 if entry.get('divergentnodes'): 440 if entry.get('divergentnodes'):
404 entry['divergentnodes'] = _siblings(entry['divergentnodes']) 441 entry['divergentnodes'] = _siblings(entry['divergentnodes'])
405 yield entry 442 yield entry
406 443
444
407 def whyunstable(context, mapping): 445 def whyunstable(context, mapping):
408 return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,)) 446 return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,))
409 447
448
410 whyunstable._requires = {'repo', 'ctx'} 449 whyunstable._requires = {'repo', 'ctx'}
450
411 451
412 def commonentry(repo, ctx): 452 def commonentry(repo, ctx):
413 node = scmutil.binnode(ctx) 453 node = scmutil.binnode(ctx)
414 return { 454 return {
415 # TODO: perhaps ctx.changectx() should be assigned if ctx is a 455 # TODO: perhaps ctx.changectx() should be assigned if ctx is a
423 'date': ctx.date(), 463 'date': ctx.date(),
424 'extra': ctx.extra(), 464 'extra': ctx.extra(),
425 'phase': ctx.phasestr(), 465 'phase': ctx.phasestr(),
426 'obsolete': ctx.obsolete(), 466 'obsolete': ctx.obsolete(),
427 'succsandmarkers': succsandmarkers, 467 'succsandmarkers': succsandmarkers,
428 'instabilities': templateutil.hybridlist(ctx.instabilities(), 468 'instabilities': templateutil.hybridlist(
429 name='instability'), 469 ctx.instabilities(), name='instability'
470 ),
430 'whyunstable': whyunstable, 471 'whyunstable': whyunstable,
431 'branch': nodebranchnodefault(ctx), 472 'branch': nodebranchnodefault(ctx),
432 'inbranch': nodeinbranch(repo, ctx), 473 'inbranch': nodeinbranch(repo, ctx),
433 'branches': nodebranchdict(repo, ctx), 474 'branches': nodebranchdict(repo, ctx),
434 'tags': nodetagsdict(repo, node), 475 'tags': nodetagsdict(repo, node),
435 'bookmarks': nodebookmarksdict(repo, node), 476 'bookmarks': nodebookmarksdict(repo, node),
436 'parent': lambda context, mapping: parents(ctx), 477 'parent': lambda context, mapping: parents(ctx),
437 'child': lambda context, mapping: children(ctx), 478 'child': lambda context, mapping: children(ctx),
438 } 479 }
439 480
481
440 def changelistentry(web, ctx): 482 def changelistentry(web, ctx):
441 '''Obtain a dictionary to be used for entries in a changelist. 483 '''Obtain a dictionary to be used for entries in a changelist.
442 484
443 This function is called when producing items for the "entries" list passed 485 This function is called when producing items for the "entries" list passed
444 to the "shortlog" and "changelog" templates. 486 to the "shortlog" and "changelog" templates.
448 n = scmutil.binnode(ctx) 490 n = scmutil.binnode(ctx)
449 showtags = showtag(repo, 'changelogtag', n) 491 showtags = showtag(repo, 'changelogtag', n)
450 files = listfilediffs(ctx.files(), n, web.maxfiles) 492 files = listfilediffs(ctx.files(), n, web.maxfiles)
451 493
452 entry = commonentry(repo, ctx) 494 entry = commonentry(repo, ctx)
453 entry.update({ 495 entry.update(
454 'allparents': lambda context, mapping: parents(ctx), 496 {
455 'parent': lambda context, mapping: parents(ctx, rev - 1), 497 'allparents': lambda context, mapping: parents(ctx),
456 'child': lambda context, mapping: children(ctx, rev + 1), 498 'parent': lambda context, mapping: parents(ctx, rev - 1),
457 'changelogtag': showtags, 499 'child': lambda context, mapping: children(ctx, rev + 1),
458 'files': files, 500 'changelogtag': showtags,
459 }) 501 'files': files,
502 }
503 )
460 return entry 504 return entry
505
461 506
462 def changelistentries(web, revs, maxcount, parityfn): 507 def changelistentries(web, revs, maxcount, parityfn):
463 """Emit up to N records for an iterable of revisions.""" 508 """Emit up to N records for an iterable of revisions."""
464 repo = web.repo 509 repo = web.repo
465 510
472 517
473 entry = changelistentry(web, repo[rev]) 518 entry = changelistentry(web, repo[rev])
474 entry['parity'] = next(parityfn) 519 entry['parity'] = next(parityfn)
475 520
476 yield entry 521 yield entry
522
477 523
478 def symrevorshortnode(req, ctx): 524 def symrevorshortnode(req, ctx):
479 if 'node' in req.qsparams: 525 if 'node' in req.qsparams:
480 return templatefilters.revescape(req.qsparams['node']) 526 return templatefilters.revescape(req.qsparams['node'])
481 else: 527 else:
482 return short(scmutil.binnode(ctx)) 528 return short(scmutil.binnode(ctx))
483 529
530
484 def _listfilesgen(context, ctx, stripecount): 531 def _listfilesgen(context, ctx, stripecount):
485 parity = paritygen(stripecount) 532 parity = paritygen(stripecount)
486 for blockno, f in enumerate(ctx.files()): 533 for blockno, f in enumerate(ctx.files()):
487 template = 'filenodelink' if f in ctx else 'filenolink' 534 template = 'filenodelink' if f in ctx else 'filenolink'
488 yield context.process(template, { 535 yield context.process(
489 'node': ctx.hex(), 536 template,
490 'file': f, 537 {
491 'blockno': blockno + 1, 538 'node': ctx.hex(),
492 'parity': next(parity), 539 'file': f,
493 }) 540 'blockno': blockno + 1,
541 'parity': next(parity),
542 },
543 )
544
494 545
495 def changesetentry(web, ctx): 546 def changesetentry(web, ctx):
496 '''Obtain a dictionary to be used to render the "changeset" template.''' 547 '''Obtain a dictionary to be used to render the "changeset" template.'''
497 548
498 showtags = showtag(web.repo, 'changesettag', scmutil.binnode(ctx)) 549 showtags = showtag(web.repo, 'changesettag', scmutil.binnode(ctx))
499 showbookmarks = showbookmark(web.repo, 'changesetbookmark', 550 showbookmarks = showbookmark(
500 scmutil.binnode(ctx)) 551 web.repo, 'changesetbookmark', scmutil.binnode(ctx)
552 )
501 showbranch = nodebranchnodefault(ctx) 553 showbranch = nodebranchnodefault(ctx)
502 554
503 basectx = basechangectx(web.repo, web.req) 555 basectx = basechangectx(web.repo, web.req)
504 if basectx is None: 556 if basectx is None:
505 basectx = ctx.p1() 557 basectx = ctx.p1()
519 symrev=symrevorshortnode(web.req, ctx), 571 symrev=symrevorshortnode(web.req, ctx),
520 basenode=basectx.hex(), 572 basenode=basectx.hex(),
521 changesettag=showtags, 573 changesettag=showtags,
522 changesetbookmark=showbookmarks, 574 changesetbookmark=showbookmarks,
523 changesetbranch=showbranch, 575 changesetbranch=showbranch,
524 files=templateutil.mappedgenerator(_listfilesgen, 576 files=templateutil.mappedgenerator(
525 args=(ctx, web.stripecount)), 577 _listfilesgen, args=(ctx, web.stripecount)
578 ),
526 diffsummary=lambda context, mapping: diffsummary(diffstatsgen), 579 diffsummary=lambda context, mapping: diffsummary(diffstatsgen),
527 diffstat=diffstats, 580 diffstat=diffstats,
528 archives=web.archivelist(ctx.hex()), 581 archives=web.archivelist(ctx.hex()),
529 **pycompat.strkwargs(commonentry(web.repo, ctx))) 582 **pycompat.strkwargs(commonentry(web.repo, ctx))
583 )
584
530 585
531 def _listfilediffsgen(context, files, node, max): 586 def _listfilediffsgen(context, files, node, max):
532 for f in files[:max]: 587 for f in files[:max]:
533 yield context.process('filedifflink', {'node': hex(node), 'file': f}) 588 yield context.process('filedifflink', {'node': hex(node), 'file': f})
534 if len(files) > max: 589 if len(files) > max:
535 yield context.process('fileellipses', {}) 590 yield context.process('fileellipses', {})
536 591
592
537 def listfilediffs(files, node, max): 593 def listfilediffs(files, node, max):
538 return templateutil.mappedgenerator(_listfilediffsgen, 594 return templateutil.mappedgenerator(
539 args=(files, node, max)) 595 _listfilediffsgen, args=(files, node, max)
596 )
597
540 598
541 def _prettyprintdifflines(context, lines, blockno, lineidprefix): 599 def _prettyprintdifflines(context, lines, blockno, lineidprefix):
542 for lineno, l in enumerate(lines, 1): 600 for lineno, l in enumerate(lines, 1):
543 difflineno = "%d.%d" % (blockno, lineno) 601 difflineno = "%d.%d" % (blockno, lineno)
544 if l.startswith('+'): 602 if l.startswith('+'):
547 ltype = "difflineminus" 605 ltype = "difflineminus"
548 elif l.startswith('@'): 606 elif l.startswith('@'):
549 ltype = "difflineat" 607 ltype = "difflineat"
550 else: 608 else:
551 ltype = "diffline" 609 ltype = "diffline"
552 yield context.process(ltype, { 610 yield context.process(
553 'line': l, 611 ltype,
554 'lineno': lineno, 612 {
555 'lineid': lineidprefix + "l%s" % difflineno, 613 'line': l,
556 'linenumber': "% 8s" % difflineno, 614 'lineno': lineno,
557 }) 615 'lineid': lineidprefix + "l%s" % difflineno,
558 616 'linenumber': "% 8s" % difflineno,
559 def _diffsgen(context, repo, ctx, basectx, files, style, stripecount, 617 },
560 linerange, lineidprefix): 618 )
619
620
621 def _diffsgen(
622 context,
623 repo,
624 ctx,
625 basectx,
626 files,
627 style,
628 stripecount,
629 linerange,
630 lineidprefix,
631 ):
561 if files: 632 if files:
562 m = match.exact(files) 633 m = match.exact(files)
563 else: 634 else:
564 m = match.always() 635 m = match.always()
565 636
576 s1, l1, s2, l2 = hunkrange 647 s1, l1, s2, l2 = hunkrange
577 if not mdiff.hunkinrange((s2, l2), linerange): 648 if not mdiff.hunkinrange((s2, l2), linerange):
578 continue 649 continue
579 lines.extend(hunklines) 650 lines.extend(hunklines)
580 if lines: 651 if lines:
581 l = templateutil.mappedgenerator(_prettyprintdifflines, 652 l = templateutil.mappedgenerator(
582 args=(lines, blockno, 653 _prettyprintdifflines, args=(lines, blockno, lineidprefix)
583 lineidprefix)) 654 )
584 yield { 655 yield {
585 'parity': next(parity), 656 'parity': next(parity),
586 'blockno': blockno, 657 'blockno': blockno,
587 'lines': l, 658 'lines': l,
588 } 659 }
589 660
661
590 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=''): 662 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=''):
591 args = (web.repo, ctx, basectx, files, style, web.stripecount, 663 args = (
592 linerange, lineidprefix) 664 web.repo,
665 ctx,
666 basectx,
667 files,
668 style,
669 web.stripecount,
670 linerange,
671 lineidprefix,
672 )
593 return templateutil.mappinggenerator(_diffsgen, args=args, name='diffblock') 673 return templateutil.mappinggenerator(_diffsgen, args=args, name='diffblock')
674
594 675
595 def _compline(type, leftlineno, leftline, rightlineno, rightline): 676 def _compline(type, leftlineno, leftline, rightlineno, rightline):
596 lineid = leftlineno and ("l%d" % leftlineno) or '' 677 lineid = leftlineno and ("l%d" % leftlineno) or ''
597 lineid += rightlineno and ("r%d" % rightlineno) or '' 678 lineid += rightlineno and ("r%d" % rightlineno) or ''
598 llno = '%d' % leftlineno if leftlineno else '' 679 llno = '%d' % leftlineno if leftlineno else ''
606 'rightlineno': rightlineno, 687 'rightlineno': rightlineno,
607 'rightlinenumber': "% 6s" % rlno, 688 'rightlinenumber': "% 6s" % rlno,
608 'rightline': rightline or '', 689 'rightline': rightline or '',
609 } 690 }
610 691
692
611 def _getcompblockgen(context, leftlines, rightlines, opcodes): 693 def _getcompblockgen(context, leftlines, rightlines, opcodes):
612 for type, llo, lhi, rlo, rhi in opcodes: 694 for type, llo, lhi, rlo, rhi in opcodes:
613 type = pycompat.sysbytes(type) 695 type = pycompat.sysbytes(type)
614 len1 = lhi - llo 696 len1 = lhi - llo
615 len2 = rhi - rlo 697 len2 = rhi - rlo
616 count = min(len1, len2) 698 count = min(len1, len2)
617 for i in pycompat.xrange(count): 699 for i in pycompat.xrange(count):
618 yield _compline(type=type, 700 yield _compline(
619 leftlineno=llo + i + 1, 701 type=type,
620 leftline=leftlines[llo + i], 702 leftlineno=llo + i + 1,
621 rightlineno=rlo + i + 1, 703 leftline=leftlines[llo + i],
622 rightline=rightlines[rlo + i]) 704 rightlineno=rlo + i + 1,
705 rightline=rightlines[rlo + i],
706 )
623 if len1 > len2: 707 if len1 > len2:
624 for i in pycompat.xrange(llo + count, lhi): 708 for i in pycompat.xrange(llo + count, lhi):
625 yield _compline(type=type, 709 yield _compline(
626 leftlineno=i + 1, 710 type=type,
627 leftline=leftlines[i], 711 leftlineno=i + 1,
628 rightlineno=None, 712 leftline=leftlines[i],
629 rightline=None) 713 rightlineno=None,
714 rightline=None,
715 )
630 elif len2 > len1: 716 elif len2 > len1:
631 for i in pycompat.xrange(rlo + count, rhi): 717 for i in pycompat.xrange(rlo + count, rhi):
632 yield _compline(type=type, 718 yield _compline(
633 leftlineno=None, 719 type=type,
634 leftline=None, 720 leftlineno=None,
635 rightlineno=i + 1, 721 leftline=None,
636 rightline=rightlines[i]) 722 rightlineno=i + 1,
723 rightline=rightlines[i],
724 )
725
637 726
638 def _getcompblock(leftlines, rightlines, opcodes): 727 def _getcompblock(leftlines, rightlines, opcodes):
639 args = (leftlines, rightlines, opcodes) 728 args = (leftlines, rightlines, opcodes)
640 return templateutil.mappinggenerator(_getcompblockgen, args=args, 729 return templateutil.mappinggenerator(
641 name='comparisonline') 730 _getcompblockgen, args=args, name='comparisonline'
731 )
732
642 733
643 def _comparegen(context, contextnum, leftlines, rightlines): 734 def _comparegen(context, contextnum, leftlines, rightlines):
644 '''Generator function that provides side-by-side comparison data.''' 735 '''Generator function that provides side-by-side comparison data.'''
645 s = difflib.SequenceMatcher(None, leftlines, rightlines) 736 s = difflib.SequenceMatcher(None, leftlines, rightlines)
646 if contextnum < 0: 737 if contextnum < 0:
649 else: 740 else:
650 for oc in s.get_grouped_opcodes(n=contextnum): 741 for oc in s.get_grouped_opcodes(n=contextnum):
651 l = _getcompblock(leftlines, rightlines, oc) 742 l = _getcompblock(leftlines, rightlines, oc)
652 yield {'lines': l} 743 yield {'lines': l}
653 744
745
654 def compare(contextnum, leftlines, rightlines): 746 def compare(contextnum, leftlines, rightlines):
655 args = (contextnum, leftlines, rightlines) 747 args = (contextnum, leftlines, rightlines)
656 return templateutil.mappinggenerator(_comparegen, args=args, 748 return templateutil.mappinggenerator(
657 name='comparisonblock') 749 _comparegen, args=args, name='comparisonblock'
750 )
751
658 752
659 def diffstatgen(ui, ctx, basectx): 753 def diffstatgen(ui, ctx, basectx):
660 '''Generator function that provides the diffstat data.''' 754 '''Generator function that provides the diffstat data.'''
661 755
662 diffopts = patch.diffopts(ui, {'noprefix': False}) 756 diffopts = patch.diffopts(ui, {'noprefix': False})
663 stats = patch.diffstatdata( 757 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx, opts=diffopts)))
664 util.iterlines(ctx.diff(basectx, opts=diffopts)))
665 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats) 758 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
666 while True: 759 while True:
667 yield stats, maxname, maxtotal, addtotal, removetotal, binary 760 yield stats, maxname, maxtotal, addtotal, removetotal, binary
668 761
762
669 def diffsummary(statgen): 763 def diffsummary(statgen):
670 '''Return a short summary of the diff.''' 764 '''Return a short summary of the diff.'''
671 765
672 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen) 766 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
673 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % ( 767 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
674 len(stats), addtotal, removetotal) 768 len(stats),
769 addtotal,
770 removetotal,
771 )
772
675 773
676 def _diffstattmplgen(context, ctx, statgen, parity): 774 def _diffstattmplgen(context, ctx, statgen, parity):
677 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen) 775 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
678 files = ctx.files() 776 files = ctx.files()
679 777
685 fileno = 0 783 fileno = 0
686 for filename, adds, removes, isbinary in stats: 784 for filename, adds, removes, isbinary in stats:
687 template = 'diffstatlink' if filename in files else 'diffstatnolink' 785 template = 'diffstatlink' if filename in files else 'diffstatnolink'
688 total = adds + removes 786 total = adds + removes
689 fileno += 1 787 fileno += 1
690 yield context.process(template, { 788 yield context.process(
691 'node': ctx.hex(), 789 template,
692 'file': filename, 790 {
693 'fileno': fileno, 791 'node': ctx.hex(),
694 'total': total, 792 'file': filename,
695 'addpct': pct(adds), 793 'fileno': fileno,
696 'removepct': pct(removes), 794 'total': total,
697 'parity': next(parity), 795 'addpct': pct(adds),
698 }) 796 'removepct': pct(removes),
797 'parity': next(parity),
798 },
799 )
800
699 801
700 def diffstat(ctx, statgen, parity): 802 def diffstat(ctx, statgen, parity):
701 '''Return a diffstat template for each file in the diff.''' 803 '''Return a diffstat template for each file in the diff.'''
702 args = (ctx, statgen, parity) 804 args = (ctx, statgen, parity)
703 return templateutil.mappedgenerator(_diffstattmplgen, args=args) 805 return templateutil.mappedgenerator(_diffstattmplgen, args=args)
704 806
807
705 class sessionvars(templateutil.wrapped): 808 class sessionvars(templateutil.wrapped):
706 def __init__(self, vars, start='?'): 809 def __init__(self, vars, start='?'):
707 self._start = start 810 self._start = start
708 self._vars = vars 811 self._vars = vars
709 812
735 raise error.ParseError(_('not filterable')) 838 raise error.ParseError(_('not filterable'))
736 839
737 def itermaps(self, context): 840 def itermaps(self, context):
738 separator = self._start 841 separator = self._start
739 for key, value in sorted(self._vars.iteritems()): 842 for key, value in sorted(self._vars.iteritems()):
740 yield {'name': key, 843 yield {
741 'value': pycompat.bytestr(value), 844 'name': key,
742 'separator': separator, 845 'value': pycompat.bytestr(value),
846 'separator': separator,
743 } 847 }
744 separator = '&' 848 separator = '&'
745 849
746 def join(self, context, mapping, sep): 850 def join(self, context, mapping, sep):
747 # could be '{separator}{name}={value|urlescape}' 851 # could be '{separator}{name}={value|urlescape}'
753 def tobool(self, context, mapping): 857 def tobool(self, context, mapping):
754 return bool(self._vars) 858 return bool(self._vars)
755 859
756 def tovalue(self, context, mapping): 860 def tovalue(self, context, mapping):
757 return self._vars 861 return self._vars
862
758 863
759 class wsgiui(uimod.ui): 864 class wsgiui(uimod.ui):
760 # default termwidth breaks under mod_wsgi 865 # default termwidth breaks under mod_wsgi
761 def termwidth(self): 866 def termwidth(self):
762 return 80 867 return 80
868
763 869
764 def getwebsubs(repo): 870 def getwebsubs(repo):
765 websubtable = [] 871 websubtable = []
766 websubdefs = repo.ui.configitems('websub') 872 websubdefs = repo.ui.configitems('websub')
767 # we must maintain interhg backwards compatibility 873 # we must maintain interhg backwards compatibility
774 # identify portions of the pattern, taking care to avoid escaped 880 # identify portions of the pattern, taking care to avoid escaped
775 # delimiters. the replace format and flags are optional, but 881 # delimiters. the replace format and flags are optional, but
776 # delimiters are required. 882 # delimiters are required.
777 match = re.match( 883 match = re.match(
778 br'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$' 884 br'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
779 % (delim, delim, delim), pattern) 885 % (delim, delim, delim),
886 pattern,
887 )
780 if not match: 888 if not match:
781 repo.ui.warn(_("websub: invalid pattern for %s: %s\n") 889 repo.ui.warn(
782 % (key, pattern)) 890 _("websub: invalid pattern for %s: %s\n") % (key, pattern)
891 )
783 continue 892 continue
784 893
785 # we need to unescape the delimiter for regexp and format 894 # we need to unescape the delimiter for regexp and format
786 delim_re = re.compile(br'(?<!\\)\\%s' % delim) 895 delim_re = re.compile(br'(?<!\\)\\%s' % delim)
787 regexp = delim_re.sub(unesc, match.group(1)) 896 regexp = delim_re.sub(unesc, match.group(1))
796 905
797 try: 906 try:
798 regexp = re.compile(regexp, flags) 907 regexp = re.compile(regexp, flags)
799 websubtable.append((regexp, format)) 908 websubtable.append((regexp, format))
800 except re.error: 909 except re.error:
801 repo.ui.warn(_("websub: invalid regexp for %s: %s\n") 910 repo.ui.warn(
802 % (key, regexp)) 911 _("websub: invalid regexp for %s: %s\n") % (key, regexp)
912 )
803 return websubtable 913 return websubtable
804 914
915
805 def getgraphnode(repo, ctx): 916 def getgraphnode(repo, ctx):
806 return (templatekw.getgraphnodecurrent(repo, ctx) + 917 return templatekw.getgraphnodecurrent(
807 templatekw.getgraphnodesymbol(ctx)) 918 repo, ctx
919 ) + templatekw.getgraphnodesymbol(ctx)