Merge lp:~jelmer/bzr/workingtree-format-registry into lp:bzr

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: 5682
Proposed branch: lp:~jelmer/bzr/workingtree-format-registry
Merge into: lp:bzr
Diff against target: 404 lines (+156/-46)
8 files modified
bzrlib/bzrdir.py (+4/-2)
bzrlib/tests/per_tree/__init__.py (+3/-3)
bzrlib/tests/per_workingtree/__init__.py (+1/-1)
bzrlib/tests/test_inv.py (+2/-2)
bzrlib/tests/test_selftest.py (+1/-1)
bzrlib/tests/test_workingtree.py (+48/-14)
bzrlib/workingtree.py (+93/-23)
doc/en/release-notes/bzr-2.4.txt (+4/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/workingtree-format-registry
Reviewer Review Type Date Requested Status
Vincent Ladeuil Needs Fixing
Review via email: mp+50453@code.launchpad.net

Commit message

Add WorkingTreeFormatRegistry.

Description of the change

Add a WorkingTreeFormatRegistry, similar to RepositoryFormatRegistry and the BranchFormatRegistry I added in lp:~jelmer/bzr/branch-format-registry.

Among other things this makes it possible to lazily register working tree formats that can not be used in bzr meta directories. This is useful so non-metadir bzr formats and foreign formats can be tested.

I next plan to work on factoring out some of the common elements of these three format registries into a single base class.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

19 # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
20 # directly from workingtree_4 triggers a circular import.
21 - tree_format='bzrlib.workingtree.WorkingTreeFormat4',
22 + tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',

The comment is now wrong because the import is lazy right ?

Please fix it and land.

review: Needs Fixing
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/bzrdir.py'
2--- bzrlib/bzrdir.py 2011-02-19 17:37:45 +0000
3+++ bzrlib/bzrdir.py 2011-02-23 13:57:14 +0000
4@@ -2119,8 +2119,10 @@
5
6 def __get_workingtree_format(self):
7 if self._workingtree_format is None:
8- from bzrlib.workingtree import WorkingTreeFormat
9- self._workingtree_format = WorkingTreeFormat.get_default_format()
10+ from bzrlib.workingtree import (
11+ format_registry as wt_format_registry,
12+ )
13+ self._workingtree_format = wt_format_registry.get_default()
14 return self._workingtree_format
15
16 def __set_workingtree_format(self, wt_format):
17
18=== modified file 'bzrlib/tests/per_tree/__init__.py'
19--- bzrlib/tests/per_tree/__init__.py 2011-02-04 18:12:44 +0000
20+++ bzrlib/tests/per_tree/__init__.py 2011-02-23 13:57:14 +0000
21@@ -38,7 +38,7 @@
22 from bzrlib.revisiontree import RevisionTree
23 from bzrlib.transform import TransformPreview
24 from bzrlib.workingtree import (
25- WorkingTreeFormat,
26+ format_registry,
27 )
28 from bzrlib.workingtree_4 import (
29 DirStateRevisionTree,
30@@ -332,7 +332,7 @@
31 # for working tree format tests, preserve the tree
32 scenario[1]["_workingtree_to_test_tree"] = return_parameter
33 # add RevisionTree scenario
34- workingtree_format = WorkingTreeFormat._default_format
35+ workingtree_format = format_registry.get_default()
36 scenarios.append((RevisionTree.__name__,
37 create_tree_scenario(transport_server, transport_readonly_server,
38 workingtree_format, revision_tree_from_workingtree,)))
39@@ -397,6 +397,6 @@
40 # None here will cause a readonly decorator to be created
41 # by the TestCaseWithTransport.get_readonly_transport method.
42 None,
43- WorkingTreeFormat.get_formats())
44+ format_registry._get_all())
45 # add the tests for the sub modules
46 return tests.multiply_tests(submod_tests, scenarios, standard_tests)
47
48=== modified file 'bzrlib/tests/per_workingtree/__init__.py'
49--- bzrlib/tests/per_workingtree/__init__.py 2011-02-04 18:12:44 +0000
50+++ bzrlib/tests/per_workingtree/__init__.py 2011-02-23 13:57:14 +0000
51@@ -120,7 +120,7 @@
52 # None here will cause a readonly decorator to be created
53 # by the TestCaseWithTransport.get_readonly_transport method.
54 None,
55- workingtree.WorkingTreeFormat.get_formats()
56+ workingtree.format_registry._get_all()
57 )
58
59 # add the tests for the sub modules
60
61=== modified file 'bzrlib/tests/test_inv.py'
62--- bzrlib/tests/test_inv.py 2011-02-04 18:12:44 +0000
63+++ bzrlib/tests/test_inv.py 2011-02-23 13:57:14 +0000
64@@ -24,6 +24,7 @@
65 repository,
66 revision,
67 tests,
68+ workingtree,
69 )
70 from bzrlib.inventory import (
71 CHKInventory,
72@@ -39,7 +40,6 @@
73 TestCaseWithTransport,
74 )
75 from bzrlib.tests.scenarios import load_tests_apply_scenarios
76-from bzrlib.workingtree import WorkingTreeFormat
77
78
79 load_tests = load_tests_apply_scenarios
80@@ -59,7 +59,7 @@
81 scenarios.append((str(format.__name__), {
82 'apply_delta':apply_inventory_Repository_add_inventory_by_delta,
83 'format':format}))
84- for format in WorkingTreeFormat.get_formats():
85+ for format in workingtree.format_registry._get_all():
86 scenarios.append(
87 (str(format.__class__.__name__) + ".update_basis_by_delta", {
88 'apply_delta':apply_inventory_WT_basis,
89
90=== modified file 'bzrlib/tests/test_selftest.py'
91--- bzrlib/tests/test_selftest.py 2011-02-18 21:52:42 +0000
92+++ bzrlib/tests/test_selftest.py 2011-02-23 13:57:14 +0000
93@@ -379,7 +379,7 @@
94 workingtree.WorkingTreeFormat3(),]
95 scenarios = make_scenarios(server1, server2, formats)
96 self.assertEqual(7, len(scenarios))
97- default_wt_format = workingtree.WorkingTreeFormat4._default_format
98+ default_wt_format = workingtree.format_registry.get_default()
99 wt4_format = workingtree.WorkingTreeFormat4()
100 wt5_format = workingtree.WorkingTreeFormat5()
101 expected_scenarios = [
102
103=== modified file 'bzrlib/tests/test_workingtree.py'
104--- bzrlib/tests/test_workingtree.py 2011-02-04 18:18:19 +0000
105+++ bzrlib/tests/test_workingtree.py 2011-02-23 13:57:14 +0000
106@@ -21,6 +21,7 @@
107 bzrdir,
108 conflicts,
109 errors,
110+ symbol_versioning,
111 transport,
112 workingtree,
113 )
114@@ -62,10 +63,10 @@
115 class TestDefaultFormat(TestCaseWithTransport):
116
117 def test_get_set_default_format(self):
118- old_format = workingtree.WorkingTreeFormat.get_default_format()
119+ old_format = workingtree.format_registry.get_default()
120 # default is 3
121 self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
122- workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
123+ workingtree.format_registry.set_default(SampleTreeFormat())
124 try:
125 # the default branch format is used by the meta dir format
126 # which is not the default bzrdir format at this point
127@@ -75,8 +76,8 @@
128 result = dir.create_workingtree()
129 self.assertEqual(result, 'A tree')
130 finally:
131- workingtree.WorkingTreeFormat.set_default_format(old_format)
132- self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
133+ workingtree.format_registry.set_default(old_format)
134+ self.assertEqual(old_format, workingtree.format_registry.get_default())
135
136 def test_open(self):
137 tree = self.make_branch_and_tree('.')
138@@ -184,22 +185,55 @@
139 # make a branch
140 format.initialize(dir)
141 # register a format for it.
142- workingtree.WorkingTreeFormat.register_format(format)
143- self.assertTrue(format in workingtree.WorkingTreeFormat.get_formats())
144+ self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
145+ workingtree.WorkingTreeFormat.register_format, format)
146+ self.assertTrue(format in
147+ self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
148+ workingtree.WorkingTreeFormat.get_formats))
149 # which branch.Open will refuse (not supported)
150 self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
151 # but open_downlevel will work
152 self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
153 # unregister the format
154- workingtree.WorkingTreeFormat.unregister_format(format)
155- self.assertFalse(format in workingtree.WorkingTreeFormat.get_formats())
156-
157- def test_register_unregister_extra_format(self):
158+ self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
159+ workingtree.WorkingTreeFormat.unregister_format, format)
160+ self.assertFalse(format in
161+ self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
162+ workingtree.WorkingTreeFormat.get_formats))
163+
164+
165+class TestWorkingTreeFormatRegistry(TestCase):
166+
167+ def setUp(self):
168+ super(TestWorkingTreeFormatRegistry, self).setUp()
169+ self.registry = workingtree.WorkingTreeFormatRegistry()
170+
171+ def test_register_unregister_format(self):
172+ format = SampleTreeFormat()
173+ self.registry.register(format)
174+ self.assertEquals(format, self.registry.get("Sample tree format."))
175+ self.registry.remove(format)
176+ self.assertRaises(KeyError, self.registry.get, "Sample tree format.")
177+
178+ def test_get_all(self):
179+ format = SampleTreeFormat()
180+ self.assertEquals([], self.registry._get_all())
181+ self.registry.register(format)
182+ self.assertEquals([format], self.registry._get_all())
183+
184+ def test_register_extra(self):
185 format = SampleExtraTreeFormat()
186- workingtree.WorkingTreeFormat.register_extra_format(format)
187- self.assertTrue(format in workingtree.WorkingTreeFormat.get_formats())
188- workingtree.WorkingTreeFormat.unregister_extra_format(format)
189- self.assertFalse(format in workingtree.WorkingTreeFormat.get_formats())
190+ self.assertEquals([], self.registry._get_all())
191+ self.registry.register_extra(format)
192+ self.assertEquals([format], self.registry._get_all())
193+
194+ def test_register_extra_lazy(self):
195+ self.assertEquals([], self.registry._get_all())
196+ self.registry.register_extra_lazy("bzrlib.tests.test_workingtree",
197+ "SampleExtraTreeFormat")
198+ formats = self.registry._get_all()
199+ self.assertEquals(1, len(formats))
200+ self.assertIsInstance(formats[0], SampleExtraTreeFormat)
201
202
203 class TestWorkingTreeFormat3(TestCaseWithTransport):
204
205=== modified file 'bzrlib/workingtree.py'
206--- bzrlib/workingtree.py 2011-02-11 17:58:56 +0000
207+++ bzrlib/workingtree.py 2011-02-23 13:57:14 +0000
208@@ -58,6 +58,7 @@
209 ignores,
210 inventory,
211 merge,
212+ registry,
213 revision as _mod_revision,
214 revisiontree,
215 trace,
216@@ -2858,6 +2859,67 @@
217 return path[:-len(suffix)]
218
219
220+class WorkingTreeFormatRegistry(registry.FormatRegistry):
221+ """Registry for working tree formats."""
222+
223+ def __init__(self, other_registry=None):
224+ super(WorkingTreeFormatRegistry, self).__init__(other_registry)
225+ self._extra_formats = []
226+ self._default_format = None
227+
228+ def register(self, format):
229+ """Register a new repository format."""
230+ super(WorkingTreeFormatRegistry, self).register(
231+ format.get_format_string(), format)
232+
233+ def remove(self, format):
234+ """Remove a registered repository format."""
235+ super(WorkingTreeFormatRegistry, self).remove(format.get_format_string())
236+
237+ def register_extra(self, format):
238+ """Register a repository format that can not be used in a metadir.
239+
240+ This is mainly useful to allow custom repository formats, such as older
241+ Bazaar formats and foreign formats, to be tested.
242+ """
243+ self._extra_formats.append(registry._ObjectGetter(format))
244+
245+ def remove_extra(self, format):
246+ """Remove an extra repository format.
247+ """
248+ self._extra_formats.remove(registry._ObjectGetter(format))
249+
250+ def register_extra_lazy(self, module_name, member_name):
251+ """Register a repository format lazily.
252+ """
253+ self._extra_formats.append(
254+ registry._LazyObjectGetter(module_name, member_name))
255+
256+ def get_default(self):
257+ """Return the current default format."""
258+ return self._default_format
259+
260+ def set_default(self, format):
261+ self._default_format = format
262+
263+ def _get_extra(self):
264+ result = []
265+ for getter in self._extra_formats:
266+ f = getter.get_obj()
267+ if callable(f):
268+ f = f()
269+ result.append(f)
270+ return result
271+
272+ def _get_all(self):
273+ """Return all repository formats, even those not usable in metadirs.
274+ """
275+ return [self.get(k) for k in self.keys()] + self._get_extra()
276+
277+
278+format_registry = WorkingTreeFormatRegistry()
279+
280+
281 class WorkingTreeFormat(object):
282 """An encapsulation of the initialization and open routines for a format.
283
284@@ -2876,15 +2938,6 @@
285 object will be created every time regardless.
286 """
287
288- _default_format = None
289- """The default format used for new trees."""
290-
291- _formats = {}
292- """The known formats."""
293-
294- _extra_formats = []
295- """Extra formats that can not be used in a metadir."""
296-
297 requires_rich_root = False
298
299 upgrade_recommended = False
300@@ -2902,7 +2955,7 @@
301 try:
302 transport = a_bzrdir.get_workingtree_transport(None)
303 format_string = transport.get_bytes("format")
304- return klass._formats[format_string]
305+ return format_registry.get(format_string)
306 except errors.NoSuchFile:
307 raise errors.NoWorkingTree(base=transport.base)
308 except KeyError:
309@@ -2916,9 +2969,11 @@
310 return not (self == other)
311
312 @classmethod
313+ @symbol_versioning.deprecated_method(
314+ symbol_versioning.deprecated_in((2, 4, 0)))
315 def get_default_format(klass):
316 """Return the current default format."""
317- return klass._default_format
318+ return format_registry.get_default()
319
320 def get_format_string(self):
321 """Return the ASCII format string that identifies this format."""
322@@ -2946,28 +3001,40 @@
323 return False
324
325 @classmethod
326+ @symbol_versioning.deprecated_method(
327+ symbol_versioning.deprecated_in((2, 4, 0)))
328 def register_format(klass, format):
329- klass._formats[format.get_format_string()] = format
330+ format_registry.register(format)
331
332 @classmethod
333+ @symbol_versioning.deprecated_method(
334+ symbol_versioning.deprecated_in((2, 4, 0)))
335 def register_extra_format(klass, format):
336- klass._extra_formats.append(format)
337+ format_registry.register_extra(format)
338
339 @classmethod
340+ @symbol_versioning.deprecated_method(
341+ symbol_versioning.deprecated_in((2, 4, 0)))
342 def unregister_extra_format(klass, format):
343- klass._extra_formats.remove(format)
344+ format_registry.unregister_extra(format)
345
346 @classmethod
347+ @symbol_versioning.deprecated_method(
348+ symbol_versioning.deprecated_in((2, 4, 0)))
349 def get_formats(klass):
350- return klass._formats.values() + klass._extra_formats
351+ return format_registry._get_all()
352
353 @classmethod
354+ @symbol_versioning.deprecated_method(
355+ symbol_versioning.deprecated_in((2, 4, 0)))
356 def set_default_format(klass, format):
357- klass._default_format = format
358+ format_registry.set_default(format)
359
360 @classmethod
361+ @symbol_versioning.deprecated_method(
362+ symbol_versioning.deprecated_in((2, 4, 0)))
363 def unregister_format(klass, format):
364- del klass._formats[format.get_format_string()]
365+ format_registry.remove(format)
366
367
368 class WorkingTreeFormat2(WorkingTreeFormat):
369@@ -3194,12 +3261,15 @@
370
371
372 __default_format = WorkingTreeFormat6()
373-WorkingTreeFormat.register_format(__default_format)
374-WorkingTreeFormat.register_format(WorkingTreeFormat5())
375-WorkingTreeFormat.register_format(WorkingTreeFormat4())
376-WorkingTreeFormat.register_format(WorkingTreeFormat3())
377-WorkingTreeFormat.set_default_format(__default_format)
378+format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
379+ "bzrlib.workingtree_4", "WorkingTreeFormat4")
380+format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
381+ "bzrlib.workingtree_4", "WorkingTreeFormat5")
382+format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
383+ "bzrlib.workingtree_4", "WorkingTreeFormat6")
384+format_registry.register(WorkingTreeFormat3())
385+format_registry.set_default(__default_format)
386 # Register extra formats which have no format string are not discoverable
387 # and not independently creatable. They are implicitly created as part of
388 # e.g. older Bazaar formats or foreign formats.
389-WorkingTreeFormat.register_extra_format(WorkingTreeFormat2())
390+format_registry.register_extra(WorkingTreeFormat2())
391
392=== modified file 'doc/en/release-notes/bzr-2.4.txt'
393--- doc/en/release-notes/bzr-2.4.txt 2011-02-22 11:59:59 +0000
394+++ doc/en/release-notes/bzr-2.4.txt 2011-02-23 13:57:14 +0000
395@@ -140,6 +140,10 @@
396 ``InterRepository.search_missing_revision_ids`` is deprecated. It is
397 replaced by the ``revision_ids`` parameter. (Andrew Bennetts)
398
399+* Working tree formats should now be registered on the format registry
400+ (``bzrlib.working_tree.format_registry``) rather than using the class
401+ methods on ``WorkingTreeFormat``. (Jelmer Vernooij, #714730)
402+
403 Internals
404 *********
405