Mercurial > hg-stable
changeset 20877:9e9e3a4e9261
bundle2: part params
author | Pierre-Yves David <pierre-yves.david@fb.com> |
---|---|
date | Thu, 20 Mar 2014 01:24:45 -0700 |
parents | ddd56f3eb786 |
children | 09e7118715eb |
files | mercurial/bundle2.py tests/test-bundle2.t |
diffstat | 2 files changed, 120 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/bundle2.py Wed Mar 19 23:36:15 2014 -0700 +++ b/mercurial/bundle2.py Thu Mar 20 01:24:45 2014 -0700 @@ -84,8 +84,31 @@ The binary format of the header is has follow :typesize: (one byte) + :typename: alphanumerical part name - :option: we do not support option yet this denoted by two 16 bites zero. + + :parameters: + + Part's parameter may have arbitraty content, the binary structure is:: + + <mandatory-count><advisory-count><param-sizes><param-data> + + :mandatory-count: 1 byte, number of mandatory parameters + + :advisory-count: 1 byte, number of advisory parameters + + :param-sizes: + + N couple of bytes, where N is the total number of parameters. Each + couple contains (<size-of-key>, <size-of-value) for one parameter. + + :param-data: + + A blob of bytes from which each parameter key and value can be + retrieved using the list of size couples stored in the previous + field. + + Mandatory parameters comes first, then the advisory ones. :payload: @@ -115,6 +138,15 @@ _fpartheadersize = '>H' _fparttypesize = '>B' _fpayloadsize = '>I' +_fpartparamcount = '>BB' + +def _makefpartparamsizes(nbparams): + """return a struct format to read part parameter sizes + + The number parameters is variable so we need to build that format + dynamically. + """ + return '>'+('BB'*nbparams) class bundle20(object): """represent an outgoing bundle2 container @@ -263,9 +295,27 @@ typesize = _unpack(_fparttypesize, fromheader(1))[0] parttype = fromheader(typesize) self.ui.debug('part type: "%s"\n' % parttype) - assert fromheader(2) == '\0\0' # no option for now + ## reading parameters + # param count + mancount, advcount = _unpack(_fpartparamcount, fromheader(2)) + self.ui.debug('part parameters: %i\n' % (mancount + advcount)) + # param size + paramsizes = _unpack(_makefpartparamsizes(mancount + advcount), + fromheader(2*(mancount + advcount))) + # make it a list of couple again + paramsizes = zip(paramsizes[::2], paramsizes[1::2]) + # split mandatory from advisory + mansizes = paramsizes[:mancount] + advsizes = paramsizes[mancount:] + # retrive param value + manparams = [] + for key, value in mansizes: + manparams.append((fromheader(key), fromheader(value))) + advparams = [] + for key, value in advsizes: + advparams.append((fromheader(key), fromheader(value))) del self._offset # clean up layer, nobody saw anything. - self.ui.debug('part parameters: 0\n') + ## part payload payload = [] payloadsize = self._unpack(_fpayloadsize)[0] self.ui.debug('payload chunk size: %i\n' % payloadsize) @@ -274,7 +324,7 @@ payloadsize = self._unpack(_fpayloadsize)[0] self.ui.debug('payload chunk size: %i\n' % payloadsize) payload = ''.join(payload) - current = part(parttype, data=payload) + current = part(parttype, manparams, advparams, data=payload) return current @@ -285,19 +335,46 @@ handler. """ - def __init__(self, parttype, data=''): + def __init__(self, parttype, mandatoryparams=(), advisoryparams=(), + data=''): self.type = parttype self.data = data + self.mandatoryparams = mandatoryparams + self.advisoryparams = advisoryparams def getchunks(self): - ### header + #### header + ## parttype header = [_pack(_fparttypesize, len(self.type)), self.type, - '\0\0', # No option support for now. ] + ## parameters + # count + manpar = self.mandatoryparams + advpar = self.advisoryparams + header.append(_pack(_fpartparamcount, len(manpar), len(advpar))) + # size + parsizes = [] + for key, value in manpar: + parsizes.append(len(key)) + parsizes.append(len(value)) + for key, value in advpar: + parsizes.append(len(key)) + parsizes.append(len(value)) + paramsizes = _pack(_makefpartparamsizes(len(parsizes) / 2), *parsizes) + header.append(paramsizes) + # key, value + for key, value in manpar: + header.append(key) + header.append(value) + for key, value in advpar: + header.append(key) + header.append(value) + ## finalize header headerchunk = ''.join(header) yield _pack(_fpartheadersize, len(headerchunk)) yield headerchunk + ## payload # we only support fixed size data now. # This will be improved in the future. if len(self.data): @@ -306,4 +383,3 @@ # end of payload yield _pack(_fpayloadsize, 0) -
--- a/tests/test-bundle2.t Wed Mar 19 23:36:15 2014 -0700 +++ b/tests/test-bundle2.t Thu Mar 20 01:24:45 2014 -0700 @@ -42,6 +42,11 @@ > bundler.addpart(part) > part = bundle2.part('test:song', data=ELEPHANTSSONG) > bundler.addpart(part) + > part = bundle2.part('test:math', + > [('pi', '3.14'), ('e', '2.72')], + > [('cooking', 'raw')], + > '42') + > bundler.addpart(part) > > if path is None: > file = sys.stdout @@ -69,6 +74,8 @@ > ui.write('parts count: %i\n' % len(parts)) > for p in parts: > ui.write(' :%s:\n' % p.type) + > ui.write(' mandatory: %i\n' % len(p.mandatoryparams)) + > ui.write(' advisory: %i\n' % len(p.advisoryparams)) > ui.write(' payload: %i bytes\n' % len(p.data)) > EOF $ cat >> $HGRCPATH << EOF @@ -247,6 +254,7 @@ bundle part: "test:empty" bundle part: "test:empty" bundle part: "test:song" + bundle part: "test:math" end of bundle $ cat ../parts.hg2 @@ -254,18 +262,28 @@ test:empty\x00\x00\x00\x00\x00\x00\x00\r (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) + Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.\x00\x00\x00\x00\x00' test:math\x02\x01\x02\x04\x01\x04\x07\x03pi3.14e2.72cookingraw\x00\x00\x00\x0242\x00\x00\x00\x00\x00\x00 (no-eol) (esc) $ hg unbundle2 < ../parts.hg2 options count: 0 - parts count: 3 + parts count: 4 :test:empty: + mandatory: 0 + advisory: 0 payload: 0 bytes :test:empty: + mandatory: 0 + advisory: 0 payload: 0 bytes :test:song: + mandatory: 0 + advisory: 0 payload: 178 bytes + :test:math: + mandatory: 2 + advisory: 1 + payload: 2 bytes $ hg unbundle2 --debug < ../parts.hg2 start processing of HG20 stream @@ -285,12 +303,27 @@ part parameters: 0 payload chunk size: 178 payload chunk size: 0 + part header size: 39 + part type: "test:math" + part parameters: 3 + payload chunk size: 2 + payload chunk size: 0 part header size: 0 end of bundle2 stream - parts count: 3 + parts count: 4 :test:empty: + mandatory: 0 + advisory: 0 payload: 0 bytes :test:empty: + mandatory: 0 + advisory: 0 payload: 0 bytes :test:song: + mandatory: 0 + advisory: 0 payload: 178 bytes + :test:math: + mandatory: 2 + advisory: 1 + payload: 2 bytes