From patchwork Thu Apr 3 22:57:50 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [3, of, 4] bundle2: records processing results in the bundleoperation object From: Pierre-Yves David X-Patchwork-Id: 4213 Message-Id: <44096fd181296f228c1f.1396565870@marginatus.alto.octopoid.net> To: mercurial-devel@selenic.com Cc: pierre-yves.david@ens-lyon.org Date: Thu, 03 Apr 2014 15:57:50 -0700 # HG changeset patch # User Pierre-Yves David # Date 1396503470 25200 # Wed Apr 02 22:37:50 2014 -0700 # Node ID 44096fd181296f228c1f2d869b53034b55d2bac9 # Parent d47181150c1edace8a5e5da51e99dffe17d52407 bundle2: records processing results in the bundleoperation object Part handlers can now add records to the `bundleoperation` object This can be used to help other part or to let the caller of the unbundling process to react to the results. diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py --- a/mercurial/bundle2.py +++ b/mercurial/bundle2.py @@ -181,10 +181,50 @@ def parthandler(parttype): assert lparttype not in parthandlermapping parthandlermapping[lparttype] = func return func return _decorator +class unbundlerecords(object): + """keep record of what happen during and unbundle + + New record are added using `records.add('cat', obj)`. Where 'cat' is a + category of record and obj is an arbitraty object. + + `records['cat']` will return all entries of this category 'cat'. + + Iterating on the object itself will yield `('category', obj)` tuple for all + entries. + + All iterations happens in chronological order. + """ + + def __init__(self): + self._categories = {} + self._sequences = [] + + def add(self, category, entry): + """add a new record of a given category. + + The entry can then be retrieved in the list returned by + self['category'].""" + category = str(category) + self._categories.setdefault(category, []).append(entry) + self._sequences.append((category, entry)) + + def __getitem__(self, cat): + return tuple(self._categories.get(cat, ())) + + def __iter__(self): + return iter(self._sequences) + + def __len__(self): + return len(self._sequences) + + def __nonzero__(self): + return bool(self._sequences) + + class bundleoperation(object): """an object that represent a single bundle processing It purpose is to carry unbundle related objects and states. @@ -200,10 +240,11 @@ class bundleoperation(object): """ def __init__(self, repo): self.repo = repo self.ui = repo.ui + self.records = unbundlerecords() def processbundle(repo, unbundler): """This function process a bundle, apply effect to/from a repo @@ -241,10 +282,11 @@ def processbundle(repo, unbundler): handler(op, part) except Exception: for part in iterparts: pass # consume the bundle content raise + return op class bundle20(object): """represent an outgoing bundle2 container Use the `addparam` method to add stream level parameter. and `addpart` to diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t --- a/tests/test-bundle2.t +++ b/tests/test-bundle2.t @@ -22,12 +22,15 @@ Create an extension to test bundle2 API > > @bundle2.parthandler('test:song') > def songhandler(op, part): > """handle a "test:song" bundle2 part, printing the lyrics on stdin""" > op.ui.write('The choir start singing:\n') + > verses = 0 > for line in part.data.split('\n'): > op.ui.write(' %s\n' % line) + > verses += 1 + > op.records.add('song', {'verses': verses}) > > @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'),], @@ -72,16 +75,19 @@ Create an extension to test bundle2 API > def cmdunbundle2(ui, repo): > """process a bundle2 stream from stdin on the current repo""" > try: > try: > unbundler = bundle2.unbundle20(ui, sys.stdin) - > bundle2.processbundle(repo, unbundler) + > op = bundle2.processbundle(repo, unbundler) > except KeyError, exc: > raise util.Abort('missing support for %s' % exc) > finally: > remains = sys.stdin.read() > ui.write('%i unread bytes\n' % len(remains)) + > if op.records['song']: + > totalverses = sum(r['verses'] for r in op.records['song']) + > ui.write('%i total verses sung\n' % totalverses) > > @command('statbundle2', [], '') > def cmdstatbundle2(ui, repo): > """print statistic on the bundle2 container read from stdin""" > unbundler = bundle2.unbundle20(ui, sys.stdin) @@ -389,10 +395,11 @@ Process the bundle payload chunk size: 0 ignoring unknown advisory part 'test:math' part header size: 0 end of bundle2 stream 0 unread bytes + 3 total verses sung $ hg bundle2 --parts --unknown ../unknown.hg2 $ hg unbundle2 < ../unknown.hg2