Rev 4038: Add helper class versionedfile.VersionedFilesDecorator for use with RemoteRepository in future. in http://people.ubuntu.com/~robertc/baz2.0/versioned_files.decorator

Robert Collins robertc at robertcollins.net
Tue Feb 24 10:57:53 GMT 2009


At http://people.ubuntu.com/~robertc/baz2.0/versioned_files.decorator

------------------------------------------------------------
revno: 4038
revision-id: robertc at robertcollins.net-20090224105745-84xd70xemb7h3jnx
parent: pqm at pqm.ubuntu.com-20090224073648-8cdhj9m2zsab8hx8
committer: Robert Collins <robertc at robertcollins.net>
branch nick: versioned_files.decorator
timestamp: Tue 2009-02-24 21:57:45 +1100
message:
  Add helper class versionedfile.VersionedFilesDecorator for use with RemoteRepository in future.
=== modified file 'NEWS'
--- a/NEWS	2009-02-24 07:36:48 +0000
+++ b/NEWS	2009-02-24 10:57:45 +0000
@@ -95,6 +95,10 @@
     * Creating a repository on a bzr+ssh:// server will now make a single
       call rather than many VFS calls. (Robert Collins)
 
+    * New helper class ``versionedfile.VersionedFilesDecorator`` provides
+      a generic way to decorate a ``VersionedFiles`` instance.
+      (Robert Collins)
+
     * New hook Commands['extend_command'] to allow plugins to access a
       command object before the command is run (or help generated from
       it), without overriding the command. (Robert Collins)

=== modified file 'bzrlib/tests/test_versionedfile.py'
--- a/bzrlib/tests/test_versionedfile.py	2009-02-23 15:42:47 +0000
+++ b/bzrlib/tests/test_versionedfile.py	2009-02-24 10:57:45 +0000
@@ -65,7 +65,10 @@
     ConstantMapper,
     HashEscapedPrefixMapper,
     PrefixMapper,
+    VersionedFilesDecorator,
     VirtualVersionedFiles,
+    make_decorator_cleanup,
+    make_decorator_factory,
     make_versioned_files_factory,
     )
 from bzrlib.weave import WeaveFile
@@ -149,6 +152,13 @@
             'key_length':2,
             'support_partial_insertion': True,
             }),
+        ('decorated', {
+            'cleanup':make_decorator_cleanup(cleanup_pack_knit),
+            'factory':make_decorator_factory(make_pack_factory(True, True, 2)),
+            'graph':True,
+            'key_length':2,
+            'support_partial_insertion': True,
+            })
         ]
     for test in iter_suite_tests(to_adapt):
         result.addTests(len_one_adapter.adapt(test))
@@ -2511,3 +2521,16 @@
         # And the request recorded
         self.assertEqual([('get_record_stream', request_keys, 'unordered',
                            False)], vf.calls)
+
+
+class TestVersionedFilesDecorator(TestCaseWithMemoryTransport):
+    """Specific behaviour tests for VersionedFilesDecorator."""
+
+    def test_factory_works(self):
+        """The test helper make_decorator_factory returns a working object."""
+        transport = self.get_transport('.')
+        factory = make_decorator_factory(make_pack_factory(False, False, 1))
+        files = factory(transport)
+        self.assertIsInstance(files, VersionedFilesDecorator)
+        cleanup = make_decorator_cleanup(cleanup_pack_knit)
+        cleanup(files)

=== modified file 'bzrlib/versionedfile.py'
--- a/bzrlib/versionedfile.py	2009-02-23 15:29:35 +0000
+++ b/bzrlib/versionedfile.py	2009-02-24 10:57:45 +0000
@@ -552,14 +552,85 @@
         return PlanWeaveMerge(plan, a_marker, b_marker).merge_lines()[0]
 
 
