Mercurial > hg
diff mercurial/scmutil.py @ 34543:6fad8059a970
scmutil: handle conflicting files and dirs in origbackuppath
When ui.origbackuppath is set, .orig files are stored outside of the working
copy. However conflicts can occur when files or directories end up having the
same name. These conflicts cause Mercurial to abort, even if they've been
created as a result of different backups.
Make sure we always replace files or directories in the origbackuppath if
they conflict with another file or directory.
Test Plan:
Add new unit test for conflicting paths.
Differential Revision: https://phab.mercurial-scm.org/D680
author | Mark Thomas <mbthomas@fb.com> |
---|---|
date | Mon, 02 Oct 2017 14:05:30 -0700 |
parents | 153e4e05e9b3 |
children | 18309380fb88 |
line wrap: on
line diff
--- a/mercurial/scmutil.py Sun Oct 01 12:21:50 2017 +0100 +++ b/mercurial/scmutil.py Mon Oct 02 14:05:30 2017 -0700 @@ -38,6 +38,7 @@ similar, url, util, + vfs, ) if pycompat.osname == 'nt': @@ -573,18 +574,34 @@ Fall back to default (filepath with .orig suffix) if not specified ''' origbackuppath = ui.config('ui', 'origbackuppath') - if origbackuppath is None: + if not origbackuppath: return filepath + ".orig" - filepathfromroot = os.path.relpath(filepath, start=repo.root) - fullorigpath = repo.wjoin(origbackuppath, filepathfromroot) + # Convert filepath from an absolute path into a path inside the repo. + filepathfromroot = util.normpath(os.path.relpath(filepath, + start=repo.root)) + + origvfs = vfs.vfs(repo.wjoin(origbackuppath)) + origbackupdir = origvfs.dirname(filepathfromroot) + if not origvfs.isdir(origbackupdir) or origvfs.islink(origbackupdir): + ui.note(_('creating directory: %s\n') % origvfs.join(origbackupdir)) - origbackupdir = repo.vfs.dirname(fullorigpath) - if not repo.vfs.exists(origbackupdir): - ui.note(_('creating directory: %s\n') % origbackupdir) - util.makedirs(origbackupdir) + # Remove any files that conflict with the backup file's path + for f in reversed(list(util.finddirs(filepathfromroot))): + if origvfs.isfileorlink(f): + ui.note(_('removing conflicting file: %s\n') + % origvfs.join(f)) + origvfs.unlink(f) + break - return fullorigpath + origvfs.makedirs(origbackupdir) + + if origvfs.isdir(filepathfromroot): + ui.note(_('removing conflicting directory: %s\n') + % origvfs.join(filepathfromroot)) + origvfs.rmtree(filepathfromroot, forcibly=True) + + return origvfs.join(filepathfromroot) class _containsnode(object): """proxy __contains__(node) to container.__contains__ which accepts revs"""