mercurial/filemerge.py
changeset 6512 368a4ec603cc
parent 6212 e75aab656f46
child 6533 65f1b97484be
equal deleted inserted replaced
6511:5c1bb5750558 6512:368a4ec603cc
     3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
     3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
     4 #
     4 #
     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 node import nullrev
     8 from node import nullrev, short
     9 from i18n import _
     9 from i18n import _
    10 import util, os, tempfile, simplemerge, re, filecmp
    10 import util, os, tempfile, simplemerge, re, filecmp
    11 
    11 
    12 def _toolstr(ui, tool, part, default=""):
    12 def _toolstr(ui, tool, part, default=""):
    13     return ui.config("merge-tools", tool + "." + part, default)
    13     return ui.config("merge-tools", tool + "." + part, default)
    97         if style:
    97         if style:
    98             newdata = data.replace(style, tostyle)
    98             newdata = data.replace(style, tostyle)
    99             if newdata != data:
    99             if newdata != data:
   100                 open(file, "wb").write(newdata)
   100                 open(file, "wb").write(newdata)
   101 
   101 
   102 def filemerge(repo, fw, fd, fo, wctx, mctx):
   102 def filemerge(repo, mynode, orig, fcd, fco, fca):
   103     """perform a 3-way merge in the working directory
   103     """perform a 3-way merge in the working directory
   104 
   104 
   105     fw = original filename in the working directory
   105     mynode = parent node before merge
   106     fd = destination filename in the working directory
   106     orig = original local filename before merge
   107     fo = filename in other parent
   107     fco = other file context
   108     wctx, mctx = working and merge changecontexts
   108     fca = ancestor file context
       
   109     fcd = local file context for current/destination file
   109     """
   110     """
   110 
   111 
   111     def temp(prefix, ctx):
   112     def temp(prefix, ctx):
   112         pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
   113         pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
   113         (fd, name) = tempfile.mkstemp(prefix=pre)
   114         (fd, name) = tempfile.mkstemp(prefix=pre)
   121         try:
   122         try:
   122             return util.binary(ctx.data())
   123             return util.binary(ctx.data())
   123         except IOError:
   124         except IOError:
   124             return False
   125             return False
   125 
   126 
   126     fco = mctx.filectx(fo)
   127     if not fco.cmp(fcd.data()): # files identical?
   127     if not fco.cmp(wctx.filectx(fd).data()): # files identical?
       
   128         return None
   128         return None
   129 
   129 
   130     ui = repo.ui
   130     ui = repo.ui
   131     fcm = wctx.filectx(fw)
   131     fd = fcd.path()
   132     fca = fcm.ancestor(fco) or repo.filectx(fw, fileid=nullrev)
   132     binary = isbin(fcd) or isbin(fco) or isbin(fca)
   133     binary = isbin(fcm) or isbin(fco) or isbin(fca)
   133     symlink = fcd.islink() or fco.islink()
   134     symlink = fcm.islink() or fco.islink()
   134     tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
   135     tool, toolpath = _picktool(repo, ui, fw, binary, symlink)
       
   136     ui.debug(_("picked tool '%s' for %s (binary %s symlink %s)\n") %
   135     ui.debug(_("picked tool '%s' for %s (binary %s symlink %s)\n") %
   137                (tool, fw, binary, symlink))
   136                (tool, fd, binary, symlink))
   138 
   137 
   139     if not tool:
   138     if not tool:
   140         tool = "internal:local"
   139         tool = "internal:local"
   141         if ui.prompt(_(" no tool found to merge %s\n"
   140         if ui.prompt(_(" no tool found to merge %s\n"
   142                        "keep (l)ocal or take (o)ther?") % fw,
   141                        "keep (l)ocal or take (o)ther?") % fd,
   143                      _("[lo]"), _("l")) != _("l"):
   142                      _("[lo]"), _("l")) != _("l"):
   144             tool = "internal:other"
   143             tool = "internal:other"
   145     if tool == "internal:local":
   144     if tool == "internal:local":
   146         return 0
   145         return 0
   147     if tool == "internal:other":
   146     if tool == "internal:other":
   156     c = temp("other", fco)
   155     c = temp("other", fco)
   157     out = ""
   156     out = ""
   158     back = a + ".orig"
   157     back = a + ".orig"
   159     util.copyfile(a, back)
   158     util.copyfile(a, back)
   160 
   159 
   161     if fw != fo:
   160     if orig != fco.path():
   162         repo.ui.status(_("merging %s and %s\n") % (fw, fo))
   161         repo.ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
   163     else:
   162     else:
   164         repo.ui.status(_("merging %s\n") % fw)
   163         repo.ui.status(_("merging %s\n") % fd)
   165     repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca))
   164 
       
   165     repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcd, fco, fca))
   166 
   166 
   167     # do we attempt to simplemerge first?
   167     # do we attempt to simplemerge first?
   168     if _toolbool(ui, tool, "premerge", not (binary or symlink)):
   168     if _toolbool(ui, tool, "premerge", not (binary or symlink)):
   169         r = simplemerge.simplemerge(a, b, c, quiet=True)
   169         r = simplemerge.simplemerge(a, b, c, quiet=True)
   170         if not r:
   170         if not r:
   174             os.unlink(c)
   174             os.unlink(c)
   175             return 0
   175             return 0
   176         util.copyfile(back, a) # restore from backup and try again
   176         util.copyfile(back, a) # restore from backup and try again
   177 
   177 
   178     env = dict(HG_FILE=fd,
   178     env = dict(HG_FILE=fd,
   179                HG_MY_NODE=str(wctx.parents()[0]),
   179                HG_MY_NODE=short(mynode),
   180                HG_OTHER_NODE=str(mctx),
   180                HG_OTHER_NODE=str(fco.changectx()),
   181                HG_MY_ISLINK=fcm.islink(),
   181                HG_MY_ISLINK=fcd.islink(),
   182                HG_OTHER_ISLINK=fco.islink(),
   182                HG_OTHER_ISLINK=fco.islink(),
   183                HG_BASE_ISLINK=fca.islink())
   183                HG_BASE_ISLINK=fca.islink())
   184 
   184 
   185     if tool == "internal:merge":
   185     if tool == "internal:merge":
   186         r = simplemerge.simplemerge(a, b, c, label=['local', 'other'])
   186         r = simplemerge.simplemerge(a, b, c, label=['local', 'other'])
   192         args = re.sub("\$(local|base|other|output)",
   192         args = re.sub("\$(local|base|other|output)",
   193                       lambda x: '"%s"' % replace[x.group()[1:]], args)
   193                       lambda x: '"%s"' % replace[x.group()[1:]], args)
   194         r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env)
   194         r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env)
   195 
   195 
   196     if not r and _toolbool(ui, tool, "checkconflicts"):
   196     if not r and _toolbool(ui, tool, "checkconflicts"):
   197         if re.match("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcm.data()):
   197         if re.match("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data()):
   198             r = 1
   198             r = 1
   199 
   199 
   200     if not r and _toolbool(ui, tool, "checkchanged"):
   200     if not r and _toolbool(ui, tool, "checkchanged"):
   201         if filecmp.cmp(repo.wjoin(fd), back):
   201         if filecmp.cmp(repo.wjoin(fd), back):
   202             if ui.prompt(_(" output file %s appears unchanged\n"
   202             if ui.prompt(_(" output file %s appears unchanged\n"