Patchwork [2,of,4] bundle2: support unbundling empty part

login
register
mail settings
Submitter Pierre-Yves David
Date March 27, 2014, 2:19 a.m.
Message ID <436781b585ec855d0991.1395886783@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/4077/
State Superseded
Commit 9a75d2559cff01ed68c30720a72f6faf7c65d4aa
Headers show

Comments

Pierre-Yves David - March 27, 2014, 2:19 a.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1395295443 25200
#      Wed Mar 19 23:04:03 2014 -0700
# Node ID 436781b585ec855d099181ee7c45787b4975a784
# Parent  447f461fcdc476a60412f7e91b29e38d5b46de22
bundle2: support unbundling empty part

We augment the unbundler to make it able to unbundle the empty part we are now
able to bundle.

Patch

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -237,23 +237,44 @@  class unbundle20(object):
             part = self._readpart()
         self.ui.debug('end of bundle2 stream\n')
 
     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 bloc
+        def fromheader(size, _offset=[0]):
+            """return the next <size> byte from the header"""
+            offset = _offset[0] #small hack to make this mutable
+            data = headerblock[offset:(offset + size)]
+            _offset[0] = 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
+        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 actual application level payload
 
     The part have `type` used to route it to proper application level object
     that interpret its content.
     """
 
-    def __init__(self, parttype):
+    def __init__(self, parttype, data=''):
         self.type = parttype
+        self.data = data
 
     def getchunks(self):
         ### header
         header = [_pack(_fparttypesize, len(self.type)),
                   self.type,
diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t
--- a/tests/test-bundle2.t
+++ b/tests/test-bundle2.t
@@ -58,10 +58,12 @@  Create an extension to test bundle2 API
   >         value = params[key]
   >         if value is not None:
   >             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]
   > bundle2=$TESTTMP/bundle2.py
   > EOF
@@ -204,10 +206,11 @@  unbundling debug
   options count: 2
   - e|! 7/
       babar%#==tutu
   - simple
   start extraction of bundle2 parts
+  part header size: 0
   end of bundle2 stream
   parts count:   0
 
 
 Test buggy input
@@ -241,5 +244,29 @@  Test part
   HG20\x00\x00\x00\r (esc)
   test:empty\x00\x00\x00\x00\x00\x00\x00\r (esc)
   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: