diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py --- a/mercurial/bundle2.py +++ b/mercurial/bundle2.py @@ -21,7 +21,7 @@ The format is architectured as follow - payload parts (any number) - end of stream marker. -The current implementation is limited to empty bundle. +The current implementation accept some stream level option but no part. Details on the Binary format ============================ @@ -37,14 +37,18 @@ Binary format is as follow The total number of Bytes used by the parameters - Currently force to 0. - :params value: arbitrary number of Bytes A blob of `params size` containing the serialized version of all stream level parameters. - Currently always empty. + The blob contains a space separated list of parameters. + + Parameter value are not supported yet. + + Special character in param name are not supported yet. + + Payload part @@ -61,32 +65,57 @@ Binary format is as follow """ import util +import struct + import changegroup from i18n import _ +_pack = struct.pack +_unpack = struct.unpack + _magicstring = 'HG20' +_fstreamparamsize = '>H' + class bundle20(object): """represent an outgoing bundle2 container - People will eventually be able to add param and parts to this object and - generated a stream from it.""" + Use the `addparam` method to add stream level parameter. Then call + `getchunks` to retrieve all the binary chunks of datathat compose the + bundle2 container. + + This object does not support payload part yet.""" def __init__(self): self._params = [] self._parts = [] + def addparam(self, name, value=None): + """add a stream level parameter""" + self._params.append((name, value)) + def getchunks(self): yield _magicstring - # no support for any param yet - # to be obviously fixed soon. - assert not self._params - yield '\0\0' + param = self._paramchunk() + yield _pack(_fstreamparamsize, len(param)) + if param: + yield param + # no support for parts # to be obviously fixed soon. assert not self._parts yield '\0\0' + def _paramchunk(self): + """return a encoded version of all stream parameters""" + blocks = [] + for key, value in self._params: + # XXX no support for value yet + assert value is None + # XXX no escaping yet + blocks.append(key) + return ' '.join(blocks) + class unbundle20(object): """interpret a bundle2 stream diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t --- a/tests/test-bundle2.t +++ b/tests/test-bundle2.t @@ -14,11 +14,15 @@ Create an extension to test bundle2 API > cmdtable = {} > command = cmdutil.command(cmdtable) > - > @command('bundle2', [], '') - > def cmdbundle2(ui, repo): + > @command('bundle2', + > [('', 'param', [], 'stream level parameter'),], + > '') + > def cmdbundle2(ui, repo, **opts): > """write a bundle2 container on standard ouput""" - > bundle = bundle2.bundle20() - > for chunk in bundle.getchunks(): + > bundler = bundle2.bundle20() + > for p in opts['param']: + > bundler.addparam(p) + > for chunk in bundler.getchunks(): > ui.write(chunk) > > @command('unbundle2', [], '') @@ -42,12 +46,19 @@ The extension requires a repo (currently $ hg add a $ hg commit -m 'a' -Test simple generation of empty bundle + +Empty bundle +================= + +- no option +- no parts + +Test bundling $ hg bundle2 HG20\x00\x00\x00\x00 (no-eol) (esc) -Test parsing of an empty bundle +Test unbundling $ hg bundle2 | hg unbundle2 options count: 0 @@ -60,3 +71,24 @@ Test old style bundle are detected and r $ hg unbundle2 < ../bundle.hg abort: unknown bundle version 10 [255] + +Test parameters +================= + +- some options +- no parts + +advisory parameters, no value +------------------------------- + +Simplest possible parameters form + +Test generation + + $ hg bundle2 --param 'caution' + HG20\x00\x07caution\x00\x00 (no-eol) (esc) + +Test generation multiple option + + $ hg bundle2 --param 'caution' --param 'meal' + HG20\x00\x0ccaution meal\x00\x00 (no-eol) (esc)