D5278: narrow: detect if narrowspec was changed in a different share
martinvonz (Martin von Zweigbergk)
phabricator at mercurial-scm.org
Thu Nov 15 05:32:06 UTC 2018
martinvonz updated this revision to Diff 12548.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D5278?vs=12547&id=12548
REVISION DETAIL
https://phab.mercurial-scm.org/D5278
AFFECTED FILES
mercurial/localrepo.py
mercurial/narrowspec.py
tests/test-narrow-share.t
CHANGE DETAILS
diff --git a/tests/test-narrow-share.t b/tests/test-narrow-share.t
--- a/tests/test-narrow-share.t
+++ b/tests/test-narrow-share.t
@@ -77,11 +77,13 @@
I path:d7
# d1/f, d3/f, d3/g and d5/f should no longer be reported
$ hg -R main files
+ not deleting possibly dirty file d3/f
+ not deleting possibly dirty file d3/g
+ not deleting possibly dirty file d5/f
main/d7/f
# d1/f should no longer be there, d3/f should be since it was dirty, d3/g should be there since
# it was added, and d5/f should be since we couldn't be sure it was clean
$ find main/d* -type f
- main/d1/f
main/d3/g
main/d3/f
main/d5/f
@@ -105,17 +107,44 @@
$ hg -R main files
main/d1/f
main/d3/f
- main/d3/g
main/d7/f
# d1/f, d3/f, d3/g should be back
$ hg -R main files
main/d1/f
main/d3/f
- main/d3/g
main/d7/f
# d3/f should be modified (not clobbered by the widening), and d3/g should be untracked
$ hg -R main st --all
M d3/f
- A d3/g
+ ? d3/g
C d1/f
C d7/f
+
+Check that failure to get the lock is not a problem
+
+#if unix-permissions system-sh
+ $ cat >> sleep10 << EOF
+ > sleep 10
+ > EOF
+ $ chmod +x sleep10
+ $ hg -R main --config hooks.update="$TESTTMP/sleep10" up 9 -C > /dev/null 2>&1 &
+ $ echo $! > $DAEMON_PIDS
+ $ hg -R share1 tracked --removeinclude d7 -q
+# d7/f is no longer reported
+ $ hg -R main files
+ main/d1/f
+ main/d3/f
+# but d7/f is still in the dirstate because we failed to update it earlier
+ $ hg -R main debugdirstate --no-dates
+ n 644 2 * d1/f (glob)
+ n 644 2 * d3/f (glob)
+ n 644 2 * d7/f (glob)
+ $ killdaemons.py
+# Now the update should work
+ $ hg -R main st
+ ? d3/g
+ $ hg -R main debugdirstate --no-dates
+ n 644 2 * d1/f (glob)
+ n 644 2 * d3/f (glob)
+
+#endif
diff --git a/mercurial/narrowspec.py b/mercurial/narrowspec.py
--- a/mercurial/narrowspec.py
+++ b/mercurial/narrowspec.py
@@ -18,7 +18,10 @@
util,
)
+# The file in .hg/store/ that indicates which paths exit in the store
FILENAME = 'narrowspec'
+# The file in .hg/ that indicates which paths exit in the dirstate
+DIRSTATE_FILENAME = 'narrowspec.dirstate'
# Pattern prefixes that are allowed in narrow patterns. This list MUST
# only contain patterns that are fast and safe to evaluate. Keep in mind
@@ -226,3 +229,75 @@
else:
res_includes = set(req_includes)
return res_includes, res_excludes, invalid_includes
+
+# These two are extracted for extensions (specifically for Google's CitC file
+# system)
+def _deletecleanfiles(repo, files):
+ for f in files:
+ repo.wvfs.unlinkpath(f)
+
+def _writeaddedfiles(repo, pctx, files):
+ for f in files:
+ if not repo.wvfs.exists(f):
+ repo.wvfs.write(f, pctx[f].data())
+
+def updatesharenarrowspec(repo):
+ # Check if we have already compared the working copy's narrowspec to the
+ # store's narrowspec. This prevents infinite recursion with manifestlog
+ # creation.
+ if getattr(repo, '_sharenarrowspecchecked', False):
+ return
+ repo._sharenarrowspecchecked = True
+
+ oldspec = repo.vfs.tryread(DIRSTATE_FILENAME)
+ newspec = repo.svfs.tryread(FILENAME)
+ if not oldspec:
+ # There was no narrowspec for the working copy, only one for the
+ # store. That should only happen on repos created before we had
+ # support for narrow+share. Assume the dirstate already matches
+ # the store's narrowspec and write the store's narrowspec to
+ # the working copy narrowspec.
+ try:
+ with repo.wlock(wait=False):
+ repo.vfs.write(DIRSTATE_FILENAME, newspec)
+ except error.LockError:
+ pass
+ return
+ elif newspec == oldspec:
+ return
+
+ try:
+ wlock = repo.wlock(False)
+ except error.LockError:
+ # We cannot update the dirstate and .hg/narrowspec.dirstate this
+ # time. That's fine, we'll try again on the next hg invocation.
+ return
+ with wlock:
+ oldincludes, oldexcludes = parseconfig(repo.ui, oldspec)
+ newincludes, newexcludes = parseconfig(repo.ui, newspec)
+ oldmatch = match(repo.root, include=oldincludes, exclude=oldexcludes)
+ newmatch = match(repo.root, include=newincludes, exclude=newexcludes)
+ addedmatch = matchmod.differencematcher(newmatch, oldmatch)
+ removedmatch = matchmod.differencematcher(oldmatch, newmatch)
+
+ ds = repo.dirstate
+ lookup, status = ds.status(removedmatch, subrepos=[], ignored=False,
+ clean=True, unknown=False)
+ _deletecleanfiles(repo, status.clean)
+ trackeddirty = lookup + status.modified + status.added
+ for f in sorted(trackeddirty):
+ repo.ui.status(_('not deleting possibly dirty file %s\n') % f)
+ for f in status.clean + trackeddirty:
+ ds.drop(f)
+
+ pctx = repo['.']
+ newfiles = list(pctx.manifest().walk(addedmatch))
+ # TODO: should probably use the merge.update() code here
+ # so the file-writing is parallelized
+ for f in newfiles:
+ if f not in ds:
+ ds.normallookup(f)
+ _writeaddedfiles(repo, pctx, newfiles)
+
+ ds.write(repo.currenttransaction())
+ repo.vfs.write(DIRSTATE_FILENAME, newspec)
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1215,6 +1215,7 @@
def _narrowmatch(self):
if repository.NARROW_REQUIREMENT not in self.requirements:
return matchmod.always(self.root, '')
+ narrowspec.updatesharenarrowspec(self)
include, exclude = self.narrowpats
return narrowspec.match(self.root, include=include, exclude=exclude)
To: martinvonz, durin42, #hg-reviewers
Cc: mercurial-devel
More information about the Mercurial-devel
mailing list