mercurial/bundle2.py
changeset 20877 9e9e3a4e9261
parent 20876 ddd56f3eb786
child 20887 662b79be093c
equal deleted inserted replaced
20876:ddd56f3eb786 20877:9e9e3a4e9261
    82     interpret the part payload.
    82     interpret the part payload.
    83 
    83 
    84     The binary format of the header is has follow
    84     The binary format of the header is has follow
    85 
    85 
    86     :typesize: (one byte)
    86     :typesize: (one byte)
       
    87 
    87     :typename: alphanumerical part name
    88     :typename: alphanumerical part name
    88     :option: we do not support option yet this denoted by two 16 bites zero.
    89 
       
    90     :parameters:
       
    91 
       
    92         Part's parameter may have arbitraty content, the binary structure is::
       
    93 
       
    94             <mandatory-count><advisory-count><param-sizes><param-data>
       
    95 
       
    96         :mandatory-count: 1 byte, number of mandatory parameters
       
    97 
       
    98         :advisory-count:  1 byte, number of advisory parameters
       
    99 
       
   100         :param-sizes:
       
   101 
       
   102             N couple of bytes, where N is the total number of parameters. Each
       
   103             couple contains (<size-of-key>, <size-of-value) for one parameter.
       
   104 
       
   105         :param-data:
       
   106 
       
   107             A blob of bytes from which each parameter key and value can be
       
   108             retrieved using the list of size couples stored in the previous
       
   109             field.
       
   110 
       
   111             Mandatory parameters comes first, then the advisory ones.
    89 
   112 
    90 :payload:
   113 :payload:
    91 
   114 
    92     payload is a series of `<chunksize><chunkdata>`.
   115     payload is a series of `<chunksize><chunkdata>`.
    93 
   116 
   113 
   136 
   114 _fstreamparamsize = '>H'
   137 _fstreamparamsize = '>H'
   115 _fpartheadersize = '>H'
   138 _fpartheadersize = '>H'
   116 _fparttypesize = '>B'
   139 _fparttypesize = '>B'
   117 _fpayloadsize = '>I'
   140 _fpayloadsize = '>I'
       
   141 _fpartparamcount = '>BB'
       
   142 
       
   143 def _makefpartparamsizes(nbparams):
       
   144     """return a struct format to read part parameter sizes
       
   145 
       
   146     The number parameters is variable so we need to build that format
       
   147     dynamically.
       
   148     """
       
   149     return '>'+('BB'*nbparams)
   118 
   150 
   119 class bundle20(object):
   151 class bundle20(object):
   120     """represent an outgoing bundle2 container
   152     """represent an outgoing bundle2 container
   121 
   153 
   122     Use the `addparam` method to add stream level parameter. and `addpart` to
   154     Use the `addparam` method to add stream level parameter. and `addpart` to
   261             self._offset = offset + size
   293             self._offset = offset + size
   262             return data
   294             return data
   263         typesize = _unpack(_fparttypesize, fromheader(1))[0]
   295         typesize = _unpack(_fparttypesize, fromheader(1))[0]
   264         parttype = fromheader(typesize)
   296         parttype = fromheader(typesize)
   265         self.ui.debug('part type: "%s"\n' % parttype)
   297         self.ui.debug('part type: "%s"\n' % parttype)
   266         assert fromheader(2) == '\0\0' # no option for now
   298         ## reading parameters
       
   299         # param count
       
   300         mancount, advcount = _unpack(_fpartparamcount, fromheader(2))
       
   301         self.ui.debug('part parameters: %i\n' % (mancount + advcount))
       
   302         # param size
       
   303         paramsizes = _unpack(_makefpartparamsizes(mancount + advcount),
       
   304                              fromheader(2*(mancount + advcount)))
       
   305         # make it a list of couple again
       
   306         paramsizes = zip(paramsizes[::2], paramsizes[1::2])
       
   307         # split mandatory from advisory
       
   308         mansizes = paramsizes[:mancount]
       
   309         advsizes = paramsizes[mancount:]
       
   310         # retrive param value
       
   311         manparams = []
       
   312         for key, value in mansizes:
       
   313             manparams.append((fromheader(key), fromheader(value)))
       
   314         advparams = []
       
   315         for key, value in advsizes:
       
   316             advparams.append((fromheader(key), fromheader(value)))
   267         del self._offset # clean up layer, nobody saw anything.
   317         del self._offset # clean up layer, nobody saw anything.
   268         self.ui.debug('part parameters: 0\n')
   318         ## part payload
   269         payload = []
   319         payload = []
   270         payloadsize = self._unpack(_fpayloadsize)[0]
   320         payloadsize = self._unpack(_fpayloadsize)[0]
   271         self.ui.debug('payload chunk size: %i\n' % payloadsize)
   321         self.ui.debug('payload chunk size: %i\n' % payloadsize)
   272         while payloadsize:
   322         while payloadsize:
   273             payload.append(self._readexact(payloadsize))
   323             payload.append(self._readexact(payloadsize))
   274             payloadsize = self._unpack(_fpayloadsize)[0]
   324             payloadsize = self._unpack(_fpayloadsize)[0]
   275             self.ui.debug('payload chunk size: %i\n' % payloadsize)
   325             self.ui.debug('payload chunk size: %i\n' % payloadsize)
   276         payload = ''.join(payload)
   326         payload = ''.join(payload)
   277         current = part(parttype, data=payload)
   327         current = part(parttype, manparams, advparams, data=payload)
   278         return current
   328         return current
   279 
   329 
   280 
   330 
   281 class part(object):
   331 class part(object):
   282     """A bundle2 part contains application level payload
   332     """A bundle2 part contains application level payload
   283 
   333 
   284     The part `type` is used to route the part to the application level
   334     The part `type` is used to route the part to the application level
   285     handler.
   335     handler.
   286     """
   336     """
   287 
   337 
   288     def __init__(self, parttype, data=''):
   338     def __init__(self, parttype, mandatoryparams=(), advisoryparams=(),
       
   339                  data=''):
   289         self.type = parttype
   340         self.type = parttype
   290         self.data = data
   341         self.data = data
       
   342         self.mandatoryparams = mandatoryparams
       
   343         self.advisoryparams = advisoryparams
   291 
   344 
   292     def getchunks(self):
   345     def getchunks(self):
   293         ### header
   346         #### header
       
   347         ## parttype
   294         header = [_pack(_fparttypesize, len(self.type)),
   348         header = [_pack(_fparttypesize, len(self.type)),
   295                   self.type,
   349                   self.type,
   296                   '\0\0', # No option support for now.
       
   297                  ]
   350                  ]
       
   351         ## parameters
       
   352         # count
       
   353         manpar = self.mandatoryparams
       
   354         advpar = self.advisoryparams
       
   355         header.append(_pack(_fpartparamcount, len(manpar), len(advpar)))
       
   356         # size
       
   357         parsizes = []
       
   358         for key, value in manpar:
       
   359             parsizes.append(len(key))
       
   360             parsizes.append(len(value))
       
   361         for key, value in advpar:
       
   362             parsizes.append(len(key))
       
   363             parsizes.append(len(value))
       
   364         paramsizes = _pack(_makefpartparamsizes(len(parsizes) / 2), *parsizes)
       
   365         header.append(paramsizes)
       
   366         # key, value
       
   367         for key, value in manpar:
       
   368             header.append(key)
       
   369             header.append(value)
       
   370         for key, value in advpar:
       
   371             header.append(key)
       
   372             header.append(value)
       
   373         ## finalize header
   298         headerchunk = ''.join(header)
   374         headerchunk = ''.join(header)
   299         yield _pack(_fpartheadersize, len(headerchunk))
   375         yield _pack(_fpartheadersize, len(headerchunk))
   300         yield headerchunk
   376         yield headerchunk
       
   377         ## payload
   301         # we only support fixed size data now.
   378         # we only support fixed size data now.
   302         # This will be improved in the future.
   379         # This will be improved in the future.
   303         if len(self.data):
   380         if len(self.data):
   304             yield _pack(_fpayloadsize, len(self.data))
   381             yield _pack(_fpayloadsize, len(self.data))
   305             yield self.data
   382             yield self.data
   306         # end of payload
   383         # end of payload
   307         yield _pack(_fpayloadsize, 0)
   384         yield _pack(_fpayloadsize, 0)
   308 
   385 
   309