--- a/mercurial/manifest.py Sun Aug 26 13:09:35 2018 -0400
+++ b/mercurial/manifest.py Mon Aug 27 10:15:15 2018 -0700
@@ -1246,7 +1246,8 @@
self.write()
self._read = False
-class manifestrevlog(revlog.revlog):
+@interfaceutil.implementer(repository.imanifeststorage)
+class manifestrevlog(object):
'''A revlog that stores manifest texts. This is responsible for caching the
full-text manifest contents.
'''
@@ -1291,10 +1292,14 @@
else:
self._dirlogcache = {'': self}
- super(manifestrevlog, self).__init__(opener, indexfile,
- # only root indexfile is cached
- checkambig=not bool(tree),
- mmaplargeindex=True)
+ self._revlog = revlog.revlog(opener, indexfile,
+ # only root indexfile is cached
+ checkambig=not bool(tree),
+ mmaplargeindex=True)
+
+ self.index = self._revlog.index
+ self.version = self._revlog.version
+ self._generaldelta = self._revlog._generaldelta
def _setupmanifestcachehooks(self, repo):
"""Persist the manifestfulltextcache on lock release"""
@@ -1323,7 +1328,7 @@
return self._fulltextcache
def clearcaches(self, clear_persisted_data=False):
- super(manifestrevlog, self).clearcaches()
+ self._revlog.clearcaches()
self._fulltextcache.clear(clear_persisted_data=clear_persisted_data)
self._dirlogcache = {self._tree: self}
@@ -1350,9 +1355,10 @@
[(x, True) for x in removed])
arraytext, deltatext = m.fastdelta(self.fulltextcache[p1], work)
- cachedelta = self.rev(p1), deltatext
+ cachedelta = self._revlog.rev(p1), deltatext
text = util.buffer(arraytext)
- n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
+ n = self._revlog.addrevision(text, transaction, link, p1, p2,
+ cachedelta)
else:
# The first parent manifest isn't already loaded, so we'll
# just encode a fulltext of the manifest and pass that
@@ -1366,7 +1372,7 @@
arraytext = None
else:
text = m.text()
- n = self.addrevision(text, transaction, link, p1, p2)
+ n = self._revlog.addrevision(text, transaction, link, p1, p2)
arraytext = bytearray(text)
if arraytext is not None:
@@ -1395,12 +1401,90 @@
n = m2.node()
if not n:
- n = self.addrevision(text, transaction, link, m1.node(), m2.node())
+ n = self._revlog.addrevision(text, transaction, link, m1.node(),
+ m2.node())
# Save nodeid so parent manifest can calculate its nodeid
m.setnode(n)
return n
+ def __len__(self):
+ return len(self._revlog)
+
+ def __iter__(self):
+ return self._revlog.__iter__()
+
+ def rev(self, node):
+ return self._revlog.rev(node)
+
+ def node(self, rev):
+ return self._revlog.node(rev)
+
+ def lookup(self, value):
+ return self._revlog.lookup(value)
+
+ def parentrevs(self, rev):
+ return self._revlog.parentrevs(rev)
+
+ def parents(self, node):
+ return self._revlog.parents(node)
+
+ def linkrev(self, rev):
+ return self._revlog.linkrev(rev)
+
+ def checksize(self):
+ return self._revlog.checksize()
+
+ def revision(self, node, _df=None, raw=False):
+ return self._revlog.revision(node, _df=_df, raw=raw)
+
+ def revdiff(self, rev1, rev2):
+ return self._revlog.revdiff(rev1, rev2)
+
+ def cmp(self, node, text):
+ return self._revlog.cmp(node, text)
+
+ def deltaparent(self, rev):
+ return self._revlog.deltaparent(rev)
+
+ def emitrevisiondeltas(self, requests):
+ return self._revlog.emitrevisiondeltas(requests)
+
+ def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
+ return self._revlog.addgroup(deltas, linkmapper, transaction,
+ addrevisioncb=addrevisioncb)
+
+ def getstrippoint(self, minlink):
+ return self._revlog.getstrippoint(minlink)
+
+ def strip(self, minlink, transaction):
+ return self._revlog.strip(minlink, transaction)
+
+ def files(self):
+ return self._revlog.files()
+
+ def clone(self, tr, destrevlog, **kwargs):
+ if not isinstance(destrevlog, manifestrevlog):
+ raise error.ProgrammingError('expected manifestrevlog to clone()')
+
+ return self._revlog.clone(tr, destrevlog._revlog, **kwargs)
+
+ @property
+ def indexfile(self):
+ return self._revlog.indexfile
+
+ @indexfile.setter
+ def indexfile(self, value):
+ self._revlog.indexfile = value
+
+ @property
+ def opener(self):
+ return self._revlog.opener
+
+ @opener.setter
+ def opener(self, value):
+ self._revlog.opener = value
+
@interfaceutil.implementer(repository.imanifestlog)
class manifestlog(object):
"""A collection class representing the collection of manifest snapshots
--- a/mercurial/repository.py Sun Aug 26 13:09:35 2018 -0400
+++ b/mercurial/repository.py Mon Aug 27 10:15:15 2018 -0700
@@ -988,6 +988,166 @@
Returns the binary node of the created revision.
"""
+class imanifeststorage(interfaceutil.Interface):
+ """Storage interface for manifest data."""
+
+ index = interfaceutil.Attribute(
+ """An ``ifilerevisionssequence`` instance.""")
+
+ indexfile = interfaceutil.Attribute(
+ """Path of revlog index file.
+
+ TODO this is revlog specific and should not be exposed.
+ """)
+
+ opener = interfaceutil.Attribute(
+ """VFS opener to use to access underlying files used for storage.
+
+ TODO this is revlog specific and should not be exposed.
+ """)
+
+ version = interfaceutil.Attribute(
+ """Revlog version number.
+
+ TODO this is revlog specific and should not be exposed.
+ """)
+
+ _generaldelta = interfaceutil.Attribute(
+ """Whether generaldelta storage is being used.
+
+ TODO this is revlog specific and should not be exposed.
+ """)
+
+ fulltextcache = interfaceutil.Attribute(
+ """Dict with cache of fulltexts.
+
+ TODO this doesn't feel appropriate for the storage interface.
+ """)
+
+ def __len__():
+ """Obtain the number of revisions stored for this manifest."""
+
+ def __iter__():
+ """Iterate over revision numbers for this manifest."""
+
+ def rev(node):
+ """Obtain the revision number given a binary node.
+
+ Raises ``error.LookupError`` if the node is not known.
+ """
+
+ def node(rev):
+ """Obtain the node value given a revision number.
+
+ Raises ``error.LookupError`` if the revision is not known.
+ """
+
+ def lookup(value):
+ """Attempt to resolve a value to a node.
+
+ Value can be a binary node, hex node, revision number, or a bytes
+ that can be converted to an integer.
+
+ Raises ``error.LookupError`` if a ndoe could not be resolved.
+
+ TODO this is only used by debug* commands and can probably be deleted
+ easily.
+ """
+
+ def parents(node):
+ """Returns a 2-tuple of parent nodes for a node.
+
+ Values will be ``nullid`` if the parent is empty.
+ """
+
+ def parentrevs(rev):
+ """Like parents() but operates on revision numbers."""
+
+ def linkrev(rev):
+ """Obtain the changeset revision number a revision is linked to."""
+
+ def revision(node, _df=None, raw=False):
+ """Obtain fulltext data for a node."""
+
+ def revdiff(rev1, rev2):
+ """Obtain a delta between two revision numbers.
+
+ The returned data is the result of ``bdiff.bdiff()`` on the raw
+ revision data.
+ """
+
+ def cmp(node, fulltext):
+ """Compare fulltext to another revision.
+
+ Returns True if the fulltext is different from what is stored.
+ """
+
+ def emitrevisiondeltas(requests):
+ """Produce ``irevisiondelta`` from ``irevisiondeltarequest``s.
+
+ See the documentation for ``ifiledata`` for more.
+ """
+
+ def addgroup(deltas, linkmapper, transaction, addrevisioncb=None):
+ """Process a series of deltas for storage.
+
+ See the documentation in ``ifilemutation`` for more.
+ """
+
+ def getstrippoint(minlink):
+ """Find minimum revision that must be stripped to strip a linkrev.
+
+ See the documentation in ``ifilemutation`` for more.
+ """
+
+ def strip(minlink, transaction):
+ """Remove storage of items starting at a linkrev.
+
+ See the documentation in ``ifilemutation`` for more.
+ """
+
+ def checksize():
+ """Obtain the expected sizes of backing files.
+
+ TODO this is used by verify and it should not be part of the interface.
+ """
+
+ def files():
+ """Obtain paths that are backing storage for this manifest.
+
+ TODO this is used by verify and there should probably be a better API
+ for this functionality.
+ """
+
+ def deltaparent(rev):
+ """Obtain the revision that a revision is delta'd against.
+
+ TODO delta encoding is an implementation detail of storage and should
+ not be exposed to the storage interface.
+ """
+
+ def clone(tr, dest, **kwargs):
+ """Clone this instance to another."""
+
+ def clearcaches(clear_persisted_data=False):
+ """Clear any caches associated with this instance."""
+
+ def dirlog(d):
+ """Obtain a manifest storage instance for a tree."""
+
+ def add(m, transaction, link, p1, p2, added, removed, readtree=None):
+ """Add a revision to storage.
+
+ ``m`` is an object conforming to ``imanifestdict``.
+
+ ``link`` is the linkrev revision number.
+
+ ``p1`` and ``p2`` are the parent revision numbers.
+
+ ``added`` and ``removed`` are iterables of added and removed paths,
+ respectively.
+ """
+
class imanifestlog(interfaceutil.Interface):
"""Interface representing a collection of manifest snapshots.