Mercurial > hg > mercurial-crew-with-dirclash
comparison contrib/simplemerge @ 4360:d5c3a70f8422
polish the simplemerge command; add a test
author | Alexis S. L. Carvalho <alexis@cecm.usp.br> |
---|---|
date | Mon, 16 Apr 2007 20:17:39 -0300 |
parents | 2e3c54fb79a3 |
children | 1ef4445c6506 |
comparison
equal
deleted
inserted
replaced
4359:2e3c54fb79a3 | 4360:d5c3a70f8422 |
---|---|
17 | 17 |
18 | 18 |
19 # mbp: "you know that thing where cvs gives you conflict markers?" | 19 # mbp: "you know that thing where cvs gives you conflict markers?" |
20 # s: "i hate that." | 20 # s: "i hate that." |
21 | 21 |
22 | 22 from mercurial import demandimport |
23 from mercurial import util, mdiff | 23 demandimport.enable() |
24 | |
25 from mercurial import util, mdiff, fancyopts | |
24 from mercurial.i18n import _ | 26 from mercurial.i18n import _ |
25 | 27 |
26 | 28 |
27 class CantReprocessAndShowBase(Exception): | 29 class CantReprocessAndShowBase(Exception): |
28 pass | 30 pass |
95 end_marker='>>>>>>>', | 97 end_marker='>>>>>>>', |
96 base_marker=None, | 98 base_marker=None, |
97 reprocess=False): | 99 reprocess=False): |
98 """Return merge in cvs-like form. | 100 """Return merge in cvs-like form. |
99 """ | 101 """ |
102 self.conflicts = False | |
100 newline = '\n' | 103 newline = '\n' |
101 if len(self.a) > 0: | 104 if len(self.a) > 0: |
102 if self.a[0].endswith('\r\n'): | 105 if self.a[0].endswith('\r\n'): |
103 newline = '\r\n' | 106 newline = '\r\n' |
104 elif self.a[0].endswith('\r'): | 107 elif self.a[0].endswith('\r'): |
124 yield self.a[i] | 127 yield self.a[i] |
125 elif what == 'b': | 128 elif what == 'b': |
126 for i in range(t[1], t[2]): | 129 for i in range(t[1], t[2]): |
127 yield self.b[i] | 130 yield self.b[i] |
128 elif what == 'conflict': | 131 elif what == 'conflict': |
132 self.conflicts = True | |
129 yield start_marker + newline | 133 yield start_marker + newline |
130 for i in range(t[3], t[4]): | 134 for i in range(t[3], t[4]): |
131 yield self.a[i] | 135 yield self.a[i] |
132 if base_marker is not None: | 136 if base_marker is not None: |
133 yield base_marker + newline | 137 yield base_marker + newline |
437 if util.binary(basetext) or util.binary(atext) or util.binary(btext): | 441 if util.binary(basetext) or util.binary(atext) or util.binary(btext): |
438 raise util.Abort(_("don't know how to merge binary files")) | 442 raise util.Abort(_("don't know how to merge binary files")) |
439 Merge3Text.__init__(self, basetext, atext, btext, base, a, b) | 443 Merge3Text.__init__(self, basetext, atext, btext, base, a, b) |
440 | 444 |
441 | 445 |
446 def simplemerge(local, base, other, **opts): | |
447 def readfile(filename): | |
448 f = open(filename, "rb") | |
449 text = f.read() | |
450 f.close() | |
451 if util.binary(text): | |
452 msg = _("%s looks like a binary file.") % filename | |
453 if not opts.get('text'): | |
454 raise util.Abort(msg) | |
455 elif not opts.get('quiet'): | |
456 sys.stderr.write(_('warning: %s\n') % msg) | |
457 return text | |
458 | |
459 name_a = local | |
460 name_b = other | |
461 labels = opts.get('label', []) | |
462 if labels: | |
463 name_a = labels.pop(0) | |
464 if labels: | |
465 name_b = labels.pop(0) | |
466 if labels: | |
467 raise util.Abort(_("can only specify two labels.")) | |
468 | |
469 localtext = readfile(local) | |
470 basetext = readfile(base) | |
471 othertext = readfile(other) | |
472 | |
473 orig = local | |
474 local = os.path.realpath(local) | |
475 if not opts.get('print'): | |
476 opener = util.opener(os.path.dirname(local)) | |
477 out = opener(os.path.basename(local), "w", atomictemp=True) | |
478 else: | |
479 out = sys.stdout | |
480 | |
481 reprocess = not opts.get('no_minimal') | |
482 | |
483 m3 = Merge3Text(basetext, localtext, othertext) | |
484 for line in m3.merge_lines(name_a=name_a, name_b=name_b, | |
485 reprocess=reprocess): | |
486 out.write(line) | |
487 | |
488 if not opts.get('print'): | |
489 out.rename() | |
490 | |
491 if m3.conflicts: | |
492 if not opts.get('quiet'): | |
493 sys.stdout.flush() | |
494 sys.stderr.write(_("warning: conflicts during merge.\n")) | |
495 return 1 | |
496 | |
497 options = [('L', 'label', [], _('labels to use on conflict markers')), | |
498 ('a', 'text', None, _('treat all files as text')), | |
499 ('p', 'print', None, | |
500 _('print results instead of overwriting LOCAL')), | |
501 ('', 'no-minimal', None, | |
502 _('do not try to minimize conflict regions')), | |
503 ('h', 'help', None, _('display help and exit')), | |
504 ('q', 'quiet', None, _('suppress output'))] | |
505 | |
506 usage = _('''simplemerge [OPTS] LOCAL BASE OTHER | |
507 | |
508 Simple three-way file merge utility with a minimal feature set. | |
509 | |
510 Apply to LOCAL the changes necessary to go from BASE to OTHER. | |
511 | |
512 By default, LOCAL is overwritten with the results of this operation. | |
513 ''') | |
514 | |
515 def showhelp(): | |
516 sys.stdout.write(usage) | |
517 sys.stdout.write('\noptions:\n') | |
518 | |
519 out_opts = [] | |
520 for shortopt, longopt, default, desc in options: | |
521 out_opts.append(('%2s%s' % (shortopt and '-%s' % shortopt, | |
522 longopt and ' --%s' % longopt), | |
523 '%s' % desc)) | |
524 opts_len = max([len(opt[0]) for opt in out_opts]) | |
525 for first, second in out_opts: | |
526 sys.stdout.write(' %-*s %s\n' % (opts_len, first, second)) | |
527 | |
528 class ParseError(Exception): | |
529 """Exception raised on errors in parsing the command line.""" | |
530 | |
442 def main(argv): | 531 def main(argv): |
443 # as for diff3 and meld the syntax is "MINE BASE OTHER" | 532 try: |
444 a = file(argv[1], 'rt').readlines() | 533 opts = {} |
445 base = file(argv[2], 'rt').readlines() | 534 try: |
446 b = file(argv[3], 'rt').readlines() | 535 args = fancyopts.fancyopts(argv[1:], options, opts) |
447 | 536 except fancyopts.getopt.GetoptError, e: |
448 m3 = Merge3(base, a, b) | 537 raise ParseError(e) |
449 | 538 if opts['help']: |
450 #for sr in m3.find_sync_regions(): | 539 showhelp() |
451 # print sr | 540 return 0 |
452 | 541 if len(args) != 3: |
453 # sys.stdout.writelines(m3.merge_lines(name_a=argv[1], name_b=argv[3])) | 542 raise ParseError(_('wrong number of arguments')) |
454 sys.stdout.writelines(m3.merge_annotated()) | 543 return simplemerge(*args, **opts) |
455 | 544 except ParseError, e: |
545 sys.stdout.write("%s: %s\n" % (sys.argv[0], e)) | |
546 showhelp() | |
547 return 1 | |
548 except util.Abort, e: | |
549 sys.stderr.write("abort: %s\n" % e) | |
550 return 255 | |
551 except KeyboardInterrupt: | |
552 return 255 | |
456 | 553 |
457 if __name__ == '__main__': | 554 if __name__ == '__main__': |
458 import sys | 555 import sys |
556 import os | |
459 sys.exit(main(sys.argv)) | 557 sys.exit(main(sys.argv)) |