[PATCH 1 of 4] bundle2: support bundling of empty part (with a type)
pierre-yves.david at ens-lyon.org
pierre-yves.david at ens-lyon.org
Wed Mar 26 21:19:42 CDT 2014
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at fb.com>
# Date 1395178173 25200
# Tue Mar 18 14:29:33 2014 -0700
# Node ID 447f461fcdc476a60412f7e91b29e38d5b46de22
# Parent 5c6341690ef3465393bc77b59aecffc201ebd9b7
bundle2: support bundling of empty part (with a type)
Here start the work on bundle2 parts. Our first step is to be able to bundle a simplistic
part that just have a type, no parameters, empty payload.
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -19,12 +19,10 @@ The format is architectured as follow
- magic string
- stream level parameters
- payload parts (any number)
- end of stream marker.
-The current implementation accept some stream level option but no part.
-
Details on the Binary format
============================
All numbers are unsigned and big endian.
@@ -69,11 +67,31 @@ Binary format is as follow
:header size: (16 bits inter)
The total number of Bytes used by the part headers. When the header is empty
(size = 0) this is interpreted as the end of stream marker.
- Currently forced to 0 in the current state of the implementation
+:header:
+
+ The header contains data about how to interpret the part. it contains two
+ piece of data: the part type, and the part parameters.
+
+ The part type will be used to route the part to the proper application
+ level object that will interpret the part paylod.
+
+ The part option will be handed as argument this application level object.
+ They are meant to convey information that will help the application level
+ object to interpret the part payload.
+
+ 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.
+
+:payload:
+
+ The payload is currently alway empty this is denoted by a 32bits zero.
"""
import util
import struct
import urllib
@@ -86,19 +104,19 @@ from i18n import _
_unpack = struct.unpack
_magicstring = 'HG20'
_fstreamparamsize = '>H'
+_fpartheadersize = '>H'
+_fparttypesize = '>B'
class bundle20(object):
"""represent an outgoing bundle2 container
- 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."""
+ Use the `addparam` method to add stream level parameter. and `addpart` to
+ populate it. Then call `getchunks` to retrieve all the binary chunks of
+ datathat compose the bundle2 container."""
def __init__(self, ui):
self.ui = ui
self._params = []
self._parts = []
@@ -109,22 +127,30 @@ class bundle20(object):
raise ValueError('empty parameter name')
if name[0] not in string.letters:
raise ValueError('non letter first character: %r' % name)
self._params.append((name, value))
+ def addpart(self, part):
+ """add a new part to the bundle2 container
+
+ Parts contains the actuall applicative payload."""
+ self._parts.append(part)
+
def getchunks(self):
self.ui.debug('start emission of %s stream\n' % _magicstring)
yield _magicstring
param = self._paramchunk()
self.ui.debug('bundle parameter: %s\n' % param)
yield _pack(_fstreamparamsize, len(param))
if param:
yield param
- # no support for parts
- # to be obviously fixed soon.
- assert not self._parts
+ self.ui.debug('start of parts\n')
+ for part in self._parts:
+ self.ui.debug('bundling part: "%s"\n' % part.type)
+ for chunk in part.getchunks():
+ yield chunk
self.ui.debug('end of bundle\n')
yield '\0\0'
def _paramchunk(self):
"""return a encoded version of all stream parameters"""
@@ -215,7 +241,28 @@ class unbundle20(object):
"""return None when an end of stream markers is reach"""
headersize = self._readexact(2)
assert headersize == '\0\0'
return None
+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):
+ self.type = parttype
+
+ def getchunks(self):
+ ### header
+ header = [_pack(_fparttypesize, len(self.type)),
+ self.type,
+ '\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'
+
+
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,12 @@ Create an extension to test bundle2 API
> from mercurial import bundle2
> cmdtable = {}
> command = cmdutil.command(cmdtable)
>
> @command('bundle2',
- > [('', 'param', [], 'stream level parameter'),],
+ > [('', 'param', [], 'stream level parameter'),
+ > ('', 'parts', False, 'include some arbitrary parts to the bundle'),],
> '[OUTPUTFILE]')
> def cmdbundle2(ui, repo, path=None, **opts):
> """write a bundle2 container on standard ouput"""
> bundler = bundle2.bundle20(ui)
> for p in opts['param']:
@@ -26,10 +27,17 @@ Create an extension to test bundle2 API
> try:
> bundler.addparam(*p)
> except ValueError, exc:
> raise util.Abort('%s' % exc)
>
+ > if opts['parts']:
+ > 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)
+ >
> if path is None:
> file = sys.stdout
> else:
> file = open(path, 'w')
>
@@ -176,10 +184,11 @@ Test debug output
bundling debug
$ hg bundle2 --debug --param 'e|! 7/=babar%#==tutu' --param simple ../out.hg2
start emission of HG20 stream
bundle parameter: e%7C%21%207/=babar%25%23%3D%3Dtutu simple
+ start of parts
end of bundle
file content is ok
$ cat ../out.hg2
@@ -213,5 +222,24 @@ empty parameter name
bad parameter name
$ hg bundle2 --param 42babar
abort: non letter first character: '42babar'
[255]
+
+
+Test part
+=================
+
+ $ hg bundle2 --parts ../parts.hg2 --debug
+ start emission of HG20 stream
+ bundle parameter:
+ start of parts
+ bundling part: "test:empty"
+ bundling part: "test:empty"
+ 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)
+
+
More information about the Mercurial-devel
mailing list