Patchwork [3,of,6] bundle2: first version of a bundle processing

login
register
mail settings
Submitter Pierre-Yves David
Date April 1, 2014, 7:35 p.m.
Message ID <a624e622d98db1b9575d.1396380924@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/4182/
State Accepted
Commit deed5edb72de8f7fa442d2a97506ddea9c2d5ec4
Headers show

Comments

Pierre-Yves David - April 1, 2014, 7:35 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1395689133 25200
#      Mon Mar 24 12:25:33 2014 -0700
# Node ID a624e622d98db1b9575db11b73bdd803da02ef6b
# Parent  aa2c8feacdf701b95c8e6ca88d5a41e6ee26456f
bundle2: first version of a bundle processing

We now have a function that interpret part content.

This is a version early version of this function. It'll see major changes in
scope and API in future development. As for previous I'm just focussing on
getting minimal logic setup. Refining will happen with real world usage.

Patch

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -146,10 +146,52 @@  def _makefpartparamsizes(nbparams):
     The number parameters is variable so we need to build that format
     dynamically.
     """
     return '>'+('BB'*nbparams)
 
+
+parthandlermapping = {}
+
+def processbundle(repo, stream):
+    """This function process a bundle, apply effect to/from a repo
+
+    Currently it:
+    - parse a stream into an unbundle20 object
+    - iterate over each parts then search and use the proper handling code to
+      process the part.
+
+    Parts are processes in order.
+
+    This is very early version of this function that will be strongly reworked
+    before final usage.
+
+    All unknown parts are currently ignored (Mandatory parts logic will comes
+    later).
+    """
+    ui = repo.ui
+    # Extraction of the unbundler object will most likely change. It may be
+    # done outside of this function, the unbundler would be passed as argument.
+    # in all case the unbundler will eventually be created by a
+    # `changegroup.readbundle` style function.
+    unbundler = unbundle20(ui, stream)
+    # todo:
+    # - replace this is a init function soon.
+    # - exception catching
+    unbundler.params
+    for part in unbundler:
+        parttype = part.type
+        # part key are matched lower case
+        key = parttype.lower()
+        try:
+            handler = parthandlermapping[key]
+            ui.debug('found an handler for part %r\n' % parttype)
+        except KeyError:
+            ui.debug('ignoring unknown advisory part %r\n' % key)
+            # todo: consume the part (once we use streamed parts)
+            continue
+        handler(repo, part)
+
 class bundle20(object):
     """represent an outgoing bundle2 container
 
     Use the `addparam` method to add stream level parameter. and `addpart` to
     populate it. Then call `getchunks` to retrieve all the binary chunks of
diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t
--- a/tests/test-bundle2.t
+++ b/tests/test-bundle2.t
@@ -18,10 +18,18 @@  Create an extension to test bundle2 API
   > ELEPHANTSSONG = """Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
   > Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
   > Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko."""
   > assert len(ELEPHANTSSONG) == 178 # future test say 178 bytes, trust it.
   > 
+  > def songhandler(repo, part):
+  >     """handle a "test:song" bundle2 part, printing the lyrics on stdin"""
+  >     repo.ui.write('The choir start singing:\n')
+  >     for line in part.data.split('\n'):
+  >         repo.ui.write('    %s\n' % line)
+  > 
+  > bundle2.parthandlermapping['test:song'] = songhandler
+  > 
   > @command('bundle2',
   >          [('', 'param', [], 'stream level parameter'),
   >           ('', 'parts', False, 'include some arbitrary parts to the bundle'),],
   >          '[OUTPUTFILE]')
   > def cmdbundle2(ui, repo, path=None, **opts):
@@ -54,10 +62,15 @@  Create an extension to test bundle2 API
   >         file = open(path, 'w')
   > 
   >     for chunk in bundler.getchunks():
   >         file.write(chunk)
   > 
+  > @command('unbundle2', [], '')
+  > def cmdunbundle2(ui, repo):
+  >     """process a bundle2 stream from stdin on the current repo"""
+  >     bundle2.processbundle(repo, sys.stdin)
+  > 
   > @command('statbundle2', [], '')
   > def cmdstatbundle2(ui, repo):
   >     """print statistic on the bundle2 container read from stdin"""
   >     unbundler = bundle2.unbundle20(ui, sys.stdin)
   >     try:
@@ -325,5 +338,43 @@  Test part
       payload: 178 bytes
     :test:math:
       mandatory: 2
       advisory: 1
       payload: 2 bytes
+
+Test actual unbundling
+========================
+
+Process the bundle
+
+  $ hg unbundle2 --debug < ../parts.hg2
+  start processing of HG20 stream
+  reading bundle2 stream parameters
+  start extraction of bundle2 parts
+  part header size: 13
+  part type: "test:empty"
+  part parameters: 0
+  payload chunk size: 0
+  ignoring unknown advisory part 'test:empty'
+  part header size: 13
+  part type: "test:empty"
+  part parameters: 0
+  payload chunk size: 0
+  ignoring unknown advisory part 'test:empty'
+  part header size: 12
+  part type: "test:song"
+  part parameters: 0
+  payload chunk size: 178
+  payload chunk size: 0
+  found an handler for part 'test:song'
+  The choir start singing:
+      Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
+      Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+      Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
+  part header size: 39
+  part type: "test:math"
+  part parameters: 3
+  payload chunk size: 2
+  payload chunk size: 0
+  ignoring unknown advisory part 'test:math'
+  part header size: 0
+  end of bundle2 stream