Merge lp:~jelmer/brz/git-submodule into lp:brz

Proposed by Jelmer Vernooij
Status: Rejected
Rejected by: Jelmer Vernooij
Proposed branch: lp:~jelmer/brz/git-submodule
Merge into: lp:brz
Diff against target: 463 lines (+146/-43)
15 files modified
breezy/branch.py (+10/-12)
breezy/builtins.py (+6/-5)
breezy/bzr/branch.py (+8/-0)
breezy/bzr/bzrdir.py (+7/-1)
breezy/bzr/workingtree.py (+7/-0)
breezy/bzr/workingtree_4.py (+18/-14)
breezy/git/branch.py (+15/-0)
breezy/git/dir.py (+6/-1)
breezy/git/fetch.py (+3/-3)
breezy/git/workingtree.py (+33/-0)
breezy/merge.py (+1/-1)
breezy/tests/blackbox/test_branch.py (+15/-0)
breezy/tests/blackbox/test_reference.py (+2/-0)
breezy/tests/per_branch/test_branch.py (+5/-6)
breezy/workingtree.py (+10/-0)
To merge this branch: bzr merge lp:~jelmer/brz/git-submodule
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve
Review via email: mp+377752@code.launchpad.net

Commit message

Fix cloning of git repositories with submodules.

Description of the change

Fix cloning of git repositories with submodules.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :

Unmerged revisions

7454. By Jelmer Vernooij

Use strip_segment_parameters.

7453. By Jelmer Vernooij

Ignore missing nested trees.

7452. By Jelmer Vernooij

Fix typo.

7451. By Jelmer Vernooij

Import from gitmodules.

7450. By Jelmer Vernooij

Use find_previous_path rather than id2path.

7449. By Jelmer Vernooij

Fix tree reference listing.

7448. By Jelmer Vernooij

Move reference info to Git.

7447. By Jelmer Vernooij

