[PATCH 2 of 3] changegroup: move treemanifest support to changegroup4

Martin von Zweigbergk martinvonz at google.com
Mon Jan 11 17:35:47 CST 2016


# HG changeset patch
# User Martin von Zweigbergk <martinvonz at google.com>
# Date 1452298378 28800
#      Fri Jan 08 16:12:58 2016 -0800
# Node ID 79c2ea05342d96fe4179b3fcb9c6709149a9af6b
# Parent  ee464a97569061f4c8bb4af316a0517b4feb0ad7
changegroup: move treemanifest support to changegroup4

This moves the treemanifest support from cg3 to cg4. Since
treemanifests are experimental, it should be okay to break BC in
cg3. cg3 retains its support for revlog flags. With treemanifest
support in cg4 instead, the separation between directories and files
gets clearer, since the separation is clearer in the changegroup
format. The immediate benefit to me is that remotefilelog should not
need to be updated to work with treemanifests. It should also make
server.validate and progress output easier to get right.

diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -522,6 +522,32 @@
     """
     version = '04'
 
+    def _unpackmanifests(self, repo, revmap, trp, prog, numchanges):
+        wasempty = (len(repo.manifest) == 0)
+        super(cg4unpacker, self)._unpackmanifests(repo, revmap, trp, prog,
+                                                  numchanges)
+        while True:
+            chunkdata = self.filelogheader()
+            if not chunkdata:
+                break
+            # If we get here, there are directory manifests in the changegroup
+            d = chunkdata["filename"]
+            repo.ui.debug("adding %s revisions\n" % d)
+            # TODO fixup repo requirements safely
+            if 'treemanifest' not in repo.requirements:
+                if not wasempty:
+                    raise error.Abort(_(
+                        "bundle contains tree manifests, but local repo is "
+                        "non-empty and does not use tree manifests"))
+                repo.requirements.add('treemanifest')
+                repo._applyopenerreqs()
+                repo._writerequirements()
+                repo.manifest._treeondisk = True
+                repo.manifest._treeinmem = True
+            dirlog = repo.manifest.dirlog(d)
+            if not dirlog.addgroup(self, revmap, trp):
+                raise error.Abort(_("received file revlog group is empty"))
+
 class headerlessfixup(object):
     def __init__(self, fh, h):
         self._h = h
@@ -898,23 +924,6 @@
     version = '03'
     deltaheader = _CHANGEGROUPV3_DELTA_HEADER
 
-    def _packmanifests(self, mfnodes, tmfnodes, lookuplinknode):
-        # Note that debug prints are super confusing in this code, as
-        # tmfnodes gets populated by the calls to lookuplinknode in
-        # the superclass's manifest packer. In the future we should
-        # probably see if we can refactor this somehow to be less
-        # confusing.
-        for x in super(cg3packer, self)._packmanifests(
-            mfnodes, {}, lookuplinknode):
-            yield x
-        dirlog = self._repo.manifest.dirlog
-        for name, nodes in tmfnodes.iteritems():
-            # For now, directory headers are simply file headers with
-            # a trailing '/' on the path (already in the name).
-            yield self.fileheader(name)
-            for chunk in self.group(nodes, dirlog(name), nodes.get):
-                yield chunk
-
     def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
         return struct.pack(
             self.deltaheader, node, p1n, p2n, basenode, linknode, flags)
@@ -929,8 +938,15 @@
         # probably see if we can refactor this somehow to be less
         # confusing.
         for x in super(cg4packer, self)._packmanifests(
-            mfnodes, tmfnodes, lookuplinknode):
+            mfnodes, {}, lookuplinknode):
             yield x
+        dirlog = self._repo.manifest.dirlog
+        for name, nodes in tmfnodes.iteritems():
+            # For now, directory headers are simply file headers with
+            # a trailing '/' on the path.
+            yield self.fileheader(name)
+            for chunk in self.group(nodes, dirlog(name), nodes.get):
+                yield chunk
         yield self.close()
 
 packermap = {'01': (cg1packer, cg1unpacker),
@@ -1059,43 +1075,22 @@
 def _addchangegroupfiles(repo, source, revmap, trp, pr, needfiles, wasempty):
     revisions = 0
     files = 0
-    submfsdone = False
     while True:
         chunkdata = source.filelogheader()
         if not chunkdata:
-            if source.version == "04" and not submfsdone:
-                submfsdone = True
-                continue
             break
         f = chunkdata["filename"]
         repo.ui.debug("adding %s revisions\n" % f)
         pr()
-        directory = (f[-1] == '/')
-        if directory:
-            # a directory using treemanifests
-            # TODO fixup repo requirements safely
-            if 'treemanifest' not in repo.requirements:
-                if not wasempty:
-                    raise error.Abort(_(
-                        "bundle contains tree manifests, but local repo is "
-                        "non-empty and does not use tree manifests"))
-                repo.requirements.add('treemanifest')
-                repo._applyopenerreqs()
-                repo._writerequirements()
-                repo.manifest._treeondisk = True
-                repo.manifest._treeinmem = True
-            fl = repo.manifest.dirlog(f)
-        else:
-            fl = repo.file(f)
+        fl = repo.file(f)
         o = len(fl)
         try:
             if not fl.addgroup(source, revmap, trp):
                 raise error.Abort(_("received file revlog group is empty"))
         except error.CensoredBaseError as e:
             raise error.Abort(_("received delta base is censored: %s") % e)
-        if not directory:
-            revisions += len(fl) - o
-            files += 1
+        revisions += len(fl) - o
+        files += 1
         if f in needfiles:
             needs = needfiles[f]
             for new in xrange(o, len(fl)):


More information about the Mercurial-devel mailing list