Mercurial > public > mercurial-scm > hg-stable
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 |