Fix cloning of git repositories with submodules.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/branch.py'
2--- breezy/branch.py 2019-10-19 23:18:56 +0000
3+++ breezy/branch.py 2020-01-17 02:30:07 +0000
4@@ -51,7 +51,7 @@
5 text_type,
6 viewitems,
7 )
8-from .trace import mutter, mutter_callsite, note, is_quiet
9+from .trace import mutter, mutter_callsite, note, is_quiet, warning
10
11
12 class UnstackableBranchFormat(errors.BzrError):
13@@ -676,14 +676,6 @@
14 raise errors.UpgradeRequired(self.user_url)
15 self.get_config_stack().set('append_revisions_only', enabled)
16
17- def set_reference_info(self, tree_path, branch_location, file_id=None):
18- """Set the branch location to use for a tree reference."""
19- raise errors.UnsupportedOperation(self.set_reference_info, self)
20-
21- def get_reference_info(self, path):
22- """Get the tree_path and branch_location for a tree reference."""
23- raise errors.UnsupportedOperation(self.get_reference_info, self)
24-
25 def fetch(self, from_branch, last_revision=None, limit=None):
26 """Copy revisions from from_branch into this branch.
27
28@@ -1412,7 +1404,10 @@
29 basis_tree = tree.basis_tree()
30 with basis_tree.lock_read():
31 for path in basis_tree.iter_references():
32- reference_parent = self.reference_parent(path)
33+ reference_parent = tree.reference_parent(path)
34+ if reference_parent is None:
35+ warning('Branch location for %s unknown.', path)
36+ continue
37 reference_parent.create_checkout(
38 tree.abspath(path),
39 basis_tree.get_reference_revision(path), lightweight)
40@@ -1432,8 +1427,11 @@
41 :return: A branch associated with the nested tree
42 """
43 # FIXME should provide multiple branches, based on config
44- return Branch.open(self.controldir.root_transport.clone(path).base,
45- possible_transports=possible_transports)
46+ try:
47+ return Branch.open(self.controldir.root_transport.clone(path).base,
48+ possible_transports=possible_transports)
49+ except errors.NotBranchError:
50+ return None
51
52 def supports_tags(self):
53 return self._format.supports_tags()
54
55=== modified file 'breezy/builtins.py'
56--- breezy/builtins.py 2020-01-12 14:46:56 +0000
57+++ breezy/builtins.py 2020-01-17 02:30:07 +0000
58@@ -6738,21 +6738,22 @@
59 if tree is None:
60 tree = branch.basis_tree()
61 if path is None:
62- info = viewitems(branch._get_all_reference_info())
63+ info = [
64+ (path, tree.get_reference_info(path))
65+ for path in tree.iter_references()]
66 self._display_reference_info(tree, branch, info)
67 else:
68 if not tree.is_versioned(path) and not force_unversioned:
69 raise errors.NotVersionedError(path)
70 if location is None:
71- info = [(path, branch.get_reference_info(path))]
72+ info = [(path, tree.get_reference_info(path))]
73 self._display_reference_info(tree, branch, info)
74 else:
75- branch.set_reference_info(
76- path, location, file_id=tree.path2id(path))
77+ tree.set_reference_info(path, location)
78
79 def _display_reference_info(self, tree, branch, info):
80 ref_list = []
81- for path, (location, file_id) in info:
82+ for path, location in info:
83 ref_list.append((path, location))
84 for path, location in sorted(ref_list):
85 self.outf.write('%s %s\n' % (path, location))
86
87=== modified file 'breezy/bzr/branch.py'
88--- breezy/bzr/branch.py 2020-01-12 13:56:10 +0000
89+++ breezy/bzr/branch.py 2020-01-17 02:30:07 +0000
90@@ -450,6 +450,14 @@
91 reconciler = BranchReconciler(self, thorough=thorough)
92 return reconciler.reconcile()
93
94+ def set_reference_info(self, tree_path, branch_location, file_id=None):
95+ """Set the branch location to use for a tree reference."""
96+ raise errors.UnsupportedOperation(self.set_reference_info, self)
97+
98+ def get_reference_info(self, path):
99+ """Get the tree_path and branch_location for a tree reference."""
100+ raise errors.UnsupportedOperation(self.get_reference_info, self)
101+
102
103 class BzrBranch8(BzrBranch):
104 """A branch that stores tree-reference locations."""
105
106=== modified file 'breezy/bzr/bzrdir.py'
107--- breezy/bzr/bzrdir.py 2019-10-20 00:11:04 +0000
108+++ breezy/bzr/bzrdir.py 2020-01-17 02:30:07 +0000
109@@ -65,6 +65,7 @@
110 from ..trace import (
111 mutter,
112 note,
113+ warning,
114 )
115
116 from .. import (
117@@ -467,8 +468,13 @@
118 subtrees = []
119 for path in subtrees:
120 target = urlutils.join(url, urlutils.escape(path))
121- sublocation = source_branch.reference_parent(
122+ sublocation = wt.reference_parent(
123 path, possible_transports=possible_transports)
124+ if sublocation is None:
125+ warning(
126+ 'Ignoring nested tree %s, parent location unknown.',
127+ path)
128+ continue
129 sublocation.controldir.sprout(
130 target, basis.get_reference_revision(path),
131 force_new_repo=force_new_repo, recurse=recurse,
132
133=== modified file 'breezy/bzr/workingtree.py'
134--- breezy/bzr/workingtree.py 2020-01-11 02:39:17 +0000
135+++ breezy/bzr/workingtree.py 2020-01-17 02:30:07 +0000
136@@ -1796,6 +1796,13 @@
137 else:
138 yield get_canonical_path(self, path, normalize)
139
140+ def get_reference_info(self, path):
141+ return self.branch.get_reference_info(path)[0]
142+
143+ def set_reference_info(self, tree_path, branch_location):
144+ self.branch.set_reference_info(
145+ tree_path, branch_location, file_id=self.path2id(tree_path))
146+
147
148 class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
149 """Base class for working trees that live in bzr meta directories."""
150
151=== modified file 'breezy/bzr/workingtree_4.py'
152--- breezy/bzr/workingtree_4.py 2020-01-11 22:33:18 +0000
153+++ breezy/bzr/workingtree_4.py 2020-01-17 02:30:07 +0000
154@@ -130,6 +130,9 @@
155 self.views = self._make_views()
156 # --- allow tests to select the dirstate iter_changes implementation
157 self._iter_changes = dirstate._process_entry
158+ self._repo_supports_tree_reference = getattr(
159+ self._branch.repository._format, "supports_tree_reference",
160+ False)
161
162 def _add(self, files, ids, kinds):
163 """See MutableTree._add."""
164@@ -550,20 +553,21 @@
165 # When the repo doesn't support references, we will have nothing to
166 # return
167 return
168- for key, tree_details in self.current_dirstate()._iter_entries():
169- if tree_details[0][0] in (b'a', b'r'): # absent, relocated
170- # not relevant to the working tree
171- continue
172- if not key[1]:
173- # the root is not a reference.
174- continue
175- relpath = pathjoin(key[0].decode('utf8'), key[1].decode('utf8'))
176- try:
177- if self.kind(relpath) == 'tree-reference':
178- yield relpath
179- except errors.NoSuchFile:
180- # path is missing on disk.
181- continue
182+ with self.lock_read():
183+ for key, tree_details in self.current_dirstate()._iter_entries():
184+ if tree_details[0][0] in (b'a', b'r'): # absent, relocated
185+ # not relevant to the working tree
186+ continue
187+ if not key[1]:
188+ # the root is not a reference.
189+ continue
190+ relpath = pathjoin(key[0].decode('utf8'), key[1].decode('utf8'))
191+ try:
192+ if self.kind(relpath) == 'tree-reference':
193+ yield relpath
194+ except errors.NoSuchFile:
195+ # path is missing on disk.
196+ continue
197
198 def _observed_sha1(self, path, sha_and_stat):
199 """See MutableTree._observed_sha1."""
200
201=== modified file 'breezy/git/branch.py'
202--- breezy/git/branch.py 2020-01-16 23:24:40 +0000
203+++ breezy/git/branch.py 2020-01-17 02:30:07 +0000
204@@ -22,6 +22,10 @@
205 from io import BytesIO
206 from collections import defaultdict
207
208+from dulwich.config import (
209+ ConfigFile as GitConfigFile,
210+ parse_submodules,
211+ )
212 from dulwich.objects import (
213 NotCommitError,
214 ZERO_SHA,
215@@ -980,6 +984,15 @@
216 other_branch=self.source)
217 return head, refs
218
219+ def _import_tree_references(self, revid):
220+ tree = self.target.repository.revision_tree(revid)
221+ with tree.get_file('.gitmodules') as f:
222+ for path, url, section in parse_submodules(
223+ GitConfigFile.from_file(f)):
224+ self.target.set_reference_info(
225+ path.decode('utf-8'), url.decode('utf-8'),
226+ tree.path2id(path.decode('utf-8')))
227+
228 def _basic_pull(self, stop_revision, overwrite, run_hooks,
229 _override_hook_target, _hook_master):
230 if overwrite is True:
231@@ -1007,6 +1020,7 @@
232 result.tag_conflicts = tags_ret
233 (result.new_revno, result.new_revid) = \
234 self.target.last_revision_info()
235+ self._import_tree_references(result.new_revid)
236 if _hook_master:
237 result.master_branch = _hook_master
238 result.local_branch = result.target_branch
239@@ -1075,6 +1089,7 @@
240 self.target.tags, "tags" in overwrite, ignore_master=True)
241 (result.tag_updates, result.tag_conflicts) = tags_ret
242 result.new_revno, result.new_revid = self.target.last_revision_info()
243+ self._import_tree_references(result.new_revid)
244 return result
245
246
247
248=== modified file 'breezy/git/dir.py'
249--- breezy/git/dir.py 2020-01-12 14:46:56 +0000
250+++ breezy/git/dir.py 2020-01-17 02:30:07 +0000
251@@ -207,8 +207,13 @@
252 subtrees = []
253 for path in subtrees:
254 target = urlutils.join(url, urlutils.escape(path))
255- sublocation = source_branch.reference_parent(
256+ sublocation = wt.reference_parent(
257 path, possible_transports=possible_transports)
258+ if sublocation is None:
259+ trace.warning(
260+ 'Ignoring nested tree %s, parent location unknown.',
261+ path)
262+ continue
263 sublocation.controldir.sprout(
264 target, basis.get_reference_revision(path),
265 force_new_repo=force_new_repo, recurse=recurse,
266
267=== modified file 'breezy/git/fetch.py'
268--- breezy/git/fetch.py 2019-10-28 01:38:39 +0000
269+++ breezy/git/fetch.py 2020-01-17 02:30:07 +0000
270@@ -55,6 +55,7 @@
271 from ..bzr.testament import (
272 StrictTestament3,
273 )
274+from ..tree import find_previous_path
275 from ..tsort import (
276 topo_sort,
277 )
278@@ -125,9 +126,8 @@
279 # Check what revision we should store
280 parent_keys = []
281 for ptree in parent_bzr_trees:
282- try:
283- ppath = ptree.id2path(file_id)
284- except errors.NoSuchId:
285+ ppath = find_previous_path(base_bzr_tree, ptree, decoded_path, file_id)
286+ if ppath is None:
287 continue
288 pkind = ptree.kind(ppath)
289 if (pkind == ie.kind and
290
291=== modified file 'breezy/git/workingtree.py'
292--- breezy/git/workingtree.py 2020-01-10 01:37:30 +0000
293+++ breezy/git/workingtree.py 2020-01-17 02:30:07 +0000
294@@ -25,6 +25,7 @@
295 from dulwich.ignore import (
296 IgnoreFilterManager,
297 )
298+from dulwich.config import ConfigFile as GitConfigFile
299 from dulwich.file import GitFile, FileLocked
300 from dulwich.index import (
301 Index,
302@@ -49,6 +50,7 @@
303 import sys
304
305 from .. import (
306+ branch as _mod_branch,
307 conflicts as _mod_conflicts,
308 errors,
309 controldir as _mod_controldir,
310@@ -1325,6 +1327,37 @@
311 new_parents = [revision_id]
312 tree.set_parent_ids(new_parents)
313
314+ def reference_parent(self, path, possible_transports=None):
315+ remote_url = self.get_reference_info(path)
316+ if remote_url is None:
317+ trace.warning("Unable to find submodule info for %s", path)
318+ return None
319+ return _mod_branch.Branch.open(remote_url, possible_transports=possible_transports)
320+
321+ def get_reference_info(self, path):
322+ submodule_info = self._submodule_info()
323+ info = submodule_info.get(path.encode('utf-8'))
324+ if info is None:
325+ return None
326+ return info[0].decode('utf-8')
327+
328+ def set_reference_info(self, tree_path, branch_location):
329+ path = self.abspath('.gitmodules')
330+ try:
331+ config = GitConfigFile.from_path(path)
332+ except EnvironmentError as e:
333+ if e.errno == errno.ENOENT:
334+ config = GitConfigFile()
335+ else:
336+ raise
337+ config.set(
338+ (b'submodule', tree_path.encode('utf-8')),
339+ b'path', tree_path.encode('utf-8'))
340+ config.set(
341+ (b'submodule', tree_path.encode('utf-8')),
342+ b'url', branch_location.encode('utf-8'))
343+ config.write_to_path(path)
344+
345
346 class GitWorkingTreeFormat(workingtree.WorkingTreeFormat):
347
348
349=== modified file 'breezy/merge.py'
350--- breezy/merge.py 2019-10-13 17:31:55 +0000
351+++ breezy/merge.py 2020-01-17 02:30:07 +0000
352@@ -641,7 +641,7 @@
353 continue
354 sub_merge = Merger(sub_tree.branch, this_tree=sub_tree)
355 sub_merge.merge_type = self.merge_type
356- other_branch = self.other_branch.reference_parent(relpath)
357+ other_branch = self.other_tree.reference_parent(relpath)
358 sub_merge.set_other_revision(other_revision, other_branch)
359 base_tree_path = _mod_tree.find_previous_path(
360 self.this_tree, self.base_tree, relpath)
361
362=== modified file 'breezy/tests/blackbox/test_branch.py'
363--- breezy/tests/blackbox/test_branch.py 2019-10-19 23:18:56 +0000
364+++ breezy/tests/blackbox/test_branch.py 2020-01-17 02:30:07 +0000
365@@ -367,6 +367,7 @@
366 subtree.add(['a'])
367 subtree.commit('add subtree contents')
368 orig.add_reference(subtree)
369+ orig.branch.set_reference_info('subtree', subtree.branch.user_url)
370 orig.commit('add subtree')
371
372 self.run_bzr('branch source target')
373@@ -376,6 +377,20 @@
374 self.assertTreesEqual(orig, target)
375 self.assertTreesEqual(subtree, target_subtree)
376
377+ def test_branch_with_nested_trees_reference_unset(self):
378+ orig = self.make_branch_and_tree('source', format='development-subtree')
379+ subtree = self.make_branch_and_tree('source/subtree')
380+ self.build_tree(['source/subtree/a'])
381+ subtree.add(['a'])
382+ subtree.commit('add subtree contents')
383+ orig.add_reference(subtree)
384+ orig.commit('add subtree')
385+
386+ self.run_bzr('branch source target')
387+
388+ target = WorkingTree.open('target')
389+ self.assertRaises(errors.NotBranchError, WorkingTree.open, 'target/subtree')
390+
391 def test_branch_with_nested_trees_no_recurse(self):
392 orig = self.make_branch_and_tree('source', format='development-subtree')
393 subtree = self.make_branch_and_tree('source/subtree')
394
395=== modified file 'breezy/tests/blackbox/test_reference.py'
396--- breezy/tests/blackbox/test_reference.py 2018-11-16 11:37:47 +0000
397+++ breezy/tests/blackbox/test_reference.py 2020-01-17 02:30:07 +0000
398@@ -76,6 +76,8 @@
399 tree.add('file', b'file-id')
400 out, err = self.run_bzr('reference tree/file http://example.org')
401 location, file_id = tree.branch.get_reference_info('file')
402+ tree_location = tree.get_reference_info('file')
403+ self.assertEqual('http://example.org', tree_location)
404 self.assertEqual('http://example.org', location)
405 self.assertEqual(b'file-id', file_id)
406 self.assertEqual('', out)
407
408=== modified file 'breezy/tests/per_branch/test_branch.py'
409--- breezy/tests/per_branch/test_branch.py 2020-01-12 15:16:27 +0000
410+++ breezy/tests/per_branch/test_branch.py 2020-01-17 02:30:07 +0000
411@@ -858,8 +858,8 @@
412 raise tests.TestNotApplicable('Tree cannot hold references.')
413 reference_parent = tree.branch.reference_parent(
414 urlutils.relative_url(
415- urlutils.split_segment_parameters(tree.branch.user_url)[0],
416- urlutils.split_segment_parameters(subtree.branch.user_url)[0]))
417+ urlutils.strip_segment_parameters(tree.branch.user_url),
418+ urlutils.strip_segment_parameters(subtree.branch.user_url)))
419 self.assertEqual(subtree.branch.user_url, reference_parent.user_url)
420
421 def test_reference_parent_accepts_possible_transports(self):
422@@ -872,8 +872,8 @@
423 raise tests.TestNotApplicable('Tree cannot hold references.')
424 reference_parent = tree.branch.reference_parent(
425 urlutils.relative_url(
426- urlutils.split_segment_parameters(tree.branch.user_url)[0],
427- urlutils.split_segment_parameters(subtree.branch.user_url)[0]),
428+ urlutils.strip_segment_parameters(tree.branch.user_url),
429+ urlutils.strip_segment_parameters(subtree.branch.user_url)),
430 possible_transports=[subtree.controldir.root_transport])
431
432 def test_get_reference_info(self):
433@@ -1014,8 +1014,7 @@
434 'branch/new-branch').open_branch()
435 new_branch.set_reference_info('../foo', '../foo', b'file-id2')
436 new_branch.push(branch)
437- self.assertEqual('foo',
438- branch.get_reference_info('../foo')[0])
439+ self.assertEqual('foo', branch.get_reference_info('../foo')[0])
440
441 def test_merge_updates_references(self):
442 branch = self.make_branch_with_reference('branch', 'reference')
443
444=== modified file 'breezy/workingtree.py'
445--- breezy/workingtree.py 2020-01-11 17:50:28 +0000
446+++ breezy/workingtree.py 2020-01-17 02:30:07 +0000
447@@ -1325,6 +1325,16 @@
448 with self.lock_read():
449 return next(self.get_canonical_paths([path]))
450
451+ def reference_parent(self, path, possible_transports=None):
452+ return self.branch.reference_parent(
453+ path, possible_transports=possible_transports)
454+
455+ def get_reference_info(self, path):
456+ raise errors.UnsupportedOperation(self.get_reference_info, self)
457+
458+ def set_reference_info(self, tree_path, branch_location):
459+ raise errors.UnsupportedOperation(self.set_reference_info, self)
460+
461
462 class WorkingTreeFormatRegistry(ControlComponentFormatRegistry):
463 """Registry for working tree formats."""

Subscribers

People subscribed via source and target branches