# HG changeset patch # User Pierre-Yves David # Date 1395178122 25200 # Node ID 520df53ad26a9105f5d4a7647243567bb7a0e697 # Parent 9c5183cb9bca46c95b0e8cd94e99cb168df0a057 bundle2: a very first version of bundle2 unbundler This changeset introduce an unbundler class to match the bundle2 bundler. It is currently able to unbundle an empty bundle2 only and will gain more feature at the same pace than the bundler. It also comes with its special extension command in test. diff -r 9c5183cb9bca -r 520df53ad26a mercurial/bundle2.py --- a/mercurial/bundle2.py Tue Mar 18 14:00:50 2014 -0700 +++ b/mercurial/bundle2.py Tue Mar 18 14:28:42 2014 -0700 @@ -60,6 +60,10 @@ Currently forced to 0 in the current state of the implementation """ +import util +import changegroup + + _magicstring = 'HG20' class bundle20(object): @@ -82,3 +86,48 @@ # to be obviously fixed soon. assert not self._parts yield '\0\0' + +class unbundle20(object): + """interpret a bundle2 stream + + (this will eventually yield parts)""" + + def __init__(self, fp): + # assume the magic string is ok and drop it + # to be obviously fixed soon. + self._fp = fp + self._readexact(4) + + def _unpack(self, format): + """unpack this struct format from the stream""" + data = self._readexact(struct.calcsize(format)) + return _unpack(format, data) + + def _readexact(self, size): + """read exactly bytes from the stream""" + return changegroup.readexactly(self._fp, size) + + @util.propertycache + def params(self): + """dictionnary of stream level parameters""" + paramsize = self._readexact(2) + assert paramsize == '\0\0' + return {} + + def __iter__(self): + """yield all parts contained in the stream""" + # make sure param have been loaded + self.params + part = self._readpart() + while part is not None: + yield part + part = self._readpart() + + def _readpart(self): + """return None when an end of stream markers is reach""" + headersize = self._readexact(2) + assert headersize == '\0\0' + return None + + + diff -r 9c5183cb9bca -r 520df53ad26a tests/test-bundle2.t --- a/tests/test-bundle2.t Tue Mar 18 14:00:50 2014 -0700 +++ b/tests/test-bundle2.t Tue Mar 18 14:28:42 2014 -0700 @@ -8,6 +8,7 @@ > code. We still need to be able to test it while it grow up. > """ > + > import sys > from mercurial import cmdutil > from mercurial import bundle2 > cmdtable = {} @@ -19,6 +20,14 @@ > bundle = bundle2.bundle20() > for chunk in bundle.getchunks(): > ui.write(chunk) + > + > @command('unbundle2', [], '') + > def cmdunbundle2(ui, repo): + > """read a bundle2 container from standard input""" + > unbundler = bundle2.unbundle20(sys.stdin) + > ui.write('options count: %i\n' % len(unbundler.params)) + > parts = list(unbundler) + > ui.write('parts count: %i\n' % len(parts)) > EOF $ cat >> $HGRCPATH << EOF > [extensions] @@ -34,3 +43,9 @@ $ hg bundle2 HG20\x00\x00\x00\x00 (no-eol) (esc) + +Test parsing of an empty bundle + + $ hg bundle2 | hg unbundle2 + options count: 0 + parts count: 0