mercurial/filemerge.py
author Nicolas Dumazet <nicdumz.commits@gmail.com>
Tue, 27 Jul 2010 23:40:46 +0900
changeset 11702 eb07fbc21e9c
parent 11149 d3c1eddfdbcf
child 11988 8380ed691df8
permissions -rw-r--r--
filectx: use cmp(self, fctx) instead of cmp(self, text) This allows more flexibility in implementation, and in particular, lets the context decide if revision text has to be loaded or not.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
# filemerge.py - file-level merge handling for Mercurial
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
#
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     3
# Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8209
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9709
diff changeset
     6
# GNU General Public License version 2 or any later version.
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
7873
4a4c7f6a5912 cleanup: drop unused imports
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7397
diff changeset
     8
from node import short
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     9
from i18n import _
11146
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
    10
import util, simplemerge, match, error
8312
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8269
diff changeset
    11
import os, tempfile, re, filecmp
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    12
6013
bb441d77df99 filemerge: handle missing regappend
Matt Mackall <mpm@selenic.com>
parents: 6007
diff changeset
    13
def _toolstr(ui, tool, part, default=""):
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    14
    return ui.config("merge-tools", tool + "." + part, default)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    15
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    16
def _toolbool(ui, tool, part, default=False):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    17
    return ui.configbool("merge-tools", tool + "." + part, default)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    18
11148
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
    19
def _toollist(ui, tool, part, default=[]):
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
    20
    return ui.configlist("merge-tools", tool + "." + part, default)
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
    21
8831
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
    22
_internal = ['internal:' + s
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
    23
             for s in 'fail local other merge prompt dump'.split()]
8830
a9850eda2973 filemerge: add internal:prompt target
Matt Mackall <mpm@selenic.com>
parents: 8615
diff changeset
    24
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    25
def _findtool(ui, tool):
8830
a9850eda2973 filemerge: add internal:prompt target
Matt Mackall <mpm@selenic.com>
parents: 8615
diff changeset
    26
    if tool in _internal:
6522
2b181fb3a70a use internal merge tool when specified for a merge-pattern in hgrc
Dov Feldstern <dfeldstern@fastimap.com>
parents: 6212
diff changeset
    27
        return tool
6006
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
    28
    k = _toolstr(ui, tool, "regkey")
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
    29
    if k:
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
    30
        p = util.lookup_reg(k, _toolstr(ui, tool, "regname"))
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
    31
        if p:
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
    32
            p = util.find_exe(p + _toolstr(ui, tool, "regappend"))
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
    33
            if p:
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
    34
                return p
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    35
    return util.find_exe(_toolstr(ui, tool, "executable", tool))
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    36
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    37
def _picktool(repo, ui, path, binary, symlink):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    38
    def check(tool, pat, symlink, binary):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    39
        tmsg = tool
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    40
        if pat:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    41
            tmsg += " specified for " + pat
7397
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
    42
        if not _findtool(ui, tool):
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
    43
            if pat: # explicitly requested tool deserves a warning
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
    44
                ui.warn(_("couldn't find merge tool %s\n") % tmsg)
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
    45
            else: # configured but non-existing tools are more silent
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
    46
                ui.note(_("couldn't find merge tool %s\n") % tmsg)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    47
        elif symlink and not _toolbool(ui, tool, "symlink"):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    48
            ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    49
        elif binary and not _toolbool(ui, tool, "binary"):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    50
            ui.warn(_("tool %s can't handle binary\n") % tmsg)
6007
090b1a665901 filemerge: add config item for GUI tools
Matt Mackall <mpm@selenic.com>
parents: 6006
diff changeset
    51
        elif not util.gui() and _toolbool(ui, tool, "gui"):
090b1a665901 filemerge: add config item for GUI tools
Matt Mackall <mpm@selenic.com>
parents: 6006
diff changeset
    52
            ui.warn(_("tool %s requires a GUI\n") % tmsg)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    53
        else:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    54
            return True
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    55
        return False
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    56
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    57
    # HGMERGE takes precedence
6025
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
    58
    hgmerge = os.environ.get("HGMERGE")
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
    59
    if hgmerge:
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
    60
        return (hgmerge, hgmerge)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    61
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    62
    # then patterns
6016
288ec2f6faa2 filemerge: fix pattern matching
dhruva <dhruvakm@gmail.com>
parents: 6015
diff changeset
    63
    for pat, tool in ui.configitems("merge-patterns"):
8567
fea40a677d43 match: add some default args
Matt Mackall <mpm@selenic.com>
parents: 8566
diff changeset
    64
        mf = match.match(repo.root, '', [pat])
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    65
        if mf(path) and check(tool, pat, symlink, False):
10339
23e608f42f2c fix spaces/identation issues
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
    66
            toolpath = _findtool(ui, tool)
23e608f42f2c fix spaces/identation issues
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
    67
            return (tool, '"' + toolpath + '"')
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    68
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    69
    # then merge tools
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    70
    tools = {}
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    71
    for k, v in ui.configitems("merge-tools"):
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    72
        t = k.split('.')[0]
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    73
        if t not in tools:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    74
            tools[t] = int(_toolstr(ui, t, "priority", "0"))
6076
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
    75
    names = tools.keys()
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    76
    tools = sorted([(-p, t) for t, p in tools.items()])
6076
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
    77
    uimerge = ui.config("ui", "merge")
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
    78
    if uimerge:
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
    79
        if uimerge not in names:
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
    80
            return (uimerge, uimerge)
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
    81
        tools.insert(0, (None, uimerge)) # highest priority
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
    82
    tools.append((None, "hgmerge")) # the old default, if found
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    83
    for p, t in tools:
7397
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
    84
        if check(t, None, symlink, binary):
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
    85
            toolpath = _findtool(ui, t)
6025
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
    86
            return (t, '"' + toolpath + '"')
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
    87
    # internal merge as last resort
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
    88
    return (not (symlink or binary) and "internal:merge" or None, None)
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    89
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    90
def _eoltype(data):
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    91
    "Guess the EOL type of a file"
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    92
    if '\0' in data: # binary
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    93
        return None
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    94
    if '\r\n' in data: # Windows
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    95
        return '\r\n'
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    96
    if '\r' in data: # Old Mac
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    97
        return '\r'
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    98
    if '\n' in data: # UNIX
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
    99
        return '\n'
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   100
    return None # unknown
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   101
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   102
def _matcheol(file, origfile):
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   103
    "Convert EOL markers in a file to match origfile"
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   104
    tostyle = _eoltype(open(origfile, "rb").read())
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   105
    if tostyle:
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   106
        data = open(file, "rb").read()
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   107
        style = _eoltype(data)
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   108
        if style:
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   109
            newdata = data.replace(style, tostyle)
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   110
            if newdata != data:
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   111
                open(file, "wb").write(newdata)
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   112
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   113
def filemerge(repo, mynode, orig, fcd, fco, fca):
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   114
    """perform a 3-way merge in the working directory
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   115
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   116
    mynode = parent node before merge
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   117
    orig = original local filename before merge
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   118
    fco = other file context
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   119
    fca = ancestor file context
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   120
    fcd = local file context for current/destination file
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   121
    """
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   122
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   123
    def temp(prefix, ctx):
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   124
        pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   125
        (fd, name) = tempfile.mkstemp(prefix=pre)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   126
        data = repo.wwritedata(ctx.path(), ctx.data())
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   127
        f = os.fdopen(fd, "wb")
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   128
        f.write(data)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   129
        f.close()
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   130
        return name
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   131
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   132
    def isbin(ctx):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   133
        try:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   134
            return util.binary(ctx.data())
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   135
        except IOError:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   136
            return False
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   137
11702
eb07fbc21e9c filectx: use cmp(self, fctx) instead of cmp(self, text)
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 11149
diff changeset
   138
    if not fco.cmp(fcd): # files identical?
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   139
        return None
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   140
10944
6f1894d6a6b0 filemerge: use working dir parent as ancestor for backward wdir merge
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10533
diff changeset
   141
    if fca == fco: # backwards, use working dir parent as ancestor
6f1894d6a6b0 filemerge: use working dir parent as ancestor for backward wdir merge
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10533
diff changeset
   142
        fca = fcd.parents()[0]
