At http://people.ubuntu.com/~robertc/baz2.0/versioned_files.decorator
------------------------------------------------------------ revno: 4038 revision-id: [email protected] parent: [email protected] committer: Robert Collins <[email protected]> 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. -- bazaar-commits mailing list [email protected] https://lists.ubuntu.com/mailman/listinfo/bazaar-commits
