# HG changeset patch # User Pierre-Yves David # Date 1395295443 25200 # Node ID 9a75d2559cff01ed68c30720a72f6faf7c65d4aa # Parent 876c17336b4ef15559d5cb14dccf73e48f854d77 bundle2: support unbundling empty part We augment the unbundler to make it able to unbundle the empty part we are now able to bundle. diff -r 876c17336b4e -r 9a75d2559cff mercurial/bundle2.py --- a/mercurial/bundle2.py Fri Mar 28 17:00:13 2014 -0700 +++ b/mercurial/bundle2.py Wed Mar 19 23:04:03 2014 -0700 @@ -240,9 +240,31 @@ def _readpart(self): """return None when an end of stream markers is reach""" - headersize = self._readexact(2) - assert headersize == '\0\0' - return None + + headersize = self._unpack(_fpartheadersize)[0] + self.ui.debug('part header size: %i\n' % headersize) + if not headersize: + return None + headerblock = self._readexact(headersize) + # some utility to help reading from the header block + self._offset = 0 # layer violation to have something easy to understand + def fromheader(size): + """return the next byte from the header""" + offset = self._offset + data = headerblock[offset:(offset + size)] + self._offset = offset + size + return data + typesize = _unpack(_fparttypesize, fromheader(1))[0] + parttype = fromheader(typesize) + self.ui.debug('part type: "%s"\n' % parttype) + current = part(parttype) + assert fromheader(2) == '\0\0' # no option for now + del self._offset # clean up layer, nobody saw anything. + self.ui.debug('part parameters: 0\n') + assert self._readexact(4) == '\0\0\0\0' #empty payload + self.ui.debug('payload chunk size: 0\n') + return current + class part(object): """A bundle2 part contains application level payload @@ -251,8 +273,9 @@ handler. """ - def __init__(self, parttype): + def __init__(self, parttype, data=''): self.type = parttype + self.data = data def getchunks(self): ### header diff -r 876c17336b4e -r 9a75d2559cff tests/test-bundle2.t --- a/tests/test-bundle2.t Fri Mar 28 17:00:13 2014 -0700 +++ b/tests/test-bundle2.t Wed Mar 19 23:04:03 2014 -0700 @@ -60,6 +60,8 @@ > ui.write(' %s\n' % value) > parts = list(unbundler) > ui.write('parts count: %i\n' % len(parts)) + > for p in parts: + > ui.write(' :%s:\n' % p.type) > EOF $ cat >> $HGRCPATH << EOF > [extensions] @@ -206,6 +208,7 @@ babar%#==tutu - simple start extraction of bundle2 parts + part header size: 0 end of bundle2 stream parts count: 0 @@ -243,3 +246,27 @@ test:empty\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc) + $ hg unbundle2 < ../parts.hg2 + options count: 0 + parts count: 2 + :test:empty: + :test:empty: + + $ hg unbundle2 --debug < ../parts.hg2 + start processing of HG20 stream + reading bundle2 stream parameters + options count: 0 + start extraction of bundle2 parts + part header size: 13 + part type: "test:empty" + part parameters: 0 + payload chunk size: 0 + part header size: 13 + part type: "test:empty" + part parameters: 0 + payload chunk size: 0 + part header size: 0 + end of bundle2 stream + parts count: 2 + :test:empty: + :test:empty: