Mercurial > hg
changeset 4364: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 | 46280c004f22 |
files | contrib/simplemerge tests/test-simplemerge-cmd tests/test-simplemerge-cmd.out |
diffstat | 3 files changed, 171 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/simplemerge Mon Apr 16 20:17:39 2007 -0300 +++ b/contrib/simplemerge Mon Apr 16 20:17:39 2007 -0300 @@ -19,8 +19,10 @@ # mbp: "you know that thing where cvs gives you conflict markers?" # s: "i hate that." +from mercurial import demandimport +demandimport.enable() -from mercurial import util, mdiff +from mercurial import util, mdiff, fancyopts from mercurial.i18n import _ @@ -97,6 +99,7 @@ reprocess=False): """Return merge in cvs-like form. """ + self.conflicts = False newline = '\n' if len(self.a) > 0: if self.a[0].endswith('\r\n'): @@ -126,6 +129,7 @@ for i in range(t[1], t[2]): yield self.b[i] elif what == 'conflict': + self.conflicts = True yield start_marker + newline for i in range(t[3], t[4]): yield self.a[i] @@ -439,21 +443,115 @@ Merge3Text.__init__(self, basetext, atext, btext, base, a, b) -def main(argv): - # as for diff3 and meld the syntax is "MINE BASE OTHER" - a = file(argv[1], 'rt').readlines() - base = file(argv[2], 'rt').readlines() - b = file(argv[3], 'rt').readlines() +def simplemerge(local, base, other, **opts): + def readfile(filename): + f = open(filename, "rb") + text = f.read() + f.close() + if util.binary(text): + msg = _("%s looks like a binary file.") % filename + if not opts.get('text'): + raise util.Abort(msg) + elif not opts.get('quiet'): + sys.stderr.write(_('warning: %s\n') % msg) + return text + + name_a = local + name_b = other + labels = opts.get('label', []) + if labels: + name_a = labels.pop(0) + if labels: + name_b = labels.pop(0) + if labels: + raise util.Abort(_("can only specify two labels.")) + + localtext = readfile(local) + basetext = readfile(base) + othertext = readfile(other) + + orig = local + local = os.path.realpath(local) + if not opts.get('print'): + opener = util.opener(os.path.dirname(local)) + out = opener(os.path.basename(local), "w", atomictemp=True) + else: + out = sys.stdout + + reprocess = not opts.get('no_minimal') + + m3 = Merge3Text(basetext, localtext, othertext) + for line in m3.merge_lines(name_a=name_a, name_b=name_b, + reprocess=reprocess): + out.write(line) + + if not opts.get('print'): + out.rename() + + if m3.conflicts: + if not opts.get('quiet'): + sys.stdout.flush() + sys.stderr.write(_("warning: conflicts during merge.\n")) + return 1 - m3 = Merge3(base, a, b) +options = [('L', 'label', [], _('labels to use on conflict markers')), + ('a', 'text', None, _('treat all files as text')), + ('p', 'print', None, + _('print results instead of overwriting LOCAL')), + ('', 'no-minimal', None, + _('do not try to minimize conflict regions')), + ('h', 'help', None, _('display help and exit')), + ('q', 'quiet', None, _('suppress output'))] + +usage = _('''simplemerge [OPTS] LOCAL BASE OTHER + + Simple three-way file merge utility with a minimal feature set. + + Apply to LOCAL the changes necessary to go from BASE to OTHER. + + By default, LOCAL is overwritten with the results of this operation. +''') + +def showhelp(): + sys.stdout.write(usage) + sys.stdout.write('\noptions:\n') - #for sr in m3.find_sync_regions(): - # print sr + out_opts = [] + for shortopt, longopt, default, desc in options: + out_opts.append(('%2s%s' % (shortopt and '-%s' % shortopt, + longopt and ' --%s' % longopt), + '%s' % desc)) + opts_len = max([len(opt[0]) for opt in out_opts]) + for first, second in out_opts: + sys.stdout.write(' %-*s %s\n' % (opts_len, first, second)) + +class ParseError(Exception): + """Exception raised on errors in parsing the command line.""" - # sys.stdout.writelines(m3.merge_lines(name_a=argv[1], name_b=argv[3])) - sys.stdout.writelines(m3.merge_annotated()) - +def main(argv): + try: + opts = {} + try: + args = fancyopts.fancyopts(argv[1:], options, opts) + except fancyopts.getopt.GetoptError, e: + raise ParseError(e) + if opts['help']: + showhelp() + return 0 + if len(args) != 3: + raise ParseError(_('wrong number of arguments')) + return simplemerge(*args, **opts) + except ParseError, e: + sys.stdout.write("%s: %s\n" % (sys.argv[0], e)) + showhelp() + return 1 + except util.Abort, e: + sys.stderr.write("abort: %s\n" % e) + return 255 + except KeyboardInterrupt: + return 255 if __name__ == '__main__': import sys + import os sys.exit(main(sys.argv))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-simplemerge-cmd Mon Apr 16 20:17:39 2007 -0300 @@ -0,0 +1,61 @@ +#!/bin/sh + +cp "$TESTDIR"/../contrib/simplemerge . + +echo base > base + +echo local > local +cat base >> local +cp local orig + +cat base > other +echo other >> other + +echo '% changing local directly' +python simplemerge local base other && echo "merge succeeded" +cat local +cp orig local + +echo '% printing to stdout' +python simplemerge -p local base other +echo ' local:' +cat local + +echo '% conflicts' +cp base conflict-local +cp other conflict-other +echo not other >> conflict-local +echo end >> conflict-local +echo end >> conflict-other +python simplemerge -p conflict-local base conflict-other || echo "merge failed" + +echo '% --no-minimal' +python simplemerge -p --no-minimal conflict-local base conflict-other + +echo '% 1 label' +python simplemerge -p -L foo conflict-local base conflict-other + +echo '% 2 labels' +python simplemerge -p -L foo -L bar conflict-local base conflict-other + +echo '% too many labels' +python simplemerge -p -L foo -L bar -L baz conflict-local base conflict-other + +echo '% binary file' +printf '\x00' > binary-local +cat orig >> binary-local +python simplemerge -p binary-local base other + +echo '% binary file --text' +python simplemerge -a -p binary-local base other + +echo '% help' +python simplemerge --help + +echo '% wrong number of arguments' +python simplemerge + +echo '% bad option' +python simplemerge --foo -p local base other + +exit 0