[PATCH 5 of 6] bundle2: add some distinction between mandatory and advisory part
pierre-yves.david at ens-lyon.org
pierre-yves.david at ens-lyon.org
Tue Apr 1 14:35:26 CDT 2014
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at fb.com>
# Date 1395691322 25200
# Mon Mar 24 13:02:02 2014 -0700
# Node ID 8f0da5aa2129a78b4e7891e29ec583d9296ac10c
# Parent 8b74b0f5ff191eb9796706e089b6c14a30c05d40
bundle2: add some distinction between mandatory and advisory part
Mandatory part cannot be ignored when unknown. We raise a simple KeyError
exception when this happen.
This is very early version of this logic, see inline comment for future
improvement lead.
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -117,10 +117,23 @@ Binary format is as follow
`chunksize` is a 32 bits integer, `chunkdata` are plain bytes (as much as
`chunksize` says)` The payload part is concluded by a zero size chunk.
The current implementation always produces either zero or one chunk.
This is an implementation limitation that will ultimatly be lifted.
+
+Bundle processing
+============================
+
+Each part is processed in order using a "part handler". Handler are registered
+for a certain part type.
+
+The matching of a part to its handler is case insensitive. The case of the
+part type is used to know if a part is mandatory or advisory. If the Part type
+contains any uppercase char it is considered mandatory. When no handler is
+known for a Mandatory part, the process is aborted and an exception is raised.
+If the part is advisory and no handler is known, the part is ignored.
+
"""
import util
import struct
import urllib
@@ -159,12 +172,13 @@ def parthandler(parttype):
def myparttypehandler(...):
'''process a part of type "my part".'''
...
"""
def _decorator(func):
- assert parttype not in parthandlermapping
- parthandlermapping[parttype] = func
+ lparttype = parttype.lower() # enforce lower case matching.
+ assert lparttype not in parthandlermapping
+ parthandlermapping[lparttype] = func
return func
return _decorator
def processbundle(repo, stream):
"""This function process a bundle, apply effect to/from a repo
@@ -177,12 +191,11 @@ def processbundle(repo, stream):
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).
+ Unknown Mandatory part will abort the process.
"""
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
@@ -198,10 +211,15 @@ def processbundle(repo, stream):
key = parttype.lower()
try:
handler = parthandlermapping[key]
ui.debug('found an handler for part %r\n' % parttype)
except KeyError:
+ if key != parttype: # mandatory parts
+ # todo:
+ # - use a more precise exception
+ # - consume the bundle2 stream anyway.
+ raise
ui.debug('ignoring unknown advisory part %r\n' % key)
# todo: consume the part (once we use streamed parts)
continue
handler(repo, part)
diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t
--- a/tests/test-bundle2.t
+++ b/tests/test-bundle2.t
@@ -27,10 +27,11 @@ Create an extension to test bundle2 API
> for line in part.data.split('\n'):
> repo.ui.write(' %s\n' % line)
>
> @command('bundle2',
> [('', 'param', [], 'stream level parameter'),
+ > ('', 'unknown', False, 'include an unknown mandatory part in the bundle'),
> ('', '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)
@@ -52,10 +53,14 @@ Create an extension to test bundle2 API
> part = bundle2.part('test:math',
> [('pi', '3.14'), ('e', '2.72')],
> [('cooking', 'raw')],
> '42')
> bundler.addpart(part)
+ > if opts['unknown']:
+ > part = bundle2.part('test:UNKNOWN',
+ > data='some random content')
+ > bundler.addpart(part)
>
> if path is None:
> file = sys.stdout
> else:
> file = open(path, 'w')
@@ -64,11 +69,14 @@ Create an extension to test bundle2 API
> file.write(chunk)
>
> @command('unbundle2', [], '')
> def cmdunbundle2(ui, repo):
> """process a bundle2 stream from stdin on the current repo"""
- > bundle2.processbundle(repo, sys.stdin)
+ > try:
+ > bundle2.processbundle(repo, sys.stdin)
+ > except KeyError, exc:
+ > raise util.Abort('missing support for %s' % exc)
>
> @command('statbundle2', [], '')
> def cmdstatbundle2(ui, repo):
> """print statistic on the bundle2 container read from stdin"""
> unbundler = bundle2.unbundle20(ui, sys.stdin)
@@ -375,5 +383,16 @@ Process the bundle
payload chunk size: 2
payload chunk size: 0
ignoring unknown advisory part 'test:math'
part header size: 0
end of bundle2 stream
+
+
+ $ hg bundle2 --parts --unknown ../unknown.hg2
+
+ $ hg unbundle2 < ../unknown.hg2
+ 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.
+ abort: missing support for 'test:unknown'
+ [255]
More information about the Mercurial-devel
mailing list