6f1894d6a6b0 filemerge: use working dir parent as ancestor for backward wdir merge
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10533
diff changeset
   143
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   144
    ui = repo.ui
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   145
    fd = fcd.path()
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   146
    binary = isbin(fcd) or isbin(fco) or isbin(fca)
6744
d3691d31fc9c context: remove islink and isexec methods
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
   147
    symlink = 'l' in fcd.flags() + fco.flags()
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   148
    tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
9467
4c041f1ee1b4 do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents: 9049
diff changeset
   149
    ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   150
               (tool, fd, binary, symlink))
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   151
8830
a9850eda2973 filemerge: add internal:prompt target
Matt Mackall <mpm@selenic.com>
parents: 8615
diff changeset
   152
    if not tool or tool == 'internal:prompt':
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   153
        tool = "internal:local"
9048
86b4a9b0ddda ui: extract choice from prompt
Simon Heimberg <simohe@besonet.ch>
parents: 8861
diff changeset
   154
        if ui.promptchoice(_(" no tool found to merge %s\n"
9049
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
   155
                             "keep (l)ocal or take (o)ther?") % fd,
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
   156
                           (_("&Local"), _("&Other")), 0):
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   157
            tool = "internal:other"
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   158
    if tool == "internal:local":
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   159
        return 0
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   160
    if tool == "internal:other":
6743
86e8187b721a simplify flag handling
Matt Mackall <mpm@selenic.com>
parents: 6533
diff changeset
   161
        repo.wwrite(fd, fco.data(), fco.flags())
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   162
        return 0
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   163
    if tool == "internal:fail":
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   164
        return 1
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   165
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   166
    # do the actual merge
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   167
    a = repo.wjoin(fd)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   168
    b = temp("base", fca)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   169
    c = temp("other", fco)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   170
    out = ""
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   171
    back = a + ".orig"
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   172
    util.copyfile(a, back)
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   173
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   174
    if orig != fco.path():
8615
94ca38e63576 use ui instead of repo.ui when the former is in scope
Martin Geisler <mg@lazybytes.net>
parents: 8567
diff changeset
   175
        ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   176
    else:
8615
94ca38e63576 use ui instead of repo.ui when the former is in scope
Martin Geisler <mg@lazybytes.net>
parents: 8567
diff changeset
   177
        ui.status(_("merging %s\n") % fd)
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   178
9467
4c041f1ee1b4 do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents: 9049
diff changeset
   179
    ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   180
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   181
    # do we attempt to simplemerge first?
11146
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   182
    try:
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   183
        premerge = _toolbool(ui, tool, "premerge", not (binary or symlink))
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   184
    except error.ConfigError:
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   185
        premerge = _toolstr(ui, tool, "premerge").lower()
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   186
        valid = 'keep'.split()
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   187
        if premerge not in valid:
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   188
            _valid = ', '.join(["'" + v + "'" for v in valid])
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   189
            raise error.ConfigError(_("%s.premerge not valid "
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   190
                                      "('%s' is neither boolean nor %s)") %
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   191
                                    (tool, premerge, _valid))
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   192
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   193
    if premerge:
8269
bb9f13974d8e simplemerge: use ui.warn() for warnings
Steve Borho <steve@borho.org>
parents: 8259
diff changeset
   194
        r = simplemerge.simplemerge(ui, a, b, c, quiet=True)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   195
        if not r:
9467
4c041f1ee1b4 do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents: 9049
diff changeset
   196
            ui.debug(" premerge successful\n")
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   197
            os.unlink(back)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   198
            os.unlink(b)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   199
            os.unlink(c)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   200
            return 0
