changegroup: cg3 has two empty groups *after* manifests
changegroup.getchunks() determines the end of the stream by looking
for an empty chunk group (two consecutive empty chunks). It ignores
empty groups in the first two groups. Changegroup 3 introduced an
empty chunk between the manifests and the files, which confuses
getchunks(). Since it comes after the first two, getchunks() will stop
there.
Fix by rewriting getchunks so it first counts two groups (empty or
not) and then keeps antostarts counting empty groups. With this counting,
changegroup 1 and 2 have exactly one empty group after the first two
groups, while changegroup 3 has two (one for directories and one for
files).
It's a little hard to test this at this point, but I have verified
that this patch fixes narrowhg (which was broken before this
patch). Also, future patches will fix "hg strip" with treemanifests,
and once that's done, getchunks() will be tested through tests of "hg
strip".
--- a/mercurial/changegroup.py Tue Jan 19 06:00:59 2016 +0100
+++ b/mercurial/changegroup.py Tue Jan 19 17:44:25 2016 -0800
@@ -189,6 +189,8 @@
deltaheader = _CHANGEGROUPV1_DELTA_HEADER
deltaheadersize = struct.calcsize(deltaheader)
version = '01'
+ _grouplistcount = 1 # One list of files after the manifests
+
def __init__(self, fh, alg):
if alg == 'UN':
alg = None # get more modern without breaking too much
@@ -270,15 +272,19 @@
"""
# an empty chunkgroup is the end of the changegroup
# a changegroup has at least 2 chunkgroups (changelog and manifest).
- # after that, an empty chunkgroup is the end of the changegroup
- empty = False
+ # after that, changegroup versions 1 and 2 have a series of groups
+ # with one group per file. changegroup 3 has a series of directory
+ # manifests before the files.
count = 0
- while not empty or count <= 2:
+ emptycount = 0
+ while emptycount < self._grouplistcount:
empty = True
count += 1
while True:
chunk = getchunk(self)
if not chunk:
+ if empty and count > 2:
+ emptycount += 1
break
empty = False
yield chunkheader(len(chunk))
@@ -515,6 +521,7 @@
deltaheader = _CHANGEGROUPV3_DELTA_HEADER
deltaheadersize = struct.calcsize(deltaheader)
version = '03'
+ _grouplistcount = 2 # One list of manifests and one list of files
def _deltaheader(self, headertuple, prevnode):
node, p1, p2, deltabase, cs, flags = headertuple