bundle2: very first version of a bundle2 bundler
authorPierre-Yves David <pierre-yves.david@fb.com>
Tue, 18 Mar 2014 14:00:50 -0700
changeset 20801 9c5183cb9bca
parent 20800 8253e55930a3
child 20802 520df53ad26a
bundle2: very first version of a bundle2 bundler This changeset is the very first of a long series. It create a new bundle2 module and add a simple class that generate and empty bundle2 container. The module is documented with the current state of the implementation. For information about the final goal you may want to consult the mercurial wiki page: http://mercurial.selenic.com/wiki/BundleFormat2 The documentation of the module will be updated with later patches adding more and more feature to the format. This patches also introduce a test case. This test case build and use its own small extension that use the new bundle2 module. Since the new format is unable to do anything right now, we could not use real mercurial code to test it. Moreover, some advanced feature of the bundle2 spec will not be used by core mercurial at all. So we need to have them tested.
mercurial/bundle2.py
tests/test-bundle2.t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/bundle2.py	Tue Mar 18 14:00:50 2014 -0700
@@ -0,0 +1,84 @@
+# bundle2.py - generic container format to transmit arbitrary data.
+#
+# Copyright 2013 Facebook, Inc.
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+"""Handling of the new bundle2 format
+
+The goal of bundle2 is to act as an atomically packet to transmit a set of
+payloads in an application agnostic way. It consist in a sequence of "parts"
+that will be handed to and processed by the application layer.
+
+
+General format architecture
+===========================
+
+The format is architectured as follow
+
+ - magic string
+ - stream level parameters
+ - payload parts (any number)
+ - end of stream marker.
+
+The current implementation is limited to empty bundle.
+
+Details on the Binary format
+============================
+
+All numbers are unsigned and big endian.
+
+stream level parameters
+------------------------
+
+Binary format is as follow
+
+:params size: (16 bits integer)
+
+  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.
+
+
+Payload part
+------------------------
+
+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
+"""
+
+_magicstring = 'HG20'
+
+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."""
+
+    def __init__(self):
+        self._params = []
+        self._parts = []
+
+    def getchunks(self):
+        yield _magicstring
+        # no support for any param yet
+        # to be obviously fixed soon.
+        assert not self._params
+        yield '\0\0'
+        # no support for parts
+        # to be obviously fixed soon.
+        assert not self._parts
+        yield '\0\0'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bundle2.t	Tue Mar 18 14:00:50 2014 -0700
@@ -0,0 +1,36 @@
+
+Create an extension to test bundle2 API
+
+  $ cat > bundle2.py << EOF
+  > """A small extension to test bundle2 implementation
+  > 
+  > Current bundle2 implementation is far too limited to be used in any core
+  > code. We still need to be able to test it while it grow up.
+  > """
+  > 
+  > from mercurial import cmdutil
+  > from mercurial import bundle2
+  > cmdtable = {}
+  > command = cmdutil.command(cmdtable)
+  > 
+  > @command('bundle2', [], '')
+  > def cmdbundle2(ui, repo):
+  >     """write a bundle2 container on standard ouput"""
+  >     bundle = bundle2.bundle20()
+  >     for chunk in bundle.getchunks():
+  >         ui.write(chunk)
+  > EOF
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > bundle2=$TESTTMP/bundle2.py
+  > EOF
+
+The extension requires a repo (currently unused)
+
+  $ hg init main
+  $ cd main
+
+Test simple generation of empty bundle
+
+  $ hg bundle2
+  HG20\x00\x00\x00\x00 (no-eol) (esc)