Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/patch.py @ 3967:dccb83241dd0
patch: use contexts for diff
author | Benoit Boissinot <benoit.boissinot@ens-lyon.org> |
---|---|
date | Mon, 25 Dec 2006 17:43:49 +0100 |
parents | ba45041827a2 |
children | fff8a5345eb0 |
comparison
equal
deleted
inserted
replaced
3966:b4eaa68dea1b | 3967:dccb83241dd0 |
---|---|
5 # This software may be used and distributed according to the terms | 5 # This software may be used and distributed according to the terms |
6 # of the GNU General Public License, incorporated herein by reference. | 6 # of the GNU General Public License, incorporated herein by reference. |
7 | 7 |
8 from i18n import _ | 8 from i18n import _ |
9 from node import * | 9 from node import * |
10 import base85, cmdutil, mdiff, util | 10 import base85, cmdutil, mdiff, util, context, revlog |
11 import cStringIO, email.Parser, os, popen2, re, sha | 11 import cStringIO, email.Parser, os, popen2, re, sha |
12 import sys, tempfile, zlib | 12 import sys, tempfile, zlib |
13 | 13 |
14 # helper functions | 14 # helper functions |
15 | 15 |
434 fp = repo.ui | 434 fp = repo.ui |
435 | 435 |
436 if not node1: | 436 if not node1: |
437 node1 = repo.dirstate.parents()[0] | 437 node1 = repo.dirstate.parents()[0] |
438 | 438 |
439 clcache = {} | 439 ccache = {} |
440 def getchangelog(n): | 440 def getctx(r): |
441 if n not in clcache: | 441 if r not in ccache: |
442 clcache[n] = repo.changelog.read(n) | 442 ccache[r] = context.changectx(repo, r) |
443 return clcache[n] | 443 return ccache[r] |
444 mcache = {} | 444 |
445 def getmanifest(n): | 445 flcache = {} |
446 if n not in mcache: | 446 def getfilectx(f, ctx): |
447 mcache[n] = repo.manifest.read(n) | 447 flctx = ctx.filectx(f, filelog=flcache.get(f)) |
448 return mcache[n] | 448 if f not in flcache: |
449 fcache = {} | 449 flcache[f] = flctx._filelog |
450 def getfile(f): | 450 return flctx |
451 if f not in fcache: | |
452 fcache[f] = repo.file(f) | |
453 return fcache[f] | |
454 | 451 |
455 # reading the data for node1 early allows it to play nicely | 452 # reading the data for node1 early allows it to play nicely |
456 # with repo.status and the revlog cache. | 453 # with repo.status and the revlog cache. |
457 change = getchangelog(node1) | 454 ctx1 = context.changectx(repo, node1) |
458 mmap = getmanifest(change[0]) | 455 # force manifest reading |
459 date1 = util.datestr(change[2]) | 456 man1 = ctx1.manifest() |
457 date1 = util.datestr(ctx1.date()) | |
460 | 458 |
461 if not changes: | 459 if not changes: |
462 changes = repo.status(node1, node2, files, match=match)[:5] | 460 changes = repo.status(node1, node2, files, match=match)[:5] |
463 modified, added, removed, deleted, unknown = changes | 461 modified, added, removed, deleted, unknown = changes |
464 if files: | 462 if files: |
474 modified, added, removed = map(filterfiles, (modified, added, removed)) | 472 modified, added, removed = map(filterfiles, (modified, added, removed)) |
475 | 473 |
476 if not modified and not added and not removed: | 474 if not modified and not added and not removed: |
477 return | 475 return |
478 | 476 |
479 # returns False if there was no rename between n1 and n2 | 477 if node2: |
480 # returns None if the file was created between n1 and n2 | 478 ctx2 = context.changectx(repo, node2) |
481 # returns the (file, node) present in n1 that was renamed to f in n2 | 479 else: |
482 def renamedbetween(f, n1, n2): | 480 ctx2 = context.workingctx(repo) |
483 r1, r2 = map(repo.changelog.rev, (n1, n2)) | 481 man2 = ctx2.manifest() |
482 | |
483 # returns False if there was no rename between ctx1 and ctx2 | |
484 # returns None if the file was created between ctx1 and ctx2 | |
485 # returns the (file, node) present in ctx1 that was renamed to f in ctx2 | |
486 def renamed(f): | |
487 startrev = ctx1.rev() | |
488 c = ctx2 | |
489 crev = c.rev() | |
490 if crev is None: | |
491 crev = repo.changelog.count() | |
484 orig = f | 492 orig = f |
485 src = None | 493 while crev > startrev: |
486 while r2 > r1: | 494 if f in c.files(): |
487 cl = getchangelog(n2) | |
488 if f in cl[3]: | |
489 m = getmanifest(cl[0]) | |
490 try: | 495 try: |
491 src = getfile(f).renamed(m[f]) | 496 src = getfilectx(f, c).renamed() |
492 except KeyError: | 497 except revlog.LookupError: |
493 return None | 498 return None |
494 if src: | 499 if src: |
495 f = src[0] | 500 f = src[0] |
496 n2 = repo.changelog.parents(n2)[0] | 501 crev = c.parents()[0].rev() |
497 r2 = repo.changelog.rev(n2) | 502 # try to reuse |
498 cl = getchangelog(n1) | 503 c = getctx(crev) |
499 m = getmanifest(cl[0]) | 504 if f not in man1: |
500 if f not in m: | |
501 return None | 505 return None |
502 if f == orig: | 506 if f == orig: |
503 return False | 507 return False |
504 return f, m[f] | 508 return f |
505 | |
506 if node2: | |
507 change = getchangelog(node2) | |
508 mmap2 = getmanifest(change[0]) | |
509 _date2 = util.datestr(change[2]) | |
510 def date2(f): | |
511 return _date2 | |
512 def read(f): | |
513 return getfile(f).read(mmap2[f]) | |
514 def renamed(f): | |
515 return renamedbetween(f, node1, node2) | |
516 else: | |
517 tz = util.makedate()[1] | |
518 _date2 = util.datestr() | |
519 def date2(f): | |
520 try: | |
521 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz)) | |
522 except OSError, err: | |
523 if err.errno != errno.ENOENT: raise | |
524 return _date2 | |
525 def read(f): | |
526 return repo.wread(f) | |
527 def renamed(f): | |
528 src = repo.dirstate.copied(f) | |
529 parent = repo.dirstate.parents()[0] | |
530 if src: | |
531 f = src | |
532 of = renamedbetween(f, node1, parent) | |
533 if of or of is None: | |
534 return of | |
535 elif src: | |
536 cl = getchangelog(parent)[0] | |
537 return (src, getmanifest(cl)[src]) | |
538 else: | |
539 return None | |
540 | 509 |
541 if repo.ui.quiet: | 510 if repo.ui.quiet: |
542 r = None | 511 r = None |
543 else: | 512 else: |
544 hexfunc = repo.ui.debugflag and hex or short | 513 hexfunc = repo.ui.debugflag and hex or short |
548 copied = {} | 517 copied = {} |
549 for f in added: | 518 for f in added: |
550 src = renamed(f) | 519 src = renamed(f) |
551 if src: | 520 if src: |
552 copied[f] = src | 521 copied[f] = src |
553 srcs = [x[1][0] for x in copied.items()] | 522 srcs = [x[1] for x in copied.items()] |
554 | 523 |
555 all = modified + added + removed | 524 all = modified + added + removed |
556 all.sort() | 525 all.sort() |
557 gone = {} | 526 gone = {} |
558 for f in all: | 527 for f in all: |
559 to = None | 528 to = None |
560 tn = None | 529 tn = None |
561 dodiff = True | 530 dodiff = True |
562 header = [] | 531 header = [] |
563 if f in mmap: | 532 if f in man1: |
564 to = getfile(f).read(mmap[f]) | 533 to = getfilectx(f, ctx1).data() |
565 if f not in removed: | 534 if f not in removed: |
566 tn = read(f) | 535 tn = getfilectx(f, ctx2).data() |
567 if opts.git: | 536 if opts.git: |
568 def gitmode(x): | 537 def gitmode(x): |
569 return x and '100755' or '100644' | 538 return x and '100755' or '100644' |
570 def addmodehdr(header, omode, nmode): | 539 def addmodehdr(header, omode, nmode): |
571 if omode != nmode: | 540 if omode != nmode: |
572 header.append('old mode %s\n' % omode) | 541 header.append('old mode %s\n' % omode) |
573 header.append('new mode %s\n' % nmode) | 542 header.append('new mode %s\n' % nmode) |
574 | 543 |
575 a, b = f, f | 544 a, b = f, f |
576 if f in added: | 545 if f in added: |
577 if node2: | 546 mode = gitmode(man2.execf(f)) |
578 mode = gitmode(mmap2.execf(f)) | |
579 else: | |
580 mode = gitmode(util.is_exec(repo.wjoin(f), None)) | |
581 if f in copied: | 547 if f in copied: |
582 a, arev = copied[f] | 548 a = copied[f] |
583 omode = gitmode(mmap.execf(a)) | 549 omode = gitmode(man1.execf(a)) |
584 addmodehdr(header, omode, mode) | 550 addmodehdr(header, omode, mode) |
585 if a in removed and a not in gone: | 551 if a in removed and a not in gone: |
586 op = 'rename' | 552 op = 'rename' |
587 gone[a] = 1 | 553 gone[a] = 1 |
588 else: | 554 else: |
589 op = 'copy' | 555 op = 'copy' |
590 header.append('%s from %s\n' % (op, a)) | 556 header.append('%s from %s\n' % (op, a)) |
591 header.append('%s to %s\n' % (op, f)) | 557 header.append('%s to %s\n' % (op, f)) |
592 to = getfile(a).read(arev) | 558 to = getfilectx(a, ctx1).data() |
593 else: | 559 else: |
594 header.append('new file mode %s\n' % mode) | 560 header.append('new file mode %s\n' % mode) |
595 if util.binary(tn): | 561 if util.binary(tn): |
596 dodiff = 'binary' | 562 dodiff = 'binary' |
597 elif f in removed: | 563 elif f in removed: |
598 if f in srcs: | 564 if f in srcs: |
599 dodiff = False | 565 dodiff = False |
600 else: | 566 else: |
601 mode = gitmode(mmap.execf(f)) | 567 mode = gitmode(man1.execf(f)) |
602 header.append('deleted file mode %s\n' % mode) | 568 header.append('deleted file mode %s\n' % mode) |
603 else: | 569 else: |
604 omode = gitmode(mmap.execf(f)) | 570 omode = gitmode(man1.execf(f)) |
605 if node2: | 571 nmode = gitmode(man2.execf(f)) |
606 nmode = gitmode(mmap2.execf(f)) | |
607 else: | |
608 nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f))) | |
609 addmodehdr(header, omode, nmode) | 572 addmodehdr(header, omode, nmode) |
610 if util.binary(to) or util.binary(tn): | 573 if util.binary(to) or util.binary(tn): |
611 dodiff = 'binary' | 574 dodiff = 'binary' |
612 r = None | 575 r = None |
613 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b)) | 576 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b)) |
614 if dodiff == 'binary': | 577 if dodiff == 'binary': |
615 fp.write(''.join(header)) | 578 fp.write(''.join(header)) |
616 b85diff(fp, to, tn) | 579 b85diff(fp, to, tn) |
617 elif dodiff: | 580 elif dodiff: |
618 text = mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts) | 581 text = mdiff.unidiff(to, date1, |
582 # ctx2 date may be dynamic | |
583 tn, util.datestr(ctx2.date()), | |
584 f, r, opts=opts) | |
619 if text or len(header) > 1: | 585 if text or len(header) > 1: |
620 fp.write(''.join(header)) | 586 fp.write(''.join(header)) |
621 fp.write(text) | 587 fp.write(text) |
622 | 588 |
623 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False, | 589 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False, |