comparison mercurial/filemerge.py @ 34782:f21eecc64ace

filemerge: use arbitraryfilectx for backups With in-memory merge, backup files might be overlayworkingfilectxs stored in memory. But they could also be real files if the user's backup directory is outside the working dir. Rather than have two code paths everywhere, let's use arbitraryfilectx so they can be consistent. Differential Revision: https://phab.mercurial-scm.org/D1057
author Phil Cohen <phillco@fb.com>
date Mon, 16 Oct 2017 13:10:55 -0700
parents 1d804c22c671
children 123a68e6b473
comparison
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