@@ -87,12 +87,17 @@ Binary format is as follow
:typename: alphanumerical part name
:option: we do not support option yet this denoted by two 16 bites zero.
:payload:
- The current payload is a 32bit integer with a value of 0. This is
- considered an "empty" payload.
+ payload is a series of `<chunksize><chunkdata>`.
+
+ `chunksize` is a 32 bits integer, `chunkdata` are plain bytes (as much as
+ `chunksize` says)` The payload part is concluded by a zero size chunk.
+
+ The current implementation always produces either zero or one chunk.
+ This is an implementation limitation that will ultimatly be lifted.
"""
import util
import struct
import urllib
@@ -107,10 +112,11 @@ from i18n import _
_magicstring = 'HG20'
_fstreamparamsize = '>H'
_fpartheadersize = '>H'
_fparttypesize = '>B'
+_fpayloadsize = '>I'
class bundle20(object):
"""represent an outgoing bundle2 container
Use the `addparam` method to add stream level parameter. and `addpart` to
@@ -255,16 +261,22 @@ class unbundle20(object):
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')
+ payload = []
+ payloadsize = self._unpack(_fpayloadsize)[0]
+ self.ui.debug('payload chunk size: %i\n' % payloadsize)
+ while payloadsize:
+ payload.append(self._readexact(payloadsize))
+ payloadsize = self._unpack(_fpayloadsize)[0]
+ self.ui.debug('payload chunk size: %i\n' % payloadsize)
+ payload = ''.join(payload)
+ current = part(parttype, data=payload)
return current
class part(object):
"""A bundle2 part contains application level payload
@@ -284,9 +296,14 @@ class part(object):
'\0\0', # No option support for now.
]
headerchunk = ''.join(header)
yield _pack(_fpartheadersize, len(headerchunk))
yield headerchunk
- # force empty part for now
- yield '\0\0\0\0'
+ # we only support fixed size data now.
+ # This will be improved in the future.
+ if len(self.data):
+ yield _pack(_fpayloadsize, len(self.data))
+ yield self.data
+ # end of payload
+ yield _pack(_fpayloadsize, 0)
@@ -13,10 +13,15 @@ Create an extension to test bundle2 API
> from mercurial import util
> from mercurial import bundle2
> cmdtable = {}
> command = cmdutil.command(cmdtable)
>
+ > ELEPHANTSSONG = """Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
+ > Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+ > Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko."""
+ > assert len(ELEPHANTSSONG) == 178 # future test say 178 bytes, trust it.
+ >
> @command('bundle2',
> [('', 'param', [], 'stream level parameter'),
> ('', 'parts', False, 'include some arbitrary parts to the bundle'),],
> '[OUTPUTFILE]')
> def cmdbundle2(ui, repo, path=None, **opts):
@@ -33,10 +38,12 @@ Create an extension to test bundle2 API
> part = bundle2.part('test:empty')
> bundler.addpart(part)
> # add a second one to make sure we handle multiple parts
> part = bundle2.part('test:empty')
> bundler.addpart(part)
+ > part = bundle2.part('test:song', data=ELEPHANTSSONG)
+ > bundler.addpart(part)
>
> if path is None:
> file = sys.stdout
> else:
> file = open(path, 'w')
@@ -60,10 +67,11 @@ Create an extension to test bundle2 API
> 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)
+ > ui.write(' payload: %i bytes\n' % len(p.data))
> EOF
$ cat >> $HGRCPATH << EOF
> [extensions]
> bundle2=$TESTTMP/bundle2.py
> EOF
@@ -236,23 +244,30 @@ Test part
start emission of HG20 stream
bundle parameter:
start of parts
bundle part: "test:empty"
bundle part: "test:empty"
+ bundle part: "test:song"
end of bundle
$ cat ../parts.hg2
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)
+ test:empty\x00\x00\x00\x00\x00\x00\x00\x0c test:song\x00\x00\x00\x00\x00\xb2Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko (esc)
+ Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+ Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
$ hg unbundle2 < ../parts.hg2
options count: 0
- parts count: 2
+ parts count: 3
:test:empty:
+ payload: 0 bytes
:test:empty:
+ payload: 0 bytes
+ :test:song:
+ payload: 178 bytes
$ hg unbundle2 --debug < ../parts.hg2
start processing of HG20 stream
reading bundle2 stream parameters
options count: 0
@@ -263,10 +278,19 @@ Test part
payload chunk size: 0
part header size: 13
part type: "test:empty"
part parameters: 0
payload chunk size: 0
+ part header size: 12
+ part type: "test:song"
+ part parameters: 0
+ payload chunk size: 178
+ payload chunk size: 0
part header size: 0
end of bundle2 stream
- parts count: 2
+ parts count: 3
:test:empty:
+ payload: 0 bytes
:test:empty:
+ payload: 0 bytes
+ :test:song:
+ payload: 178 bytes