view contrib/simplemerge @ 41188:006c9ce486fa

rust-cpython: bindings for MissingAncestors The exposition is rather straightforward, except for the remove_ancestors_from() method, which forces us to an inefficient conversion between Python sets and Rust HashSets. Two alternatives are proposed in comments: - changing the inner API to "emit" the revision numbers to discard this would be a substantial change, and it would be better only in the cases where there are more to retain than to discard - mutating the Python set directly: this would force us to define an abstract `RevisionSet` trait, and implement it both for plain `HashSet` and for a struct enclosing a Python set with the GIL marker `Python<'p>`, also a non trivial effort. The main (and seemingly only) caller of this method being `mercurial.setdiscovery`, which is currently undergoing serious refactoring, it's not clear whether these improvements would be worth the effort right now, so we're leaving it as-is. Also, in `get_bases()` (will also be used by `setdiscovery`), we'd prefer to build a Python set directly, but we resort to returning a tuple, waiting to hear back from our PR onto rust-cpython about that Differential Revision: https://phab.mercurial-scm.org/D5550
author Georges Racinet <georges.racinet@octobus.net>
date Fri, 30 Nov 2018 20:05:34 +0100
parents d6b7c4e77bb4
children 3c2799cbace4
line wrap: on
line source

#!/usr/bin/env python
from __future__ import absolute_import

import getopt
import sys

import hgdemandimport
hgdemandimport.enable()

from mercurial.i18n import _
from mercurial import (
    context,
    error,
    fancyopts,
    pycompat,
    simplemerge,
    ui as uimod,
)
from mercurial.utils import (
    procutil,
)

options = [(b'L', b'label', [], _(b'labels to use on conflict markers')),
           (b'a', b'text', None, _(b'treat all files as text')),
           (b'p', b'print', None,
            _(b'print results instead of overwriting LOCAL')),
           (b'', b'no-minimal', None, _(b'no effect (DEPRECATED)')),
           (b'h', b'help', None, _(b'display help and exit')),
           (b'q', b'quiet', None, _(b'suppress output'))]

usage = _(b'''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.
''')

class ParseError(Exception):
    """Exception raised on errors in parsing the command line."""

def showhelp():
    pycompat.stdout.write(usage)
    pycompat.stdout.write(b'\noptions:\n')

    out_opts = []
    for shortopt, longopt, default, desc in options:
        out_opts.append((b'%2s%s' % (shortopt and b'-%s' % shortopt,
                                     longopt and b' --%s' % longopt),
                         b'%s' % desc))
    opts_len = max([len(opt[0]) for opt in out_opts])
    for first, second in out_opts:
        pycompat.stdout.write(b' %-*s  %s\n' % (opts_len, first, second))

try:
    for fp in (sys.stdin, pycompat.stdout, sys.stderr):
        procutil.setbinary(fp)

    opts = {}
    try:
        bargv = [a.encode('utf8') for a in sys.argv[1:]]
        args = fancyopts.fancyopts(bargv, options, opts)
    except getopt.GetoptError as e:
        raise ParseError(e)
    if opts[b'help']:
        showhelp()
        sys.exit(0)
    if len(args) != 3:
            raise ParseError(_(b'wrong number of arguments').decode('utf8'))
    local, base, other = args
    sys.exit(simplemerge.simplemerge(uimod.ui.load(),
                                     context.arbitraryfilectx(local),
                                     context.arbitraryfilectx(base),
                                     context.arbitraryfilectx(other),
                                     **pycompat.strkwargs(opts)))
except ParseError as e:
    if pycompat.ispy3:
        e = str(e).encode('utf8')
    pycompat.stdout.write(b"%s: %s\n" % (sys.argv[0].encode('utf8'), e))
    showhelp()
    sys.exit(1)
except error.Abort as e:
    pycompat.stderr.write(b"abort: %s\n" % e)
    sys.exit(255)
except KeyboardInterrupt:
    sys.exit(255)