-class RecordingVersionedFilesDecorator(object):
+class VersionedFilesDecorator(object):
+    """A VersionedFiles that decorates a backing versioned files."""
+
+    def __init__(self, hook_call):
+        """Create a VersionedFilesDecorator.
+
+        :param hook_call: A callback invoked on every method call to the
+            decorator. This call should ensure that the _backing_vf attribute
+            is correctly populated and may do any other housekeeping needed.
+            After the call is made, the invoked method is dispatched through
+            the _backing_vf and the result returned to the caller.
+            hook_call should take (self, method_name, *args) and return None.
+        """
+        self._hook_call = hook_call
+        self._backing_vf = None
+
+    def add_lines(self, key, parents, lines, parent_texts=None,
+        left_matching_blocks=None, nostore_sha=None, random_id=False,
+        check_content=True):
+        self._hook_call(self, "add_lines", key, parents, lines, parent_texts,
+            left_matching_blocks, nostore_sha, random_id, check_content)
+        return self._backing_vf.add_lines(key, parents, lines, parent_texts,
+            left_matching_blocks, nostore_sha, random_id, check_content)
+
+    def add_mpdiffs(self, records):
+        self._hook_call(self, "add_mpdiffs", records)
+        return self._backing_vf.add_mpdiffs(records)
+
+    def annotate(self, key):
+        self._hook_call(self, "annotate", key)
+        return self._backing_vf.annotate(key)
+
+    def check(self):
+        self._hook_call(self, "check")
+        return self._backing_vf.check()
+
+    def get_missing_compression_parent_keys(self):
+        self._hook_call(self, "get_missing_compression_parent_keys")
+        return self._backing_vf.get_missing_compression_parent_keys()
+
+    def get_parent_map(self, keys):
+        self._hook_call(self, "get_parent_map", keys)
+        return self._backing_vf.get_parent_map(keys)
+
+    def get_record_stream(self, keys, sort_order, include_delta_closure):
+        self._hook_call(self, "get_record_stream", keys, sort_order,
+            include_delta_closure)
+        return self._backing_vf.get_record_stream(keys, sort_order,
+            include_delta_closure)
+
+    def get_sha1s(self, keys):
+        self._hook_call(self, "get_sha1s", keys)
+        return self._backing_vf.get_sha1s(keys)
+
+    def insert_record_stream(self, stream):
+        self._hook_call(self, "insert_record_stream", stream)
+        return self._backing_vf.insert_record_stream(stream)
+
+    def iter_lines_added_or_present_in_keys(self, keys, pb=None):
+        self._hook_call(self, "iter_lines_added_or_present_in_keys", keys, pb)
+        return self._backing_vf.iter_lines_added_or_present_in_keys(keys, pb=pb)
+
+    def keys(self):
+        self._hook_call(self, "keys")
+        return self._backing_vf.keys()
+
+    def make_mpdiffs(self, keys):
+        self._hook_call(self, "make_mpdiffs", keys)
+        return self._backing_vf.make_mpdiffs(keys)
+
+
+class RecordingVersionedFilesDecorator(VersionedFilesDecorator):
     """A minimal versioned files that records calls made on it.
 
-    Only enough methods have been added to support tests using it to date.
-
     :ivar calls: A list of the calls made; can be reset at any time by
         assigning [] to it.
     """
+    # Note that some methods are overridden to ensure that iterable parameters
+    # are not consumed in _hook_call.
 
     def __init__(self, backing_vf):
         """Create a RecordingVersionedFilesDecorator decorating backing_vf.
@@ -569,16 +640,8 @@
         self._backing_vf = backing_vf
         self.calls = []
 
-    def add_lines(self, key, parents, lines, parent_texts=None,
-        left_matching_blocks=None, nostore_sha=None, random_id=False,
-        check_content=True):
-        self.calls.append(("add_lines", key, parents, lines, parent_texts,
-            left_matching_blocks, nostore_sha, random_id, check_content))
-        return self._backing_vf.add_lines(key, parents, lines, parent_texts,
-            left_matching_blocks, nostore_sha, random_id, check_content)
-
-    def check(self):
-        self._backing_vf.check()
+    def _hook_call(_self, self, method_name, *args):
+        self.calls.append((method_name,) + args)
 
     def get_parent_map(self, keys):
         self.calls.append(("get_parent_map", copy(keys)))
@@ -598,10 +661,6 @@
         self.calls.append(("iter_lines_added_or_present_in_keys", copy(keys)))
         return self._backing_vf.iter_lines_added_or_present_in_keys(keys, pb=pb)
 
-    def keys(self):
-        self.calls.append(("keys",))
-        return self._backing_vf.keys()
-
 
 class OrderingVersionedFilesDecorator(RecordingVersionedFilesDecorator):
     """A VF that records calls, and returns keys in specific order.
@@ -757,6 +816,34 @@
         return urllib.unquote(basename)
 
 
+def make_decorator_cleanup(versioned_files_cleanup):
+    """Create a VersionedFilesDecorator cleanup helper.
+
+    :param versioned_files_cleanup: The cleanup to call
+        to cleanup the backing vf for a VersionedFilesDecorator.
+    """
+    def cleanup(files):
+        if files._backing_vf is not None:
+            versioned_files_cleanup(files._backing_vf)
+    return cleanup
+
+
+def make_decorator_factory(versioned_files_factory):
+    """Create VersionedFilesDecorator factory.
+
+    The factory will return a callable which when called returns a
+    VersionedFilesDecorator. The decorator is configured to invoke the
+    original versioned_files_factory when a backing_vf is required.
+    """
+    def factory(transport):
+        def _ensure_backing_vf(self, method_name, *args):
+            """Ensure there is a backing vf set."""
+            if self._backing_vf is None:
+                self._backing_vf = versioned_files_factory(transport)
+        return VersionedFilesDecorator(_ensure_backing_vf)
+    return factory
+
+
 def make_versioned_files_factory(versioned_file_factory, mapper):
     """Create a ThunkedVersionedFiles factory.
 




More information about the bazaar-commits mailing list