mercurial/filemerge.py
changeset 34782 f21eecc64ace
parent 34506 1d804c22c671
child 34784 123a68e6b473
equal deleted inserted replaced
34781:fe987d0b9e1e 34782:f21eecc64ace
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
    10 import filecmp
       
    11 import os
    10 import os
    12 import re
    11 import re
    13 import tempfile
    12 import tempfile
    14 
    13 
    15 from .i18n import _
    14 from .i18n import _
   224         return '\r'
   223         return '\r'
   225     if '\n' in data: # UNIX
   224     if '\n' in data: # UNIX
   226         return '\n'
   225         return '\n'
   227     return None # unknown
   226     return None # unknown
   228 
   227 
   229 def _matcheol(file, origfile):
   228 def _matcheol(file, back):
   230     "Convert EOL markers in a file to match origfile"
   229     "Convert EOL markers in a file to match origfile"
   231     tostyle = _eoltype(util.readfile(origfile))
   230     tostyle = _eoltype(back.data()) # No repo.wread filters?
   232     if tostyle:
   231     if tostyle:
   233         data = util.readfile(file)
   232         data = util.readfile(file)
   234         style = _eoltype(data)
   233         style = _eoltype(data)
   235         if style:
   234         if style:
   236             newdata = data.replace(style, tostyle)
   235             newdata = data.replace(style, tostyle)
   503                }
   502                }
   504         ui = repo.ui
   503         ui = repo.ui
   505 
   504 
   506         args = _toolstr(ui, tool, "args", '$local $base $other')
   505         args = _toolstr(ui, tool, "args", '$local $base $other')
   507         if "$output" in args:
   506         if "$output" in args:
   508             out, a = a, back # read input from backup, write to original
   507             # read input from backup, write to original
       
   508             out = a
       
   509             a = repo.wvfs.join(back.path())
   509         replace = {'local': a, 'base': b, 'other': c, 'output': out}
   510         replace = {'local': a, 'base': b, 'other': c, 'output': out}
   510         args = util.interpolate(r'\$', replace, args,
   511         args = util.interpolate(r'\$', replace, args,
   511                                 lambda s: util.shellquote(util.localpath(s)))
   512                                 lambda s: util.shellquote(util.localpath(s)))
   512         cmd = toolpath + ' ' + args
   513         cmd = toolpath + ' ' + args
   513         if _toolbool(ui, tool, "gui"):
   514         if _toolbool(ui, tool, "gui"):
   586     }
   587     }
   587 
   588 
   588 def _restorebackup(fcd, back):
   589 def _restorebackup(fcd, back):
   589     # TODO: Add a workingfilectx.write(otherfilectx) path so we can use
   590     # TODO: Add a workingfilectx.write(otherfilectx) path so we can use
   590     # util.copy here instead.
   591     # util.copy here instead.
   591     fcd.write(util.readfile(back), fcd.flags())
   592     fcd.write(back.data(), fcd.flags())
   592 
   593 
   593 def _makebackup(repo, ui, fcd, premerge):
   594 def _makebackup(repo, ui, wctx, fcd, premerge):
   594     """Makes a backup of the local `fcd` file prior to merging.
   595     """Makes and returns a filectx-like object for ``fcd``'s backup file.
   595 
   596 
   596     In addition to preserving the user's pre-existing modifications to `fcd`
   597     In addition to preserving the user's pre-existing modifications to `fcd`
   597     (if any), the backup is used to undo certain premerges, confirm whether a
   598     (if any), the backup is used to undo certain premerges, confirm whether a
   598     merge changed anything, and determine what line endings the new file should
   599     merge changed anything, and determine what line endings the new file should
   599     have.
   600     have.
   600     """
   601     """
   601     if fcd.isabsent():
   602     if fcd.isabsent():
   602         return None
   603         return None
   603 
   604     # TODO: Break this import cycle somehow. (filectx -> ctx -> fileset ->
       
   605     # merge -> filemerge). (I suspect the fileset import is the weakest link)
       
   606     from . import context
   604     a = _workingpath(repo, fcd)
   607     a = _workingpath(repo, fcd)
   605     back = scmutil.origpath(ui, repo, a)
   608     back = scmutil.origpath(ui, repo, a)
   606     if premerge:
   609     if premerge:
   607         util.copyfile(a, back)
   610         util.copyfile(a, back)
   608     return back
   611     return context.arbitraryfilectx(back, repo=repo)
   609 
   612 
   610 def _maketempfiles(repo, fco, fca):
   613 def _maketempfiles(repo, fco, fca):
   611     """Writes out `fco` and `fca` as temporary files, so an external merge
   614     """Writes out `fco` and `fca` as temporary files, so an external merge
   612     tool may use them.
   615     tool may use them.
   613     """
   616     """
   689                                  toolconf):
   692                                  toolconf):
   690         if onfailure:
   693         if onfailure:
   691             ui.warn(onfailure % fd)
   694             ui.warn(onfailure % fd)
   692         return True, 1, False
   695         return True, 1, False
   693 
   696 
   694     back = _makebackup(repo, ui, fcd, premerge)
   697     back = _makebackup(repo, ui, wctx, fcd, premerge)
   695     files = (None, None, None, back)
   698     files = (None, None, None, back)
   696     r = 1
   699     r = 1
   697     try:
   700     try:
   698         markerstyle = ui.config('ui', 'mergemarkers')
   701         markerstyle = ui.config('ui', 'mergemarkers')
   699         if not labels:
   702         if not labels:
   717                 ui.warn(onfailure % fd)
   720                 ui.warn(onfailure % fd)
   718 
   721 
   719         return True, r, deleted
   722         return True, r, deleted
   720     finally:
   723     finally:
   721         if not r and back is not None:
   724         if not r and back is not None:
   722             util.unlink(back)
   725             back.remove()
   723 
   726 
   724 def _check(repo, r, ui, tool, fcd, files):
   727 def _check(repo, r, ui, tool, fcd, files):
   725     fd = fcd.path()
   728     fd = fcd.path()
   726     unused, unused, unused, back = files
   729     unused, unused, unused, back = files
   727 
   730 
   739             r = 1
   742             r = 1
   740 
   743 
   741     if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
   744     if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
   742                                   'changed' in
   745                                   'changed' in
   743                                   _toollist(ui, tool, "check")):
   746                                   _toollist(ui, tool, "check")):
   744         if back is not None and filecmp.cmp(_workingpath(repo, fcd), back):
   747         if back is not None and not fcd.cmp(back):
   745             if ui.promptchoice(_(" output file %s appears unchanged\n"
   748             if ui.promptchoice(_(" output file %s appears unchanged\n"
   746                                  "was merge successful (yn)?"
   749                                  "was merge successful (yn)?"
   747                                  "$$ &Yes $$ &No") % fd, 1):
   750                                  "$$ &Yes $$ &No") % fd, 1):
   748                 r = 1
   751                 r = 1
   749 
   752