43 |
43 |
44 from ..utils import stringutil |
44 from ..utils import stringutil |
45 |
45 |
46 archivespecs = util.sortdict( |
46 archivespecs = util.sortdict( |
47 ( |
47 ( |
48 ('zip', ('application/zip', 'zip', '.zip', None)), |
48 (b'zip', (b'application/zip', b'zip', b'.zip', None)), |
49 ('gz', ('application/x-gzip', 'tgz', '.tar.gz', None)), |
49 (b'gz', (b'application/x-gzip', b'tgz', b'.tar.gz', None)), |
50 ('bz2', ('application/x-bzip2', 'tbz2', '.tar.bz2', None)), |
50 (b'bz2', (b'application/x-bzip2', b'tbz2', b'.tar.bz2', None)), |
51 ) |
51 ) |
52 ) |
52 ) |
53 |
53 |
54 |
54 |
55 def archivelist(ui, nodeid, url=None): |
55 def archivelist(ui, nodeid, url=None): |
56 allowed = ui.configlist('web', 'allow-archive', untrusted=True) |
56 allowed = ui.configlist(b'web', b'allow-archive', untrusted=True) |
57 archives = [] |
57 archives = [] |
58 |
58 |
59 for typ, spec in archivespecs.iteritems(): |
59 for typ, spec in archivespecs.iteritems(): |
60 if typ in allowed or ui.configbool( |
60 if typ in allowed or ui.configbool( |
61 'web', 'allow' + typ, untrusted=True |
61 b'web', b'allow' + typ, untrusted=True |
62 ): |
62 ): |
63 archives.append( |
63 archives.append( |
64 {'type': typ, 'extension': spec[2], 'node': nodeid, 'url': url,} |
64 { |
|
65 b'type': typ, |
|
66 b'extension': spec[2], |
|
67 b'node': nodeid, |
|
68 b'url': url, |
|
69 } |
65 ) |
70 ) |
66 |
71 |
67 return templateutil.mappinglist(archives) |
72 return templateutil.mappinglist(archives) |
68 |
73 |
69 |
74 |
70 def up(p): |
75 def up(p): |
71 if p[0:1] != "/": |
76 if p[0:1] != b"/": |
72 p = "/" + p |
77 p = b"/" + p |
73 if p[-1:] == "/": |
78 if p[-1:] == b"/": |
74 p = p[:-1] |
79 p = p[:-1] |
75 up = os.path.dirname(p) |
80 up = os.path.dirname(p) |
76 if up == "/": |
81 if up == b"/": |
77 return "/" |
82 return b"/" |
78 return up + "/" |
83 return up + b"/" |
79 |
84 |
80 |
85 |
81 def _navseq(step, firststep=None): |
86 def _navseq(step, firststep=None): |
82 if firststep: |
87 if firststep: |
83 yield firststep |
88 yield firststep |
275 branchnode = repo.branchtip(branch) |
285 branchnode = repo.branchtip(branch) |
276 except error.RepoLookupError: |
286 except error.RepoLookupError: |
277 branchnode = None |
287 branchnode = None |
278 if branchnode == ctx.node(): |
288 if branchnode == ctx.node(): |
279 branches.append(branch) |
289 branches.append(branch) |
280 return templateutil.hybridlist(branches, name='name') |
290 return templateutil.hybridlist(branches, name=b'name') |
281 |
291 |
282 |
292 |
283 def nodeinbranch(repo, ctx): |
293 def nodeinbranch(repo, ctx): |
284 branches = [] |
294 branches = [] |
285 branch = ctx.branch() |
295 branch = ctx.branch() |
286 try: |
296 try: |
287 branchnode = repo.branchtip(branch) |
297 branchnode = repo.branchtip(branch) |
288 except error.RepoLookupError: |
298 except error.RepoLookupError: |
289 branchnode = None |
299 branchnode = None |
290 if branch != 'default' and branchnode != ctx.node(): |
300 if branch != b'default' and branchnode != ctx.node(): |
291 branches.append(branch) |
301 branches.append(branch) |
292 return templateutil.hybridlist(branches, name='name') |
302 return templateutil.hybridlist(branches, name=b'name') |
293 |
303 |
294 |
304 |
295 def nodebranchnodefault(ctx): |
305 def nodebranchnodefault(ctx): |
296 branches = [] |
306 branches = [] |
297 branch = ctx.branch() |
307 branch = ctx.branch() |
298 if branch != 'default': |
308 if branch != b'default': |
299 branches.append(branch) |
309 branches.append(branch) |
300 return templateutil.hybridlist(branches, name='name') |
310 return templateutil.hybridlist(branches, name=b'name') |
301 |
311 |
302 |
312 |
303 def _nodenamesgen(context, f, node, name): |
313 def _nodenamesgen(context, f, node, name): |
304 for t in f(node): |
314 for t in f(node): |
305 yield {name: t} |
315 yield {name: t} |
306 |
316 |
307 |
317 |
308 def showtag(repo, t1, node=nullid): |
318 def showtag(repo, t1, node=nullid): |
309 args = (repo.nodetags, node, 'tag') |
319 args = (repo.nodetags, node, b'tag') |
310 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1) |
320 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1) |
311 |
321 |
312 |
322 |
313 def showbookmark(repo, t1, node=nullid): |
323 def showbookmark(repo, t1, node=nullid): |
314 args = (repo.nodebookmarks, node, 'bookmark') |
324 args = (repo.nodebookmarks, node, b'bookmark') |
315 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1) |
325 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1) |
316 |
326 |
317 |
327 |
318 def branchentries(repo, stripecount, limit=0): |
328 def branchentries(repo, stripecount, limit=0): |
319 tips = [] |
329 tips = [] |
329 for ctx, closed in sorted(tips, key=sortkey, reverse=True): |
339 for ctx, closed in sorted(tips, key=sortkey, reverse=True): |
330 if limit > 0 and count >= limit: |
340 if limit > 0 and count >= limit: |
331 return |
341 return |
332 count += 1 |
342 count += 1 |
333 if closed: |
343 if closed: |
334 status = 'closed' |
344 status = b'closed' |
335 elif ctx.node() not in heads: |
345 elif ctx.node() not in heads: |
336 status = 'inactive' |
346 status = b'inactive' |
337 else: |
347 else: |
338 status = 'open' |
348 status = b'open' |
339 yield { |
349 yield { |
340 'parity': next(parity), |
350 b'parity': next(parity), |
341 'branch': ctx.branch(), |
351 b'branch': ctx.branch(), |
342 'status': status, |
352 b'status': status, |
343 'node': ctx.hex(), |
353 b'node': ctx.hex(), |
344 'date': ctx.date(), |
354 b'date': ctx.date(), |
345 } |
355 } |
346 |
356 |
347 return templateutil.mappinggenerator(entries) |
357 return templateutil.mappinggenerator(entries) |
348 |
358 |
349 |
359 |
350 def cleanpath(repo, path): |
360 def cleanpath(repo, path): |
351 path = path.lstrip('/') |
361 path = path.lstrip(b'/') |
352 auditor = pathutil.pathauditor(repo.root, realfs=False) |
362 auditor = pathutil.pathauditor(repo.root, realfs=False) |
353 return pathutil.canonpath(repo.root, '', path, auditor=auditor) |
363 return pathutil.canonpath(repo.root, b'', path, auditor=auditor) |
354 |
364 |
355 |
365 |
356 def changectx(repo, req): |
366 def changectx(repo, req): |
357 changeid = "tip" |
367 changeid = b"tip" |
358 if 'node' in req.qsparams: |
368 if b'node' in req.qsparams: |
359 changeid = req.qsparams['node'] |
369 changeid = req.qsparams[b'node'] |
360 ipos = changeid.find(':') |
370 ipos = changeid.find(b':') |
361 if ipos != -1: |
371 if ipos != -1: |
362 changeid = changeid[(ipos + 1) :] |
372 changeid = changeid[(ipos + 1) :] |
363 |
373 |
364 return scmutil.revsymbol(repo, changeid) |
374 return scmutil.revsymbol(repo, changeid) |
365 |
375 |
366 |
376 |
367 def basechangectx(repo, req): |
377 def basechangectx(repo, req): |
368 if 'node' in req.qsparams: |
378 if b'node' in req.qsparams: |
369 changeid = req.qsparams['node'] |
379 changeid = req.qsparams[b'node'] |
370 ipos = changeid.find(':') |
380 ipos = changeid.find(b':') |
371 if ipos != -1: |
381 if ipos != -1: |
372 changeid = changeid[:ipos] |
382 changeid = changeid[:ipos] |
373 return scmutil.revsymbol(repo, changeid) |
383 return scmutil.revsymbol(repo, changeid) |
374 |
384 |
375 return None |
385 return None |
376 |
386 |
377 |
387 |
378 def filectx(repo, req): |
388 def filectx(repo, req): |
379 if 'file' not in req.qsparams: |
389 if b'file' not in req.qsparams: |
380 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given') |
390 raise ErrorResponse(HTTP_NOT_FOUND, b'file not given') |
381 path = cleanpath(repo, req.qsparams['file']) |
391 path = cleanpath(repo, req.qsparams[b'file']) |
382 if 'node' in req.qsparams: |
392 if b'node' in req.qsparams: |
383 changeid = req.qsparams['node'] |
393 changeid = req.qsparams[b'node'] |
384 elif 'filenode' in req.qsparams: |
394 elif b'filenode' in req.qsparams: |
385 changeid = req.qsparams['filenode'] |
395 changeid = req.qsparams[b'filenode'] |
386 else: |
396 else: |
387 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given') |
397 raise ErrorResponse(HTTP_NOT_FOUND, b'node or filenode not given') |
388 try: |
398 try: |
389 fctx = scmutil.revsymbol(repo, changeid)[path] |
399 fctx = scmutil.revsymbol(repo, changeid)[path] |
390 except error.RepoError: |
400 except error.RepoError: |
391 fctx = repo.filectx(path, fileid=changeid) |
401 fctx = repo.filectx(path, fileid=changeid) |
392 |
402 |
393 return fctx |
403 return fctx |
394 |
404 |
395 |
405 |
396 def linerange(req): |
406 def linerange(req): |
397 linerange = req.qsparams.getall('linerange') |
407 linerange = req.qsparams.getall(b'linerange') |
398 if not linerange: |
408 if not linerange: |
399 return None |
409 return None |
400 if len(linerange) > 1: |
410 if len(linerange) > 1: |
401 raise ErrorResponse(HTTP_BAD_REQUEST, 'redundant linerange parameter') |
411 raise ErrorResponse(HTTP_BAD_REQUEST, b'redundant linerange parameter') |
402 try: |
412 try: |
403 fromline, toline = map(int, linerange[0].split(':', 1)) |
413 fromline, toline = map(int, linerange[0].split(b':', 1)) |
404 except ValueError: |
414 except ValueError: |
405 raise ErrorResponse(HTTP_BAD_REQUEST, 'invalid linerange parameter') |
415 raise ErrorResponse(HTTP_BAD_REQUEST, b'invalid linerange parameter') |
406 try: |
416 try: |
407 return util.processlinerange(fromline, toline) |
417 return util.processlinerange(fromline, toline) |
408 except error.ParseError as exc: |
418 except error.ParseError as exc: |
409 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc)) |
419 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc)) |
410 |
420 |
411 |
421 |
412 def formatlinerange(fromline, toline): |
422 def formatlinerange(fromline, toline): |
413 return '%d:%d' % (fromline + 1, toline) |
423 return b'%d:%d' % (fromline + 1, toline) |
414 |
424 |
415 |
425 |
416 def _succsandmarkersgen(context, mapping): |
426 def _succsandmarkersgen(context, mapping): |
417 repo = context.resource(mapping, 'repo') |
427 repo = context.resource(mapping, b'repo') |
418 itemmappings = templatekw.showsuccsandmarkers(context, mapping) |
428 itemmappings = templatekw.showsuccsandmarkers(context, mapping) |
419 for item in itemmappings.tovalue(context, mapping): |
429 for item in itemmappings.tovalue(context, mapping): |
420 item['successors'] = _siblings( |
430 item[b'successors'] = _siblings( |
421 repo[successor] for successor in item['successors'] |
431 repo[successor] for successor in item[b'successors'] |
422 ) |
432 ) |
423 yield item |
433 yield item |
424 |
434 |
425 |
435 |
426 def succsandmarkers(context, mapping): |
436 def succsandmarkers(context, mapping): |
427 return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,)) |
437 return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,)) |
428 |
438 |
429 |
439 |
430 # teach templater succsandmarkers is switched to (context, mapping) API |
440 # teach templater succsandmarkers is switched to (context, mapping) API |
431 succsandmarkers._requires = {'repo', 'ctx'} |
441 succsandmarkers._requires = {b'repo', b'ctx'} |
432 |
442 |
433 |
443 |
434 def _whyunstablegen(context, mapping): |
444 def _whyunstablegen(context, mapping): |
435 repo = context.resource(mapping, 'repo') |
445 repo = context.resource(mapping, b'repo') |
436 ctx = context.resource(mapping, 'ctx') |
446 ctx = context.resource(mapping, b'ctx') |
437 |
447 |
438 entries = obsutil.whyunstable(repo, ctx) |
448 entries = obsutil.whyunstable(repo, ctx) |
439 for entry in entries: |
449 for entry in entries: |
440 if entry.get('divergentnodes'): |
450 if entry.get(b'divergentnodes'): |
441 entry['divergentnodes'] = _siblings(entry['divergentnodes']) |
451 entry[b'divergentnodes'] = _siblings(entry[b'divergentnodes']) |
442 yield entry |
452 yield entry |
443 |
453 |
444 |
454 |
445 def whyunstable(context, mapping): |
455 def whyunstable(context, mapping): |
446 return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,)) |
456 return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,)) |
447 |
457 |
448 |
458 |
449 whyunstable._requires = {'repo', 'ctx'} |
459 whyunstable._requires = {b'repo', b'ctx'} |
450 |
460 |
451 |
461 |
452 def commonentry(repo, ctx): |
462 def commonentry(repo, ctx): |
453 node = scmutil.binnode(ctx) |
463 node = scmutil.binnode(ctx) |
454 return { |
464 return { |
455 # TODO: perhaps ctx.changectx() should be assigned if ctx is a |
465 # TODO: perhaps ctx.changectx() should be assigned if ctx is a |
456 # filectx, but I'm not pretty sure if that would always work because |
466 # filectx, but I'm not pretty sure if that would always work because |
457 # fctx.parents() != fctx.changectx.parents() for example. |
467 # fctx.parents() != fctx.changectx.parents() for example. |
458 'ctx': ctx, |
468 b'ctx': ctx, |
459 'rev': ctx.rev(), |
469 b'rev': ctx.rev(), |
460 'node': hex(node), |
470 b'node': hex(node), |
461 'author': ctx.user(), |
471 b'author': ctx.user(), |
462 'desc': ctx.description(), |
472 b'desc': ctx.description(), |
463 'date': ctx.date(), |
473 b'date': ctx.date(), |
464 'extra': ctx.extra(), |
474 b'extra': ctx.extra(), |
465 'phase': ctx.phasestr(), |
475 b'phase': ctx.phasestr(), |
466 'obsolete': ctx.obsolete(), |
476 b'obsolete': ctx.obsolete(), |
467 'succsandmarkers': succsandmarkers, |
477 b'succsandmarkers': succsandmarkers, |
468 'instabilities': templateutil.hybridlist( |
478 b'instabilities': templateutil.hybridlist( |
469 ctx.instabilities(), name='instability' |
479 ctx.instabilities(), name=b'instability' |
470 ), |
480 ), |
471 'whyunstable': whyunstable, |
481 b'whyunstable': whyunstable, |
472 'branch': nodebranchnodefault(ctx), |
482 b'branch': nodebranchnodefault(ctx), |
473 'inbranch': nodeinbranch(repo, ctx), |
483 b'inbranch': nodeinbranch(repo, ctx), |
474 'branches': nodebranchdict(repo, ctx), |
484 b'branches': nodebranchdict(repo, ctx), |
475 'tags': nodetagsdict(repo, node), |
485 b'tags': nodetagsdict(repo, node), |
476 'bookmarks': nodebookmarksdict(repo, node), |
486 b'bookmarks': nodebookmarksdict(repo, node), |
477 'parent': lambda context, mapping: parents(ctx), |
487 b'parent': lambda context, mapping: parents(ctx), |
478 'child': lambda context, mapping: children(ctx), |
488 b'child': lambda context, mapping: children(ctx), |
479 } |
489 } |
480 |
490 |
481 |
491 |
482 def changelistentry(web, ctx): |
492 def changelistentry(web, ctx): |
483 '''Obtain a dictionary to be used for entries in a changelist. |
493 '''Obtain a dictionary to be used for entries in a changelist. |
514 break |
524 break |
515 |
525 |
516 count += 1 |
526 count += 1 |
517 |
527 |
518 entry = changelistentry(web, repo[rev]) |
528 entry = changelistentry(web, repo[rev]) |
519 entry['parity'] = next(parityfn) |
529 entry[b'parity'] = next(parityfn) |
520 |
530 |
521 yield entry |
531 yield entry |
522 |
532 |
523 |
533 |
524 def symrevorshortnode(req, ctx): |
534 def symrevorshortnode(req, ctx): |
525 if 'node' in req.qsparams: |
535 if b'node' in req.qsparams: |
526 return templatefilters.revescape(req.qsparams['node']) |
536 return templatefilters.revescape(req.qsparams[b'node']) |
527 else: |
537 else: |
528 return short(scmutil.binnode(ctx)) |
538 return short(scmutil.binnode(ctx)) |
529 |
539 |
530 |
540 |
531 def _listfilesgen(context, ctx, stripecount): |
541 def _listfilesgen(context, ctx, stripecount): |
532 parity = paritygen(stripecount) |
542 parity = paritygen(stripecount) |
533 for blockno, f in enumerate(ctx.files()): |
543 for blockno, f in enumerate(ctx.files()): |
534 template = 'filenodelink' if f in ctx else 'filenolink' |
544 template = b'filenodelink' if f in ctx else b'filenolink' |
535 yield context.process( |
545 yield context.process( |
536 template, |
546 template, |
537 { |
547 { |
538 'node': ctx.hex(), |
548 b'node': ctx.hex(), |
539 'file': f, |
549 b'file': f, |
540 'blockno': blockno + 1, |
550 b'blockno': blockno + 1, |
541 'parity': next(parity), |
551 b'parity': next(parity), |
542 }, |
552 }, |
543 ) |
553 ) |
544 |
554 |
545 |
555 |
546 def changesetentry(web, ctx): |
556 def changesetentry(web, ctx): |
547 '''Obtain a dictionary to be used to render the "changeset" template.''' |
557 '''Obtain a dictionary to be used to render the "changeset" template.''' |
548 |
558 |
549 showtags = showtag(web.repo, 'changesettag', scmutil.binnode(ctx)) |
559 showtags = showtag(web.repo, b'changesettag', scmutil.binnode(ctx)) |
550 showbookmarks = showbookmark( |
560 showbookmarks = showbookmark( |
551 web.repo, 'changesetbookmark', scmutil.binnode(ctx) |
561 web.repo, b'changesetbookmark', scmutil.binnode(ctx) |
552 ) |
562 ) |
553 showbranch = nodebranchnodefault(ctx) |
563 showbranch = nodebranchnodefault(ctx) |
554 |
564 |
555 basectx = basechangectx(web.repo, web.req) |
565 basectx = basechangectx(web.repo, web.req) |
556 if basectx is None: |
566 if basectx is None: |
557 basectx = ctx.p1() |
567 basectx = ctx.p1() |
558 |
568 |
559 style = web.config('web', 'style') |
569 style = web.config(b'web', b'style') |
560 if 'style' in web.req.qsparams: |
570 if b'style' in web.req.qsparams: |
561 style = web.req.qsparams['style'] |
571 style = web.req.qsparams[b'style'] |
562 |
572 |
563 diff = diffs(web, ctx, basectx, None, style) |
573 diff = diffs(web, ctx, basectx, None, style) |
564 |
574 |
565 parity = paritygen(web.stripecount) |
575 parity = paritygen(web.stripecount) |
566 diffstatsgen = diffstatgen(web.repo.ui, ctx, basectx) |
576 diffstatsgen = diffstatgen(web.repo.ui, ctx, basectx) |
583 ) |
593 ) |
584 |
594 |
585 |
595 |
586 def _listfilediffsgen(context, files, node, max): |
596 def _listfilediffsgen(context, files, node, max): |
587 for f in files[:max]: |
597 for f in files[:max]: |
588 yield context.process('filedifflink', {'node': hex(node), 'file': f}) |
598 yield context.process(b'filedifflink', {b'node': hex(node), b'file': f}) |
589 if len(files) > max: |
599 if len(files) > max: |
590 yield context.process('fileellipses', {}) |
600 yield context.process(b'fileellipses', {}) |
591 |
601 |
592 |
602 |
593 def listfilediffs(files, node, max): |
603 def listfilediffs(files, node, max): |
594 return templateutil.mappedgenerator( |
604 return templateutil.mappedgenerator( |
595 _listfilediffsgen, args=(files, node, max) |
605 _listfilediffsgen, args=(files, node, max) |
596 ) |
606 ) |
597 |
607 |
598 |
608 |
599 def _prettyprintdifflines(context, lines, blockno, lineidprefix): |
609 def _prettyprintdifflines(context, lines, blockno, lineidprefix): |
600 for lineno, l in enumerate(lines, 1): |
610 for lineno, l in enumerate(lines, 1): |
601 difflineno = "%d.%d" % (blockno, lineno) |
611 difflineno = b"%d.%d" % (blockno, lineno) |
602 if l.startswith('+'): |
612 if l.startswith(b'+'): |
603 ltype = "difflineplus" |
613 ltype = b"difflineplus" |
604 elif l.startswith('-'): |
614 elif l.startswith(b'-'): |
605 ltype = "difflineminus" |
615 ltype = b"difflineminus" |
606 elif l.startswith('@'): |
616 elif l.startswith(b'@'): |
607 ltype = "difflineat" |
617 ltype = b"difflineat" |
608 else: |
618 else: |
609 ltype = "diffline" |
619 ltype = b"diffline" |
610 yield context.process( |
620 yield context.process( |
611 ltype, |
621 ltype, |
612 { |
622 { |
613 'line': l, |
623 b'line': l, |
614 'lineno': lineno, |
624 b'lineno': lineno, |
615 'lineid': lineidprefix + "l%s" % difflineno, |
625 b'lineid': lineidprefix + b"l%s" % difflineno, |
616 'linenumber': "% 8s" % difflineno, |
626 b'linenumber': b"% 8s" % difflineno, |
617 }, |
627 }, |
618 ) |
628 ) |
619 |
629 |
620 |
630 |
621 def _diffsgen( |
631 def _diffsgen( |
651 if lines: |
661 if lines: |
652 l = templateutil.mappedgenerator( |
662 l = templateutil.mappedgenerator( |
653 _prettyprintdifflines, args=(lines, blockno, lineidprefix) |
663 _prettyprintdifflines, args=(lines, blockno, lineidprefix) |
654 ) |
664 ) |
655 yield { |
665 yield { |
656 'parity': next(parity), |
666 b'parity': next(parity), |
657 'blockno': blockno, |
667 b'blockno': blockno, |
658 'lines': l, |
668 b'lines': l, |
659 } |
669 } |
660 |
670 |
661 |
671 |
662 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=''): |
672 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=b''): |
663 args = ( |
673 args = ( |
664 web.repo, |
674 web.repo, |
665 ctx, |
675 ctx, |
666 basectx, |
676 basectx, |
667 files, |
677 files, |
668 style, |
678 style, |
669 web.stripecount, |
679 web.stripecount, |
670 linerange, |
680 linerange, |
671 lineidprefix, |
681 lineidprefix, |
672 ) |
682 ) |
673 return templateutil.mappinggenerator(_diffsgen, args=args, name='diffblock') |
683 return templateutil.mappinggenerator( |
|
684 _diffsgen, args=args, name=b'diffblock' |
|
685 ) |
674 |
686 |
675 |
687 |
676 def _compline(type, leftlineno, leftline, rightlineno, rightline): |
688 def _compline(type, leftlineno, leftline, rightlineno, rightline): |
677 lineid = leftlineno and ("l%d" % leftlineno) or '' |
689 lineid = leftlineno and (b"l%d" % leftlineno) or b'' |
678 lineid += rightlineno and ("r%d" % rightlineno) or '' |
690 lineid += rightlineno and (b"r%d" % rightlineno) or b'' |
679 llno = '%d' % leftlineno if leftlineno else '' |
691 llno = b'%d' % leftlineno if leftlineno else b'' |
680 rlno = '%d' % rightlineno if rightlineno else '' |
692 rlno = b'%d' % rightlineno if rightlineno else b'' |
681 return { |
693 return { |
682 'type': type, |
694 b'type': type, |
683 'lineid': lineid, |
695 b'lineid': lineid, |
684 'leftlineno': leftlineno, |
696 b'leftlineno': leftlineno, |
685 'leftlinenumber': "% 6s" % llno, |
697 b'leftlinenumber': b"% 6s" % llno, |
686 'leftline': leftline or '', |
698 b'leftline': leftline or b'', |
687 'rightlineno': rightlineno, |
699 b'rightlineno': rightlineno, |
688 'rightlinenumber': "% 6s" % rlno, |
700 b'rightlinenumber': b"% 6s" % rlno, |
689 'rightline': rightline or '', |
701 b'rightline': rightline or b'', |
690 } |
702 } |
691 |
703 |
692 |
704 |
693 def _getcompblockgen(context, leftlines, rightlines, opcodes): |
705 def _getcompblockgen(context, leftlines, rightlines, opcodes): |
694 for type, llo, lhi, rlo, rhi in opcodes: |
706 for type, llo, lhi, rlo, rhi in opcodes: |
725 |
737 |
726 |
738 |
727 def _getcompblock(leftlines, rightlines, opcodes): |
739 def _getcompblock(leftlines, rightlines, opcodes): |
728 args = (leftlines, rightlines, opcodes) |
740 args = (leftlines, rightlines, opcodes) |
729 return templateutil.mappinggenerator( |
741 return templateutil.mappinggenerator( |
730 _getcompblockgen, args=args, name='comparisonline' |
742 _getcompblockgen, args=args, name=b'comparisonline' |
731 ) |
743 ) |
732 |
744 |
733 |
745 |
734 def _comparegen(context, contextnum, leftlines, rightlines): |
746 def _comparegen(context, contextnum, leftlines, rightlines): |
735 '''Generator function that provides side-by-side comparison data.''' |
747 '''Generator function that provides side-by-side comparison data.''' |
736 s = difflib.SequenceMatcher(None, leftlines, rightlines) |
748 s = difflib.SequenceMatcher(None, leftlines, rightlines) |
737 if contextnum < 0: |
749 if contextnum < 0: |
738 l = _getcompblock(leftlines, rightlines, s.get_opcodes()) |
750 l = _getcompblock(leftlines, rightlines, s.get_opcodes()) |
739 yield {'lines': l} |
751 yield {b'lines': l} |
740 else: |
752 else: |
741 for oc in s.get_grouped_opcodes(n=contextnum): |
753 for oc in s.get_grouped_opcodes(n=contextnum): |
742 l = _getcompblock(leftlines, rightlines, oc) |
754 l = _getcompblock(leftlines, rightlines, oc) |
743 yield {'lines': l} |
755 yield {b'lines': l} |
744 |
756 |
745 |
757 |
746 def compare(contextnum, leftlines, rightlines): |
758 def compare(contextnum, leftlines, rightlines): |
747 args = (contextnum, leftlines, rightlines) |
759 args = (contextnum, leftlines, rightlines) |
748 return templateutil.mappinggenerator( |
760 return templateutil.mappinggenerator( |
749 _comparegen, args=args, name='comparisonblock' |
761 _comparegen, args=args, name=b'comparisonblock' |
750 ) |
762 ) |
751 |
763 |
752 |
764 |
753 def diffstatgen(ui, ctx, basectx): |
765 def diffstatgen(ui, ctx, basectx): |
754 '''Generator function that provides the diffstat data.''' |
766 '''Generator function that provides the diffstat data.''' |
755 |
767 |
756 diffopts = patch.diffopts(ui, {'noprefix': False}) |
768 diffopts = patch.diffopts(ui, {b'noprefix': False}) |
757 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx, opts=diffopts))) |
769 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx, opts=diffopts))) |
758 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats) |
770 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats) |
759 while True: |
771 while True: |
760 yield stats, maxname, maxtotal, addtotal, removetotal, binary |
772 yield stats, maxname, maxtotal, addtotal, removetotal, binary |
761 |
773 |
762 |
774 |
763 def diffsummary(statgen): |
775 def diffsummary(statgen): |
764 '''Return a short summary of the diff.''' |
776 '''Return a short summary of the diff.''' |
765 |
777 |
766 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen) |
778 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen) |
767 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % ( |
779 return _(b' %d files changed, %d insertions(+), %d deletions(-)\n') % ( |
768 len(stats), |
780 len(stats), |
769 addtotal, |
781 addtotal, |
770 removetotal, |
782 removetotal, |
771 ) |
783 ) |
772 |
784 |
826 def getmember(self, context, mapping, key): |
838 def getmember(self, context, mapping, key): |
827 key = templateutil.unwrapvalue(context, mapping, key) |
839 key = templateutil.unwrapvalue(context, mapping, key) |
828 return self._vars.get(key) |
840 return self._vars.get(key) |
829 |
841 |
830 def getmin(self, context, mapping): |
842 def getmin(self, context, mapping): |
831 raise error.ParseError(_('not comparable')) |
843 raise error.ParseError(_(b'not comparable')) |
832 |
844 |
833 def getmax(self, context, mapping): |
845 def getmax(self, context, mapping): |
834 raise error.ParseError(_('not comparable')) |
846 raise error.ParseError(_(b'not comparable')) |
835 |
847 |
836 def filter(self, context, mapping, select): |
848 def filter(self, context, mapping, select): |
837 # implement if necessary |
849 # implement if necessary |
838 raise error.ParseError(_('not filterable')) |
850 raise error.ParseError(_(b'not filterable')) |
839 |
851 |
840 def itermaps(self, context): |
852 def itermaps(self, context): |
841 separator = self._start |
853 separator = self._start |
842 for key, value in sorted(self._vars.iteritems()): |
854 for key, value in sorted(self._vars.iteritems()): |
843 yield { |
855 yield { |
844 'name': key, |
856 b'name': key, |
845 'value': pycompat.bytestr(value), |
857 b'value': pycompat.bytestr(value), |
846 'separator': separator, |
858 b'separator': separator, |
847 } |
859 } |
848 separator = '&' |
860 separator = b'&' |
849 |
861 |
850 def join(self, context, mapping, sep): |
862 def join(self, context, mapping, sep): |
851 # could be '{separator}{name}={value|urlescape}' |
863 # could be '{separator}{name}={value|urlescape}' |
852 raise error.ParseError(_('not displayable without template')) |
864 raise error.ParseError(_(b'not displayable without template')) |
853 |
865 |
854 def show(self, context, mapping): |
866 def show(self, context, mapping): |
855 return self.join(context, '') |
867 return self.join(context, b'') |
856 |
868 |
857 def tobool(self, context, mapping): |
869 def tobool(self, context, mapping): |
858 return bool(self._vars) |
870 return bool(self._vars) |
859 |
871 |
860 def tovalue(self, context, mapping): |
872 def tovalue(self, context, mapping): |