changeset 20949:571f2903ff1e

bundle2: record processing results in the bundleoperation object Part handlers can now add records to the `bundleoperation` object. This can be used to help other parts or to let the caller of the unbundling process react to the results.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Wed, 02 Apr 2014 22:37:50 -0700
parents 329cd74b52bd
children c7ceae0faf69
files mercurial/bundle2.py tests/test-bundle2.t
diffstat 2 files changed, 48 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/bundle2.py	Wed Apr 02 22:24:44 2014 -0700
+++ b/mercurial/bundle2.py	Wed Apr 02 22:37:50 2014 -0700
@@ -183,6 +183,44 @@
         return func
     return _decorator
 
+class unbundlerecords(object):
+    """keep record of what happens during and unbundle
+
+    New records 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)` tuples
+    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']."""
+        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 represents a single bundling process
 
@@ -202,6 +240,7 @@
     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
@@ -242,6 +281,7 @@
         for part in iterparts:
             pass # consume the bundle content
         raise
+    return op
 
 class bundle20(object):
     """represent an outgoing bundle2 container
--- a/tests/test-bundle2.t	Wed Apr 02 22:24:44 2014 -0700
+++ b/tests/test-bundle2.t	Wed Apr 02 22:37:50 2014 -0700
@@ -24,8 +24,11 @@
   > def songhandler(op, part):
   >     """handle a "test:song" bundle2 part, printing the lyrics on stdin"""
   >     op.ui.write('The choir starts 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'),
@@ -75,13 +78,16 @@
   >         lock = repo.lock()
   >         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:
   >         lock.release()
   >         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):
@@ -393,6 +399,7 @@
   part header size: 0
   end of bundle2 stream
   0 unread bytes
+  3 total verses sung
 
 
   $ hg bundle2 --parts --unknown ../unknown.hg2