comparison mercurial/context.py @ 35324:72fbdd373de8

overlayworkingctx: add _auditconflicts to write() Alas, part of Mercurial's conflict detection (for file<->folder conflicts, for example) depends on the filesystem. We don't have the filesystem with IMM, so we have to run these checks ourselves. Differential Revision: https://phab.mercurial-scm.org/D1241
author Phil Cohen <phillco@fb.com>
date Thu, 07 Dec 2017 16:07:06 -0800
parents 8e1386b342f7
children 71edd38c4bb4
comparison
equal deleted inserted replaced
35323:8e1386b342f7 35324:72fbdd373de8
2090 self._wrappedctx[path] 2090 self._wrappedctx[path]
2091 return True 2091 return True
2092 except error.ManifestLookupError: 2092 except error.ManifestLookupError:
2093 return False 2093 return False
2094 2094
2095 def _auditconflicts(self, path):
2096 """Replicates conflict checks done by wvfs.write().
2097
2098 Since we never write to the filesystem and never call `applyupdates` in
2099 IMM, we'll never check that a path is actually writable -- e.g., because
2100 it adds `a/foo`, but `a` is actually a file in the other commit.
2101 """
2102 def fail(path, component):
2103 # p1() is the base and we're receiving "writes" for p2()'s
2104 # files.
2105 if 'l' in self.p1()[component].flags():
2106 raise error.Abort("error: %s conflicts with symlink %s "
2107 "in %s." % (path, component,
2108 self.p1().rev()))
2109 else:
2110 raise error.Abort("error: '%s' conflicts with file '%s' in "
2111 "%s." % (path, component,
2112 self.p1().rev()))
2113
2114 # Test that each new directory to be created to write this path from p2
2115 # is not a file in p1.
2116 components = path.split('/')
2117 for i in xrange(len(components)):
2118 component = "/".join(components[0:i])
2119 if component in self.p1():
2120 fail(path, component)
2121
2122 # Test the other direction -- that this path from p2 isn't a directory
2123 # in p1 (test that p1 doesn't any paths matching `path/*`).
2124 match = matchmod.match('/', '', [path + '/'], default=b'relpath')
2125 matches = self.p1().manifest().matches(match)
2126 if len(matches) > 0:
2127 if len(matches) == 1 and matches.keys()[0] == path:
2128 return
2129 raise error.Abort("error: file '%s' cannot be written because "
2130 " '%s/' is a folder in %s (containing %d "
2131 "entries: %s)"
2132 % (path, path, self.p1(), len(matches),
2133 ', '.join(matches.keys())))
2134
2095 def write(self, path, data, flags=''): 2135 def write(self, path, data, flags=''):
2096 if data is None: 2136 if data is None:
2097 raise error.ProgrammingError("data must be non-None") 2137 raise error.ProgrammingError("data must be non-None")
2138 self._auditconflicts(path)
2098 self._markdirty(path, exists=True, data=data, date=util.makedate(), 2139 self._markdirty(path, exists=True, data=data, date=util.makedate(),
2099 flags=flags) 2140 flags=flags)
2100 2141
2101 def setflags(self, path, l, x): 2142 def setflags(self, path, l, x):
2102 self._markdirty(path, exists=True, date=util.makedate(), 2143 self._markdirty(path, exists=True, date=util.makedate(),