11146
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   201
        if premerge != 'keep':
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
   202
            util.copyfile(back, a) # restore from backup and try again
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   203
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   204
    env = dict(HG_FILE=fd,
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   205
               HG_MY_NODE=short(mynode),
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   206
               HG_OTHER_NODE=str(fco.changectx()),
9709
5858117a0077 merge: supply base node to merge tools in the environment
Sune Foldager <cryo@cyanite.org>
parents: 9467
diff changeset
   207
               HG_BASE_NODE=str(fca.changectx()),
6744
d3691d31fc9c context: remove islink and isexec methods
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
   208
               HG_MY_ISLINK='l' in fcd.flags(),
d3691d31fc9c context: remove islink and isexec methods
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
   209
               HG_OTHER_ISLINK='l' in fco.flags(),
d3691d31fc9c context: remove islink and isexec methods
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
   210
               HG_BASE_ISLINK='l' in fca.flags())
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   211
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   212
    if tool == "internal:merge":
8269
bb9f13974d8e simplemerge: use ui.warn() for warnings
Steve Borho <steve@borho.org>
parents: 8259
diff changeset
   213
        r = simplemerge.simplemerge(ui, a, b, c, label=['local', 'other'])
8831
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
   214
    elif tool == 'internal:dump':
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
   215
        a = repo.wjoin(fd)
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
   216
        util.copyfile(a, a + ".local")
8861
90f74b31ed4f filemerge: fix internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8831
diff changeset
   217
        repo.wwrite(fd + ".other", fco.data(), fco.flags())
90f74b31ed4f filemerge: fix internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8831
diff changeset
   218
        repo.wwrite(fd + ".base", fca.data(), fca.flags())
8831
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
   219
        return 1 # unresolved
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   220
    else:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   221
        args = _toolstr(ui, tool, "args", '$local $base $other')
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   222
        if "$output" in args:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   223
            out, a = a, back # read input from backup, write to original
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   224
        replace = dict(local=a, base=b, other=c, output=out)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   225
        args = re.sub("\$(local|base|other|output)",
10533
184cdb66263e filemerge: use native path separators when merging (issue1399)
Patrick Mezard <pmezard@gmail.com>
parents: 10339
diff changeset
   226
            lambda x: '"%s"' % util.localpath(replace[x.group()[1:]]), args)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   227
        r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   228
11148
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
   229
    if not r and (_toolbool(ui, tool, "checkconflicts") or
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
   230
                  'conflicts' in _toollist(ui, tool, "check")):
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
   231
        if re.match("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data()):
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   232
            r = 1
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   233
11149
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   234
    checked = False
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   235
    if 'prompt' in _toollist(ui, tool, "check"):
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   236
        checked = True
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   237
        if ui.promptchoice(_("was merge of '%s' successful (yn)?") % fd,
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   238
                           (_("&Yes"), _("&No")), 1):
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   239
            r = 1
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   240
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   241
    if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
   242
                                  'changed' in _toollist(ui, tool, "check")):
6075
63e0e57ab157 filemerge: add 'checkchanged' merge tool property
Steve Borho <steve@borho.org>
parents: 6025
diff changeset
   243
        if filecmp.cmp(repo.wjoin(fd), back):
9048
86b4a9b0ddda ui: extract choice from prompt
Simon Heimberg <simohe@besonet.ch>
parents: 8861
diff changeset
   244
            if ui.promptchoice(_(" output file %s appears unchanged\n"
9049
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
   245
                                 "was merge successful (yn)?") % fd,
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
   246
                               (_("&Yes"), _("&No")), 1):
6075
63e0e57ab157 filemerge: add 'checkchanged' merge tool property
Steve Borho <steve@borho.org>
parents: 6025
diff changeset
   247
                r = 1
63e0e57ab157 filemerge: add 'checkchanged' merge tool property
Steve Borho <steve@borho.org>
parents: 6025
diff changeset
   248
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   249
    if _toolbool(ui, tool, "fixeol"):
6015
26ef792f834e filemerge: fix path to working file when fixeol is enabled
Lee Cantey <lcantey@gmail.com>
parents: 6013
diff changeset
   250
        _matcheol(repo.wjoin(fd), back)
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
   251
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   252
    if r:
8615
94ca38e63576 use ui instead of repo.ui when the former is in scope
Martin Geisler <mg@lazybytes.net>
parents: 8567
diff changeset
   253
        ui.warn(_("merging %s failed!\n") % fd)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   254
    else:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
   255
        os.unlink(back)
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   256
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   257
    os.unlink(b)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   258
    os.unlink(c)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   259
    return r