hgext/narrow/narrowrepo.py
changeset 36079 a2a6e724d61a
child 36088 8c31187b6717
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/narrow/narrowrepo.py	Mon Jan 29 16:19:33 2018 -0500
@@ -0,0 +1,110 @@
+# narrowrepo.py - repository which supports narrow revlogs, lazy loading
+#
+# Copyright 2017 Google, Inc.
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from __future__ import absolute_import
+
+from mercurial import (
+    bundlerepo,
+    localrepo,
+    match as matchmod,
+    scmutil,
+)
+
+from .. import (
+    share,
+)
+
+from . import (
+    narrowrevlog,
+    narrowspec,
+)
+
+requirement = 'narrowhg'
+
+def wrappostshare(orig, sourcerepo, destrepo, **kwargs):
+    orig(sourcerepo, destrepo, **kwargs)
+    if requirement in sourcerepo.requirements:
+        with destrepo.wlock():
+            with destrepo.vfs('shared', 'a') as fp:
+                fp.write(narrowspec.FILENAME + '\n')
+
+def unsharenarrowspec(orig, ui, repo, repopath):
+    if (requirement in repo.requirements
+        and repo.path == repopath and repo.shared()):
+        srcrepo = share._getsrcrepo(repo)
+        with srcrepo.vfs(narrowspec.FILENAME) as f:
+            spec = f.read()
+        with repo.vfs(narrowspec.FILENAME, 'w') as f:
+            f.write(spec)
+    return orig(ui, repo, repopath)
+
+def wraprepo(repo, opts_narrow):
+    """Enables narrow clone functionality on a single local repository."""
+
+    cacheprop = localrepo.storecache
+    if isinstance(repo, bundlerepo.bundlerepository):
+        # We have to use a different caching property decorator for
+        # bundlerepo because storecache blows up in strange ways on a
+        # bundlerepo. Fortunately, there's no risk of data changing in
+        # a bundlerepo.
+        cacheprop = lambda name: localrepo.unfilteredpropertycache
+
+    class narrowrepository(repo.__class__):
+
+        def _constructmanifest(self):
+            manifest = super(narrowrepository, self)._constructmanifest()
+            narrowrevlog.makenarrowmanifestrevlog(manifest, repo)
+            return manifest
+
+        @cacheprop('00manifest.i')
+        def manifestlog(self):
+            mfl = super(narrowrepository, self).manifestlog
+            narrowrevlog.makenarrowmanifestlog(mfl, self)
+            return mfl
+
+        def file(self, f):
+            fl = super(narrowrepository, self).file(f)
+            narrowrevlog.makenarrowfilelog(fl, self.narrowmatch())
+            return fl
+
+        @localrepo.repofilecache(narrowspec.FILENAME)
+        def narrowpats(self):
+            return narrowspec.load(self)
+
+        @localrepo.repofilecache(narrowspec.FILENAME)
+        def _narrowmatch(self):
+            include, exclude = self.narrowpats
+            if not opts_narrow and not include and not exclude:
+                return matchmod.always(self.root, '')
+            return narrowspec.match(self.root, include=include, exclude=exclude)
+
+        # TODO(martinvonz): make this property-like instead?
+        def narrowmatch(self):
+            return self._narrowmatch
+
+        def setnarrowpats(self, newincludes, newexcludes):
+            narrowspec.save(self, newincludes, newexcludes)
+            self.invalidate(clearfilecache=True)
+
+        # I'm not sure this is the right place to do this filter.
+        # context._manifestmatches() would probably be better, or perhaps
+        # move it to a later place, in case some of the callers do want to know
+        # which directories changed. This seems to work for now, though.
+        def status(self, *args, **kwargs):
+            s = super(narrowrepository, self).status(*args, **kwargs)
+            narrowmatch = self.narrowmatch()
+            modified = filter(narrowmatch, s.modified)
+            added = filter(narrowmatch, s.added)
+            removed = filter(narrowmatch, s.removed)
+            deleted = filter(narrowmatch, s.deleted)
+            unknown = filter(narrowmatch, s.unknown)
+            ignored = filter(narrowmatch, s.ignored)
+            clean = filter(narrowmatch, s.clean)
+            return scmutil.status(modified, added, removed, deleted, unknown,
+                                  ignored, clean)
+
+    repo.__class__ = narrowrepository