Merge lp:~jelmer/bzr/2a-repo-supports-nested-trees into lp:bzr

Proposed by Jelmer Vernooij
Status: Rejected
Rejected by: Jelmer Vernooij
Proposed branch: lp:~jelmer/bzr/2a-repo-supports-nested-trees
Merge into: lp:bzr
Diff against target: 322 lines (+91/-20)
10 files modified
bzrlib/bzrdir.py (+3/-3)
bzrlib/commit.py (+0/-1)
bzrlib/repofmt/groupcompress_repo.py (+1/-1)
bzrlib/tests/per_pack_repository.py (+11/-2)
bzrlib/tests/per_tree/test_path_content_summary.py (+1/-1)
bzrlib/tests/test_merge.py (+2/-2)
bzrlib/tests/test_smart.py (+1/-1)
bzrlib/workingtree.py (+12/-1)
bzrlib/workingtree_4.py (+55/-8)
doc/en/release-notes/bzr-2.6.txt (+5/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/2a-repo-supports-nested-trees
Reviewer Review Type Date Requested Status
Vincent Ladeuil Needs Information
Review via email: mp+89919@code.launchpad.net

Description of the change

Enable support for nested trees in the '2a' repository format.

Support for storing 'tree-reference' inventory entries has always
been present in the '2a' repository format, just never been officially
supported by the format. The actual change (a new inventory entry kind
'tree-reference') is small and non-controversial.

Instead, this marks working tree formats 4-6 as not actually supporting
nested trees. Previously it would claim to support nested trees
depending on whether the associated repository supported nested trees.
In practice the current wt implementation doesn't properly support nested trees:

 * There is no cheap way to iterate over all nested trees, so every
   working tree that supports nested trees (even if there are none) pays
   the penalty of scanning the entire working tree for nested trees
   every time it is accessed.
 * There are various bugs around the current implementation that
   make it impossible to use it with nested trees. Just checking out
   a containing tree shows the kind of the nested trees of having changed
   from nested tree to regular directory

This adds an experimental 'Working Tree Format 7' which does claim to support
nested trees and is used by development-subtree. We can extend this to
do whatever is necessary to properly handle tree references and then
potentially merge it back into the other working tree formats with a
feature flag.

This change is sufficient for bzr-git to allow importing
git repositories with submodules somewhere in their history (launchpad bug
#402814
), although not yet sufficient to allow checking out trees with
submodules. We'd need working tree support for the latter, of course.

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

280 + return "Working tree format 6"

Really ?

Apart from that I don't quite see how your cover letter relates to this
proposal:

> The actual change (a new inventory entry kind 'tree-reference') is small
  and non-controversial.

There is nothing about that in your proposal, are you just referring to the
initial introduction of the tree-reference entry kind bak in the days ?

Ot is the actual change really:

51 + supports_tree_reference = True

and

59 - supports_tree_reference = True

If that's the case, I'm surprised there is no fallouts from activating tree
references support in 2a (line 51) !?! Not a single test failing ?

Also, what's the plan for RepositoryFormat2aSubtree ? Keeping it this way is
likely to get it forgotten, we at least need a bug to track its removal
describing some plan (since it's an experimental one, I think the plan can
be reduced to: delete it, users knew).

> Instead, this marks working tree formats 4-6 as not actually supporting
  nested trees.

So *this* part is uncontroversial and can be landed IMHO.

69 + if repo._format.supports_chks:
70 + matching_format_name = '2a'
71 + else:
72 + matching_format_name = 'pack-0.92-subtree'

81 + if repo.supports_rich_root():
82 + if repo._format.supports_chks:
83 + matching_format_name = '2a'
84 + else:
85 + matching_format_name = 'pack-0.92-subtree'
86 + else:
87 + matching_format_name = 'dirstate-subtree'

Urgh, these tests were already confusing, now they are almost undecipherable
:-(

Can't you abstract the logic here so we get a clearer view of what we are
tested ? Since these tests are about stacking, I'd really prefer them to be
easier to grasp, especially regarding the compatibility between the various
formats. There is also a hint that it's time to address:

        # TODO: Possibly this should be run per-repository-format and raise
        # TestNotApplicable on formats that don't support stacking. -- mbp
        # 20080729

100 + if not tree.supports_tree_reference():

Why is that a method for working trees (or is it wt formats) and an
attribute for repos ?

Highly confusing :-/

> This change is sufficient for bzr-git to allow importing (launchpad bug
  #402814), although not yet sufficient to allow checking out trees with
  submodules. We'd need working tree support for the latter, of course.

Meh, can you elaborate on that ? How does bzr-git uses this change ? By
using wt format 7 ? And how do you allow checking out such trees ? Or is
this proposal incomplete in this respect ?

We add a discussion in Budapest where you mentioned a list of limitations
(which I agreed with) to allow experimenting with subtrees. It would be nice
to formalize them so we a get some understanding on where this proposal
stands on the roadmap ;)

Failing that, I don't know how to review this proposal or if it needs to
be split into several parts that would be easier to understand.

review: Needs Information
Revision history for this message
Jelmer Vernooij (jelmer) wrote :
Download full text (4.2 KiB)

On Thu, Jan 26, 2012 at 09:27:24AM -0000, Vincent Ladeuil wrote:
> Review: Needs Information
> 280 + return "Working tree format 6"
>
> Really ?

I'm not sure what's so controversial about this?

> Apart from that I don't quite see how your cover letter relates to this
> proposal:
>
> > The actual change (a new inventory entry kind 'tree-reference') is small
> and non-controversial.
>
> There is nothing about that in your proposal, are you just referring to the
> initial introduction of the tree-reference entry kind bak in the days ?
Yes.

> Ot is the actual change really:
>
> 51 + supports_tree_reference = True
>
> and
>
> 59 - supports_tree_reference = True

> If that's the case, I'm surprised there is no fallouts from activating tree
> references support in 2a (line 51) !?! Not a single test failing ?
Basically, yeah.

> Also, what's the plan for RepositoryFormat2aSubtree ? Keeping it this way is
> likely to get it forgotten, we at least need a bug to track its removal
> describing some plan (since it's an experimental one, I think the plan can
> be reduced to: delete it, users knew).
I think we should support upgrading from 2a-subtree to 2a and then get
rid of 2a.

> > Instead, this marks working tree formats 4-6 as not actually supporting
> nested trees.
>
> So *this* part is uncontroversial and can be landed IMHO.
I disagree, doing just that without adding a new working tree format
means we no longer test the current subtree support. So I think as
part of disabling nested tree support in wt 4-6 we should also add wt
7. Or do you perhaps mean that you would like to see the working tree
changes split out?

>
> 69 + if repo._format.supports_chks:
> 70 + matching_format_name = '2a'
> 71 + else:
> 72 + matching_format_name = 'pack-0.92-subtree'
>
> 81 + if repo.supports_rich_root():
> 82 + if repo._format.supports_chks:
> 83 + matching_format_name = '2a'
> 84 + else:
> 85 + matching_format_name = 'pack-0.92-subtree'
> 86 + else:
> 87 + matching_format_name = 'dirstate-subtree'
>
> Urgh, these tests were already confusing, now they are almost undecipherable
> :-(
>
> Can't you abstract the logic here so we get a clearer view of what we are
> tested ? Since these tests are about stacking, I'd really prefer them to be
> easier to grasp, especially regarding the compatibility between the various
> formats. There is also a hint that it's time to address:
>
> # TODO: Possibly this should be run per-repository-format and raise
> # TestNotApplicable on formats that don't support stacking. -- mbp
> # 20080729
I'll have a look.

>
> 100 + if not tree.supports_tree_reference():
> Why is that a method for working trees (or is it wt formats) and an
> attribute for repos ?
>
> Highly confusing :-/
I agree. That's unfortunately something we've had for ages. I think poolie
preferred methods so we've slowly been transitioning to that.

WorkingTreeFormat seems to prefer methods, and RepositoryFormat seems
to prefer attributes.

> > This change is sufficient for bzr-git to allow importing (launchpad bug
> #402814), although not yet sufficient to allow checking out trees with
> submodules. We'd need working tree su...

Read more...

Revision history for this message
Vincent Ladeuil (vila) wrote :
Download full text (5.2 KiB)

I'm sure I started replying shortly after your reply and I sadly discover my
answer is nowhere to be seen :-(

> On Thu, Jan 26, 2012 at 09:27:24AM -0000, Vincent Ladeuil wrote:
> > Review: Needs Information
> > 280 + return "Working tree format 6"
> >
> > Really ?
>
> I'm not sure what's so controversial about this?

*6* instead of 7 ? This line is part of WorkingTreeFormat7

>
> > Apart from that I don't quite see how your cover letter relates to this
> > proposal:
> >
> > > The actual change (a new inventory entry kind 'tree-reference') is small
> > and non-controversial.
> >
> > There is nothing about that in your proposal, are you just referring to the
> > initial introduction of the tree-reference entry kind bak in the days ?
> Yes.

Ok, with that in mind, I better understand the cover letter ('change' there
wasn't related to the proposal itself which confused me).

>
> > Ot is the actual change really:
> >
> > 51 + supports_tree_reference = True
> >
> > and
> >
> > 59 - supports_tree_reference = True
>
> > If that's the case, I'm surprised there is no fallouts from activating tree
> > references support in 2a (line 51) !?! Not a single test failing ?
> Basically, yeah.

;_; so be it.

>
> > Also, what's the plan for RepositoryFormat2aSubtree ? Keeping it this way is
> > likely to get it forgotten, we at least need a bug to track its removal
> > describing some plan (since it's an experimental one, I think the plan can
> > be reduced to: delete it, users knew).
> I think we should support upgrading from 2a-subtree to 2a and then get
> rid of 2a.

 I assume you meant 'get rid of 2a-subtree'. Ok.

>
> > > Instead, this marks working tree formats 4-6 as not actually supporting
> > nested trees.
> >
> > So *this* part is uncontroversial and can be landed IMHO.
> I disagree, doing just that without adding a new working tree format
> means we no longer test the current subtree support. So I think as
> part of disabling nested tree support in wt 4-6 we should also add wt
> 7. Or do you perhaps mean that you would like to see the working tree
> changes split out?

Yup.

>
> >
> > 69 + if repo._format.supports_chks:
> > 70 + matching_format_name = '2a'
> > 71 + else:
> > 72 + matching_format_name = 'pack-0.92-subtree'
> >
> > 81 + if repo.supports_rich_root():
> > 82 + if repo._format.supports_chks:
> > 83 + matching_format_name = '2a'
> > 84 + else:
> > 85 + matching_format_name = 'pack-0.92-subtree'
> > 86 + else:
> > 87 + matching_format_name = 'dirstate-subtree'
> >
> > Urgh, these tests were already confusing, now they are almost undecipherable
> > :-(
> >
> > Can't you abstract the logic here so we get a clearer view of what we are
> > tested ? Since these tests are about stacking, I'd really prefer them to be
> > easier to grasp, especially regarding the compatibility between the various
> > formats. There is also a hint that it's time to address:
> >
> > # TODO: Possibly this should be run per-repository-format and raise
> > # TestNotApplicable on formats that don't support stacking. -- mbp
> > # 20080729
> I'll have a look.

Cool.

>
> >
> > 100 + if not tree...

Read more...

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 2012-01-18 20:27:41 +0000
3+++ bzrlib/bzrdir.py 2012-01-24 15:41:25 +0000
4@@ -2193,7 +2193,7 @@
5 help='Variant of dirstate with support for nested trees. '
6 'Introduced in 0.15.',
7 branch_format='bzrlib.branch.BzrBranchFormat6',
8- tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
9+ tree_format='bzrlib.workingtree_4.WorkingTreeFormat7',
10 experimental=True,
11 hidden=True,
12 )
13@@ -2293,7 +2293,7 @@
14 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
15 'before use.',
16 branch_format='bzrlib.branch.BzrBranchFormat7',
17- tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
18+ tree_format='bzrlib.workingtree_4.WorkingTreeFormat7',
19 experimental=True,
20 hidden=True,
21 alias=False, # Restore to being an alias when an actual development subtree format is added
22@@ -2309,7 +2309,7 @@
23 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
24 'before use.',
25 branch_format='bzrlib.branch.BzrBranchFormat7',
26- tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
27+ tree_format='bzrlib.workingtree_4.WorkingTreeFormat7',
28 experimental=True,
29 hidden=True,
30 alias=False,
31
32=== modified file 'bzrlib/commit.py'
33--- bzrlib/commit.py 2011-12-18 12:46:49 +0000
34+++ bzrlib/commit.py 2012-01-24 15:41:25 +0000
35@@ -347,7 +347,6 @@
36 # generation. See bug 347649.
37 self.use_record_iter_changes = (
38 not self.exclude and
39- not self.branch.repository._format.supports_tree_reference and
40 (self.branch.repository._format.fast_deltas or
41 len(self.parents) < 2))
42 self.pb = ui.ui_factory.nested_progress_bar()
43
44=== modified file 'bzrlib/repofmt/groupcompress_repo.py'
45--- bzrlib/repofmt/groupcompress_repo.py 2011-12-19 19:15:58 +0000
46+++ bzrlib/repofmt/groupcompress_repo.py 2012-01-24 15:41:25 +0000
47@@ -1362,6 +1362,7 @@
48 """A CHK repository that uses the bencode revision serializer."""
49
50 repository_class = CHKInventoryRepository
51+ supports_tree_reference = True
52 supports_external_lookups = True
53 supports_chks = True
54 _commit_builder_class = PackRootCommitBuilder
55@@ -1423,4 +1424,3 @@
56 "group compression and chk inventories")
57
58 experimental = True
59- supports_tree_reference = True
60
61=== modified file 'bzrlib/tests/per_pack_repository.py'
62--- bzrlib/tests/per_pack_repository.py 2011-08-19 22:34:02 +0000
63+++ bzrlib/tests/per_pack_repository.py 2012-01-24 15:41:25 +0000
64@@ -884,7 +884,10 @@
65 # can only stack on repositories that have compatible internal
66 # metadata
67 if getattr(repo._format, 'supports_tree_reference', False):
68- matching_format_name = 'pack-0.92-subtree'
69+ if repo._format.supports_chks:
70+ matching_format_name = '2a'
71+ else:
72+ matching_format_name = 'pack-0.92-subtree'
73 else:
74 if repo._format.supports_chks:
75 matching_format_name = '2a'
76@@ -915,7 +918,13 @@
77 if getattr(repo._format, 'supports_tree_reference', False):
78 # can only stack on repositories that have compatible internal
79 # metadata
80- matching_format_name = 'pack-0.92-subtree'
81+ if repo.supports_rich_root():
82+ if repo._format.supports_chks:
83+ matching_format_name = '2a'
84+ else:
85+ matching_format_name = 'pack-0.92-subtree'
86+ else:
87+ matching_format_name = 'dirstate-subtree'
88 mismatching_format_name = 'rich-root-pack'
89 else:
90 if repo.supports_rich_root():
91
92=== modified file 'bzrlib/tests/per_tree/test_path_content_summary.py'
93--- bzrlib/tests/per_tree/test_path_content_summary.py 2011-12-16 17:34:46 +0000
94+++ bzrlib/tests/per_tree/test_path_content_summary.py 2012-01-24 15:41:25 +0000
95@@ -147,7 +147,7 @@
96
97 def test_tree_content_summary(self):
98 tree = self.make_branch_and_tree('tree')
99- if not tree.branch.repository._format.supports_tree_reference:
100+ if not tree.supports_tree_reference():
101 raise tests.TestNotApplicable("Tree references not supported.")
102 subtree = self.make_branch_and_tree('tree/path')
103 tree.add(['path'])
104
105=== modified file 'bzrlib/tests/test_merge.py'
106--- bzrlib/tests/test_merge.py 2012-01-05 13:02:31 +0000
107+++ bzrlib/tests/test_merge.py 2012-01-24 15:41:25 +0000
108@@ -227,9 +227,9 @@
109
110 def test_nested_merge(self):
111 tree = self.make_branch_and_tree('tree',
112- format='dirstate-with-subtree')
113+ format='development-subtree')
114 sub_tree = self.make_branch_and_tree('tree/sub-tree',
115- format='dirstate-with-subtree')
116+ format='development-subtree')
117 sub_tree.set_root_id('sub-tree-root')
118 self.build_tree_contents([('tree/sub-tree/file', 'text1')])
119 sub_tree.add('file')
120
121=== modified file 'bzrlib/tests/test_smart.py'
122--- bzrlib/tests/test_smart.py 2012-01-19 19:18:47 +0000
123+++ bzrlib/tests/test_smart.py 2012-01-24 15:41:25 +0000
124@@ -2669,7 +2669,7 @@
125 base_inv = repository.revision_tree(base_revid).inventory
126 inv = repository.revision_tree(revid).inventory
127 inv_delta = inv._make_delta(base_inv)
128- serializer = inventory_delta.InventoryDeltaSerializer(True, False)
129+ serializer = inventory_delta.InventoryDeltaSerializer(True, True)
130 return "".join(serializer.delta_to_lines(base_revid, revid, inv_delta))
131
132 def test_single(self):
133
134=== modified file 'bzrlib/workingtree.py'
135--- bzrlib/workingtree.py 2012-01-18 17:47:06 +0000
136+++ bzrlib/workingtree.py 2012-01-24 15:41:25 +0000
137@@ -840,7 +840,7 @@
138 raise NotImplementedError(self.subsume)
139
140 def _setup_directory_is_tree_reference(self):
141- if self._branch.repository._format.supports_tree_reference:
142+ if self.supports_tree_reference():
143 self._directory_is_tree_reference = \
144 self._directory_may_be_tree_reference
145 else:
146@@ -3098,6 +3098,15 @@
147 """True if this format supports stored views."""
148 return False
149
150+ def supports_tree_reference(self):
151+ """True if this format supports tree references.
152+
153+ Note that in order to be able to add tree references the
154+ working tree, branch and repository all have to support
155+ tree references.
156+ """
157+ return False
158+
159 @classmethod
160 @symbol_versioning.deprecated_method(
161 symbol_versioning.deprecated_in((2, 4, 0)))
162@@ -3181,6 +3190,8 @@
163 "bzrlib.workingtree_4", "WorkingTreeFormat5")
164 format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
165 "bzrlib.workingtree_4", "WorkingTreeFormat6")
166+format_registry.register_lazy("Bazaar Working Tree Format 7 (bzr 2.6)\n",
167+ "bzrlib.workingtree_4", "WorkingTreeFormat7")
168 format_registry.register_lazy("Bazaar-NG Working Tree format 3",
169 "bzrlib.workingtree_3", "WorkingTreeFormat3")
170 format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")
171
172=== modified file 'bzrlib/workingtree_4.py'
173--- bzrlib/workingtree_4.py 2012-01-06 14:09:04 +0000
174+++ bzrlib/workingtree_4.py 2012-01-24 15:41:25 +0000
175@@ -201,7 +201,7 @@
176 WorkingTree._comparison_data(self, entry, path)
177 # it looks like a plain directory, but it's really a reference -- see
178 # also kind()
179- if (self._repo_supports_tree_reference and kind == 'directory'
180+ if (self.supports_tree_reference() and kind == 'directory'
181 and entry is not None and entry.kind == 'tree-reference'):
182 kind = 'tree-reference'
183 return kind, executable, stat_value
184@@ -346,7 +346,7 @@
185 # add this entry to the parent map.
186 parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
187 elif kind == 'tree-reference':
188- if not self._repo_supports_tree_reference:
189+ if not self.supports_tree_reference():
190 raise errors.UnsupportedOperation(
191 self._generate_inventory,
192 self.branch.repository)
193@@ -526,7 +526,7 @@
194 return iter(result)
195
196 def iter_references(self):
197- if not self._repo_supports_tree_reference:
198+ if not self.supports_tree_reference():
199 # When the repo doesn't support references, we will have nothing to
200 # return
201 return
202@@ -551,6 +551,7 @@
203 entry = self._get_entry(file_id=file_id, path=path)
204 state._observed_sha1(entry, sha1, statvalue)
205
206+ @needs_read_lock
207 def kind(self, file_id):
208 """Return the kind of a file.
209
210@@ -568,7 +569,7 @@
211 def _kind(self, relpath):
212 abspath = self.abspath(relpath)
213 kind = file_kind(abspath)
214- if (self._repo_supports_tree_reference and kind == 'directory'):
215+ if (self.supports_tree_reference() and kind == 'directory'):
216 entry = self._get_entry(path=relpath)
217 if entry[1] is not None:
218 if entry[1][0][0] == 't':
219@@ -1176,7 +1177,8 @@
220
221 @needs_read_lock
222 def supports_tree_reference(self):
223- return self._repo_supports_tree_reference
224+ return (self._format.supports_tree_reference() and
225+ self._repo_supports_tree_reference)
226
227 def unlock(self):
228 """Unlock in format 4 trees needs to write the entire dirstate."""
229@@ -1445,6 +1447,19 @@
230 return views.PathBasedViews(self)
231
232
233+class WorkingTree7(ContentFilteringDirStateWorkingTree):
234+ """This is the Format 7 working tree.
235+
236+ This differs from WorkingTree6 by:
237+ - Supporting nested trees.
238+
239+ This is new in bzr 2.6.
240+ """
241+
242+ def _make_views(self):
243+ return views.PathBasedViews(self)
244+
245+
246 class DirStateWorkingTreeFormat(WorkingTreeFormatMetaDir):
247
248 missing_parent_conflicts = True
249@@ -1597,8 +1612,7 @@
250 def _get_matchingbzrdir(self):
251 """Overrideable method to get a bzrdir for testing."""
252 # please test against something that will let us do tree references
253- return bzrdir.format_registry.make_bzrdir(
254- 'dirstate-with-subtree')
255+ return bzrdir.format_registry.make_bzrdir('2a')
256
257 _matchingbzrdir = property(__get_matchingbzrdir)
258
259@@ -1678,6 +1692,39 @@
260 return True
261
262
263+class WorkingTreeFormat7(DirStateWorkingTreeFormat):
264+ """WorkingTree format supporting nested trees.
265+
266+ This format is still experimental and can change.
267+ """
268+
269+ upgrade_recommended = False
270+
271+ _tree_class = WorkingTree7
272+
273+ @classmethod
274+ def get_format_string(cls):
275+ """See WorkingTreeFormat.get_format_string()."""
276+ return "Bazaar Working Tree Format 7 (bzr 2.6)\n"
277+
278+ def get_format_description(self):
279+ """See WorkingTreeFormat.get_format_description()."""
280+ return "Working tree format 6"
281+
282+ def _init_custom_control_files(self, wt):
283+ """Subclasses with custom control files should override this method."""
284+ wt._transport.put_bytes('views', '', mode=wt.bzrdir._get_file_mode())
285+
286+ def supports_content_filtering(self):
287+ return True
288+
289+ def supports_views(self):
290+ return True
291+
292+ def supports_tree_reference(self):
293+ return True
294+
295+
296 class DirStateRevisionTree(InventoryTree):
297 """A revision tree pulling the inventory from a dirstate.
298
299@@ -1738,7 +1785,7 @@
300 return path_utf8.decode('utf8')
301
302 def iter_references(self):
303- if not self._repo_supports_tree_reference:
304+ if not self.supports_tree_reference():
305 # When the repo doesn't support references, we will have nothing to
306 # return
307 return iter([])
308
309=== modified file 'doc/en/release-notes/bzr-2.6.txt'
310--- doc/en/release-notes/bzr-2.6.txt 2012-01-23 15:07:14 +0000
311+++ doc/en/release-notes/bzr-2.6.txt 2012-01-24 15:41:25 +0000
312@@ -31,6 +31,11 @@
313 the URL scheme when accessing a HTTPS location.
314 (Jelmer Vernooij, #125055)
315
316+ * The ``2a`` repository format now supports tree references, making
317+ it possible to import Git repositories with submodules in their
318+ history. It is not yet possible to check out revisions
319+ that contain nested trees. (Jelmer Vernooij, #402814)
320+
321 Bug Fixes
322 *********
323