Show More
@@ -394,7 +394,7 b' def overridewalk(orig, self, match, subr' | |||||
394 | visit.update(f for f in copymap |
|
394 | visit.update(f for f in copymap | |
395 | if f not in results and matchfn(f)) |
|
395 | if f not in results and matchfn(f)) | |
396 |
|
396 | |||
397 | audit = pathutil.pathauditor(self._root).check |
|
397 | audit = pathutil.pathauditor(self._root, cached=True).check | |
398 | auditpass = [f for f in visit if audit(f)] |
|
398 | auditpass = [f for f in visit if audit(f)] | |
399 | auditpass.sort() |
|
399 | auditpass.sort() | |
400 | auditfail = visit.difference(auditpass) |
|
400 | auditfail = visit.difference(auditpass) |
@@ -3218,7 +3218,7 b' def _performrevert(repo, parents, ctx, a' | |||||
3218 | pass |
|
3218 | pass | |
3219 | repo.dirstate.remove(f) |
|
3219 | repo.dirstate.remove(f) | |
3220 |
|
3220 | |||
3221 | audit_path = pathutil.pathauditor(repo.root) |
|
3221 | audit_path = pathutil.pathauditor(repo.root, cached=True) | |
3222 | for f in actions['forget'][0]: |
|
3222 | for f in actions['forget'][0]: | |
3223 | if interactive: |
|
3223 | if interactive: | |
3224 | choice = repo.ui.promptchoice( |
|
3224 | choice = repo.ui.promptchoice( |
@@ -1089,7 +1089,7 b' class dirstate(object):' | |||||
1089 | # that wasn't ignored, and everything that matched was stat'ed |
|
1089 | # that wasn't ignored, and everything that matched was stat'ed | |
1090 | # and is already in results. |
|
1090 | # and is already in results. | |
1091 | # The rest must thus be ignored or under a symlink. |
|
1091 | # The rest must thus be ignored or under a symlink. | |
1092 | audit_path = pathutil.pathauditor(self._root) |
|
1092 | audit_path = pathutil.pathauditor(self._root, cached=True) | |
1093 |
|
1093 | |||
1094 | for nf in iter(visit): |
|
1094 | for nf in iter(visit): | |
1095 | # If a stat for the same file was already added with a |
|
1095 | # If a stat for the same file was already added with a |
@@ -273,8 +273,8 b' class localrepository(object):' | |||||
273 | self.origroot = path |
|
273 | self.origroot = path | |
274 | self.auditor = pathutil.pathauditor(self.root, self._checknested) |
|
274 | self.auditor = pathutil.pathauditor(self.root, self._checknested) | |
275 | self.nofsauditor = pathutil.pathauditor(self.root, self._checknested, |
|
275 | self.nofsauditor = pathutil.pathauditor(self.root, self._checknested, | |
276 | realfs=False) |
|
276 | realfs=False, cached=True) | |
277 | self.vfs = vfsmod.vfs(self.path) |
|
277 | self.vfs = vfsmod.vfs(self.path, cacheaudited=True) | |
278 | self.baseui = baseui |
|
278 | self.baseui = baseui | |
279 | self.ui = baseui.copy() |
|
279 | self.ui = baseui.copy() | |
280 | self.ui.copy = baseui.copy # prevent copying repo configuration |
|
280 | self.ui.copy = baseui.copy # prevent copying repo configuration | |
@@ -350,7 +350,8 b' class localrepository(object):' | |||||
350 | raise |
|
350 | raise | |
351 |
|
351 | |||
352 | self.store = store.store( |
|
352 | self.store = store.store( | |
353 |
|
|
353 | self.requirements, self.sharedpath, | |
|
354 | lambda base: vfsmod.vfs(base, cacheaudited=True)) | |||
354 | self.spath = self.store.path |
|
355 | self.spath = self.store.path | |
355 | self.svfs = self.store.vfs |
|
356 | self.svfs = self.store.vfs | |
356 | self.sjoin = self.store.join |
|
357 | self.sjoin = self.store.join |
@@ -33,13 +33,18 b' class pathauditor(object):' | |||||
33 | The file system checks are only done when 'realfs' is set to True (the |
|
33 | The file system checks are only done when 'realfs' is set to True (the | |
34 | default). They should be disable then we are auditing path for operation on |
|
34 | default). They should be disable then we are auditing path for operation on | |
35 | stored history. |
|
35 | stored history. | |
|
36 | ||||
|
37 | If 'cached' is set to True, audited paths and sub-directories are cached. | |||
|
38 | Be careful to not keep the cache of unmanaged directories for long because | |||
|
39 | audited paths may be replaced with symlinks. | |||
36 | ''' |
|
40 | ''' | |
37 |
|
41 | |||
38 | def __init__(self, root, callback=None, realfs=True): |
|
42 | def __init__(self, root, callback=None, realfs=True, cached=False): | |
39 | self.audited = set() |
|
43 | self.audited = set() | |
40 | self.auditeddir = set() |
|
44 | self.auditeddir = set() | |
41 | self.root = root |
|
45 | self.root = root | |
42 | self._realfs = realfs |
|
46 | self._realfs = realfs | |
|
47 | self._cached = cached | |||
43 | self.callback = callback |
|
48 | self.callback = callback | |
44 | if os.path.lexists(root) and not util.fscasesensitive(root): |
|
49 | if os.path.lexists(root) and not util.fscasesensitive(root): | |
45 | self.normcase = util.normcase |
|
50 | self.normcase = util.normcase | |
@@ -96,10 +101,11 b' class pathauditor(object):' | |||||
96 | self._checkfs(prefix, path) |
|
101 | self._checkfs(prefix, path) | |
97 | prefixes.append(normprefix) |
|
102 | prefixes.append(normprefix) | |
98 |
|
103 | |||
99 | self.audited.add(normpath) |
|
104 | if self._cached: | |
100 | # only add prefixes to the cache after checking everything: we don't |
|
105 | self.audited.add(normpath) | |
101 | # want to add "foo/bar/baz" before checking if there's a "foo/.hg" |
|
106 | # only add prefixes to the cache after checking everything: we don't | |
102 | self.auditeddir.update(prefixes) |
|
107 | # want to add "foo/bar/baz" before checking if there's a "foo/.hg" | |
|
108 | self.auditeddir.update(prefixes) | |||
103 |
|
109 | |||
104 | def _checkfs(self, prefix, path): |
|
110 | def _checkfs(self, prefix, path): | |
105 | """raise exception if a file system backed check fails""" |
|
111 | """raise exception if a file system backed check fails""" |
@@ -667,7 +667,7 b' def _interestingfiles(repo, matcher):' | |||||
667 | This is different from dirstate.status because it doesn't care about |
|
667 | This is different from dirstate.status because it doesn't care about | |
668 | whether files are modified or clean.''' |
|
668 | whether files are modified or clean.''' | |
669 | added, unknown, deleted, removed, forgotten = [], [], [], [], [] |
|
669 | added, unknown, deleted, removed, forgotten = [], [], [], [], [] | |
670 | audit_path = pathutil.pathauditor(repo.root) |
|
670 | audit_path = pathutil.pathauditor(repo.root, cached=True) | |
671 |
|
671 | |||
672 | ctx = repo[None] |
|
672 | ctx = repo[None] | |
673 | dirstate = repo.dirstate |
|
673 | dirstate = repo.dirstate |
@@ -276,13 +276,19 b' class vfs(abstractvfs):' | |||||
276 |
|
276 | |||
277 | This class is used to hide the details of COW semantics and |
|
277 | This class is used to hide the details of COW semantics and | |
278 | remote file access from higher level code. |
|
278 | remote file access from higher level code. | |
|
279 | ||||
|
280 | 'cacheaudited' should be enabled only if (a) vfs object is short-lived, or | |||
|
281 | (b) the base directory is managed by hg and considered sort-of append-only. | |||
|
282 | See pathutil.pathauditor() for details. | |||
279 | ''' |
|
283 | ''' | |
280 |
def __init__(self, base, audit=True, expandpath=False, |
|
284 | def __init__(self, base, audit=True, cacheaudited=False, expandpath=False, | |
|
285 | realpath=False): | |||
281 | if expandpath: |
|
286 | if expandpath: | |
282 | base = util.expandpath(base) |
|
287 | base = util.expandpath(base) | |
283 | if realpath: |
|
288 | if realpath: | |
284 | base = os.path.realpath(base) |
|
289 | base = os.path.realpath(base) | |
285 | self.base = base |
|
290 | self.base = base | |
|
291 | self._cacheaudited = cacheaudited | |||
286 | self.mustaudit = audit |
|
292 | self.mustaudit = audit | |
287 | self.createmode = None |
|
293 | self.createmode = None | |
288 | self._trustnlink = None |
|
294 | self._trustnlink = None | |
@@ -295,7 +301,8 b' class vfs(abstractvfs):' | |||||
295 | def mustaudit(self, onoff): |
|
301 | def mustaudit(self, onoff): | |
296 | self._audit = onoff |
|
302 | self._audit = onoff | |
297 | if onoff: |
|
303 | if onoff: | |
298 |
self.audit = pathutil.pathauditor( |
|
304 | self.audit = pathutil.pathauditor( | |
|
305 | self.base, cached=self._cacheaudited) | |||
299 | else: |
|
306 | else: | |
300 | self.audit = util.always |
|
307 | self.audit = util.always | |
301 |
|
308 |
@@ -169,9 +169,9 b' and the rebase should fail (issue5628)' | |||||
169 | $ hg up -qC 2 |
|
169 | $ hg up -qC 2 | |
170 | $ hg rebase -s 2 -d 1 --config extensions.rebase= |
|
170 | $ hg rebase -s 2 -d 1 --config extensions.rebase= | |
171 | rebasing 2:e73c21d6b244 "file a/poisoned" (tip) |
|
171 | rebasing 2:e73c21d6b244 "file a/poisoned" (tip) | |
172 | saved backup bundle to * (glob) |
|
172 | abort: path 'a/poisoned' traverses symbolic link 'a' | |
|
173 | [255] | |||
173 | $ ls ../merge-symlink-out |
|
174 | $ ls ../merge-symlink-out | |
174 | poisoned |
|
|||
175 |
|
175 | |||
176 | $ cd .. |
|
176 | $ cd .. | |
177 |
|
177 | |||
@@ -211,10 +211,9 b' audited first by calculateupdates(), whe' | |||||
211 |
|
211 | |||
212 | $ hg up -qC null |
|
212 | $ hg up -qC null | |
213 | $ hg up 1 |
|
213 | $ hg up 1 | |
214 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
214 | abort: path 'a/b' traverses symbolic link 'a' | |
|
215 | [255] | |||
215 | $ ls ../update-symlink-out |
|
216 | $ ls ../update-symlink-out | |
216 | b |
|
|||
217 | $ rm ../update-symlink-out/b |
|
|||
218 |
|
217 | |||
219 | try branch update replacing directory with symlink, and its content: the |
|
218 | try branch update replacing directory with symlink, and its content: the | |
220 | path 'a' is audited as a directory first, which should be audited again as |
|
219 | path 'a' is audited as a directory first, which should be audited again as | |
@@ -223,9 +222,9 b' a symlink.' | |||||
223 | $ rm -f a |
|
222 | $ rm -f a | |
224 | $ hg up -qC 2 |
|
223 | $ hg up -qC 2 | |
225 | $ hg up 1 |
|
224 | $ hg up 1 | |
226 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
225 | abort: path 'a/b' traverses symbolic link 'a' | |
|
226 | [255] | |||
227 | $ ls ../update-symlink-out |
|
227 | $ ls ../update-symlink-out | |
228 | b |
|
|||
229 |
|
228 | |||
230 | $ cd .. |
|
229 | $ cd .. | |
231 |
|
230 |
@@ -956,10 +956,9 b' and the merge should fail (issue5628)' | |||||
956 | *** runcommand up -qC 2 |
|
956 | *** runcommand up -qC 2 | |
957 | *** runcommand up -qC 1 |
|
957 | *** runcommand up -qC 1 | |
958 | *** runcommand merge 2 |
|
958 | *** runcommand merge 2 | |
959 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
959 | abort: path 'a/poisoned' traverses symbolic link 'a' | |
960 | (branch merge, don't forget to commit) |
|
960 | [255] | |
961 | $ ls ../merge-symlink-out |
|
961 | $ ls ../merge-symlink-out | |
962 | poisoned |
|
|||
963 |
|
962 | |||
964 | cache of repo.auditor should be discarded, so matcher would never traverse |
|
963 | cache of repo.auditor should be discarded, so matcher would never traverse | |
965 | symlinks: |
|
964 | symlinks: | |
@@ -983,7 +982,8 b' symlinks:' | |||||
983 | *** runcommand up -qC 0 |
|
982 | *** runcommand up -qC 0 | |
984 | *** runcommand up -qC 1 |
|
983 | *** runcommand up -qC 1 | |
985 | *** runcommand files a/poisoned |
|
984 | *** runcommand files a/poisoned | |
986 | [1] |
|
985 | abort: path 'a/poisoned' traverses symbolic link 'a' | |
|
986 | [255] | |||
987 |
|
987 | |||
988 | $ cd .. |
|
988 | $ cd .. | |
989 |
|
989 |
General Comments 0
You need to be logged in to leave comments.
Login now