Merge lp:~jelmer/brz/move-reference-functions into lp:brz

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/move-reference-functions
Merge into: lp:brz
Diff against target: 1111 lines (+440/-275)
19 files modified
breezy/branch.py (+5/-20)
breezy/builtins.py (+11/-13)
breezy/bzr/branch.py (+33/-4)
breezy/bzr/bzrdir.py (+18/-9)
breezy/bzr/inventorytree.py (+23/-2)
breezy/bzr/remote.py (+25/-0)
breezy/bzr/workingtree.py (+10/-0)
breezy/git/branch.py (+0/-11)
breezy/git/dir.py (+6/-1)
breezy/git/workingtree.py (+46/-1)
breezy/merge.py (+1/-1)
breezy/tests/blackbox/test_branch.py (+15/-0)
breezy/tests/blackbox/test_reference.py (+15/-14)
breezy/tests/per_branch/test_branch.py (+0/-189)
breezy/tests/per_workingtree/test_workingtree.py (+214/-3)
breezy/tests/test_branch.py (+4/-2)
breezy/tests/test_bzrdir.py (+4/-4)
breezy/tree.py (+1/-1)
breezy/workingtree.py (+9/-0)
To merge this branch: bzr merge lp:~jelmer/brz/move-reference-functions
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve
Review via email: mp+377800@code.launchpad.net

Commit message

Move tree reference info functions to workingtree.

Description of the change

Move tree reference info functions to workingtree.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve

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 2020-01-18 15:06:40 +0000
3+++ breezy/branch.py 2020-01-19 02:30:26 +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@@ -1401,7 +1393,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@@ -1414,16 +1409,6 @@
41 """
42 raise NotImplementedError(self.reconcile)
43
44- def reference_parent(self, path, possible_transports=None):
45- """Return the parent branch for a tree-reference file_id
46-
47- :param path: The path of the nested tree in the tree
48- :return: A branch associated with the nested tree
49- """
50- # FIXME should provide multiple branches, based on config
51- return Branch.open(self.controldir.root_transport.clone(path).base,
52- possible_transports=possible_transports)
53-
54 def supports_tags(self):
55 return self._format.supports_tags()
56
57
58=== modified file 'breezy/builtins.py'
59--- breezy/builtins.py 2020-01-12 14:46:56 +0000
60+++ breezy/builtins.py 2020-01-19 02:30:26 +0000
61@@ -6723,36 +6723,34 @@
62
63 takes_args = ['path?', 'location?']
64 takes_options = [
65+ 'directory',
66 Option('force-unversioned',
67 help='Set reference even if path is not versioned.'),
68 ]
69
70- def run(self, path=None, location=None, force_unversioned=False):
71- branchdir = '.'
72- if path is not None:
73- branchdir = path
74+ def run(self, path=None, directory='.', location=None, force_unversioned=False):
75 tree, branch, relpath = (
76- controldir.ControlDir.open_containing_tree_or_branch(branchdir))
77- if path is not None:
78- path = relpath
79+ controldir.ControlDir.open_containing_tree_or_branch(directory))
80 if tree is None:
81 tree = branch.basis_tree()
82 if path is None:
83- info = viewitems(branch._get_all_reference_info())
84- self._display_reference_info(tree, branch, info)
85+ with tree.lock_read():
86+ info = [
87+ (path, tree.get_reference_info(path, branch))
88+ for path in tree.iter_references()]
89+ self._display_reference_info(tree, branch, info)
90 else:
91 if not tree.is_versioned(path) and not force_unversioned:
92 raise errors.NotVersionedError(path)
93 if location is None:
94- info = [(path, branch.get_reference_info(path))]
95+ info = [(path, tree.get_reference_info(path, branch))]
96 self._display_reference_info(tree, branch, info)
97 else:
98- branch.set_reference_info(
99- path, location, file_id=tree.path2id(path))
100+ tree.set_reference_info(path, location)
101
102 def _display_reference_info(self, tree, branch, info):
103 ref_list = []
104- for path, (location, file_id) in info:
105+ for path, location in info:
106 ref_list.append((path, location))
107 for path, location in sorted(ref_list):
108 self.outf.write('%s %s\n' % (path, location))
109
110=== modified file 'breezy/bzr/branch.py'
111--- breezy/bzr/branch.py 2020-01-12 13:56:10 +0000
112+++ breezy/bzr/branch.py 2020-01-19 02:30:26 +0000
113@@ -450,6 +450,29 @@
114 reconciler = BranchReconciler(self, thorough=thorough)
115 return reconciler.reconcile()
116
117+ def set_reference_info(self, tree_path, branch_location, file_id=None):
118+ """Set the branch location to use for a tree reference."""
119+ raise errors.UnsupportedOperation(self.set_reference_info, self)
120+
121+ def get_reference_info(self, path):
122+ """Get the tree_path and branch_location for a tree reference."""
123+ raise errors.UnsupportedOperation(self.get_reference_info, self)
124+
125+ def reference_parent(self, path, possible_transports=None):
126+ """Return the parent branch for a tree-reference.
127+
128+ :param path: The path of the nested tree in the tree
129+ :return: A branch associated with the nested tree
130+ """
131+ branch_location = self.get_reference_info(path)[0]
132+ if branch_location is None:
133+ try:
134+ return Branch.open_from_transport(
135+ self.controldir.root_transport.clone(path),
136+ possible_transports=possible_transports)
137+ except errors.NotBranchError:
138+ return None
139+
140
141 class BzrBranch8(BzrBranch):
142 """A branch that stores tree-reference locations."""
143@@ -583,10 +606,16 @@
144 """
145 branch_location = self.get_reference_info(path)[0]
146 if branch_location is None:
147- return Branch.reference_parent(self, path, possible_transports)
148- branch_location = urlutils.join(self.user_url, branch_location)
149- return Branch.open(branch_location,
150- possible_transports=possible_transports)
151+ try:
152+ return Branch.open_from_transport(
153+ self.controldir.root_transport.clone(path),
154+ possible_transports=possible_transports)
155+ except errors.NotBranchError:
156+ return None
157+ else:
158+ branch_location = urlutils.join(self.user_url, branch_location)
159+ return Branch.open(
160+ branch_location, possible_transports=possible_transports)
161
162 def set_push_location(self, location):
163 """See Branch.set_push_location."""
164
165=== modified file 'breezy/bzr/bzrdir.py'
166--- breezy/bzr/bzrdir.py 2019-10-20 00:11:04 +0000
167+++ breezy/bzr/bzrdir.py 2020-01-19 02:30:26 +0000
168@@ -65,6 +65,7 @@
169 from ..trace import (
170 mutter,
171 note,
172+ warning,
173 )
174
175 from .. import (
176@@ -453,22 +454,30 @@
177 else:
178 wt = None
179 if recurse == 'down':
180- basis = None
181+ tree = None
182 if wt is not None:
183- basis = wt.basis_tree()
184+ tree = wt
185+ basis = tree.basis_tree()
186+ stack.enter_context(basis.lock_read())
187 elif result_branch is not None:
188- basis = result_branch.basis_tree()
189+ basis = tree = result_branch.basis_tree()
190 elif source_branch is not None:
191- basis = source_branch.basis_tree()
192- if basis is not None:
193- stack.enter_context(basis.lock_read())
194- subtrees = basis.iter_references()
195+ basis = tree = source_branch.basis_tree()
196+ if tree is not None:
197+ stack.enter_context(tree.lock_read())
198+ subtrees = tree.iter_references()
199 else:
200 subtrees = []
201 for path in subtrees:
202 target = urlutils.join(url, urlutils.escape(path))
203- sublocation = source_branch.reference_parent(
204- path, possible_transports=possible_transports)
205+ sublocation = tree.reference_parent(
206+ path, branch=result_branch,
207+ possible_transports=possible_transports)
208+ if sublocation is None:
209+ warning(
210+ 'Ignoring nested tree %s, parent location unknown.',
211+ path)
212+ continue
213 sublocation.controldir.sprout(
214 target, basis.get_reference_revision(path),
215 force_new_repo=force_new_repo, recurse=recurse,
216
217=== modified file 'breezy/bzr/inventorytree.py'
218--- breezy/bzr/inventorytree.py 2020-01-11 02:39:17 +0000
219+++ breezy/bzr/inventorytree.py 2020-01-19 02:30:26 +0000
220@@ -23,6 +23,7 @@
221 import re
222
223 from .. import (
224+ branch as _mod_branch,
225 debug,
226 errors,
227 lazy_import,
228@@ -199,7 +200,10 @@
229 trace.mutter_callsite(
230 2, "id2path with nested trees scales with tree size.")
231 for path in self.iter_references():
232- subtree = self.get_nested_tree(path)
233+ try:
234+ subtree = self.get_nested_tree(path)
235+ except errors.NotBranchError:
236+ continue
237 try:
238 return osutils.pathjoin(path, subtree.id2path(file_id))
239 except errors.NoSuchId:
240@@ -784,6 +788,22 @@
241 def has_filename(self, filename):
242 return bool(self.path2id(filename))
243
244+ def reference_parent(self, path, branch=None, possible_transports=None):
245+ if branch is not None:
246+ parent_url = branch.get_reference_info(path)[0]
247+ else:
248+ subdir = ControlDir.open_from_transport(
249+ self._repository.user_transport.clone(path))
250+ parent_url = subdir.open_branch().get_parent()
251+ if parent_url is None:
252+ return None
253+ return _mod_branch.Branch.open(
254+ parent_url,
255+ possible_transports=possible_transports)
256+
257+ def get_reference_info(self, path, branch=None):
258+ return branch.get_reference_info(path)[0]
259+
260 def list_files(self, include_root=False, from_dir=None, recursive=True,
261 recurse_nested=False):
262 # The only files returned by this are those from the version
263@@ -823,7 +843,8 @@
264
265 def _get_nested_tree(self, path, file_id, reference_revision):
266 # Just a guess..
267- subdir = ControlDir.open_from_transport(self._repository.user_transport.clone(path))
268+ subdir = ControlDir.open_from_transport(
269+ self._repository.user_transport.clone(path))
270 subrepo = subdir.find_repository()
271 try:
272 revtree = subrepo.revision_tree(reference_revision)
273
274=== modified file 'breezy/bzr/remote.py'
275--- breezy/bzr/remote.py 2019-06-29 22:49:46 +0000
276+++ breezy/bzr/remote.py 2020-01-19 02:30:26 +0000
277@@ -3415,6 +3415,8 @@
278 return True
279 return False
280
281+ supports_reference_locations = False
282+
283
284 class RemoteBranchStore(_mod_config.IniFileStore):
285 """Branch store which attempts to use HPSS calls to retrieve branch store.
286@@ -4177,6 +4179,29 @@
287 reconciler = BranchReconciler(self, thorough=thorough)
288 return reconciler.reconcile()
289
290+ def set_reference_info(self, tree_path, branch_location, file_id=None):
291+ raise errors.UnsupportedOperation(self.set_reference_info, self)
292+
293+ def get_reference_info(self, tree_path):
294+ raise errors.UnsupportedOperation(self.get_reference_info, self)
295+
296+ def _get_all_reference_info(self):
297+ self._ensure_real()
298+ return self._real_branch._get_all_reference_info()
299+
300+ def reference_parent(self, path, possible_transports=None):
301+ """Return the parent branch for a tree-reference.
302+
303+ :param path: The path of the nested tree in the tree
304+ :return: A branch associated with the nested tree
305+ """
306+ branch_location = self.get_reference_info(path)[0]
307+ if branch_location is None:
308+ return BzrBranch.reference_parent(self, path, possible_transports)
309+ branch_location = urlutils.join(self.user_url, branch_location)
310+ return Branch.open(branch_location,
311+ possible_transports=possible_transports)
312+
313
314 class RemoteConfig(object):
315 """A Config that reads and writes from smart verbs.
316
317=== modified file 'breezy/bzr/workingtree.py'
318--- breezy/bzr/workingtree.py 2020-01-11 02:39:17 +0000
319+++ breezy/bzr/workingtree.py 2020-01-19 02:30:26 +0000
320@@ -1796,6 +1796,16 @@
321 else:
322 yield get_canonical_path(self, path, normalize)
323
324+ def get_reference_info(self, path, branch=None):
325+ return self.branch.get_reference_info(path)[0]
326+
327+ def set_reference_info(self, tree_path, branch_location):
328+ self.branch.set_reference_info(tree_path, branch_location)
329+
330+ def reference_parent(self, path, branch=None, possible_transports=None):
331+ return self.branch.reference_parent(
332+ path, possible_transports=possible_transports)
333+
334
335 class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
336 """Base class for working trees that live in bzr meta directories."""
337
338=== modified file 'breezy/git/branch.py'
339--- breezy/git/branch.py 2020-01-18 15:06:40 +0000
340+++ breezy/git/branch.py 2020-01-19 02:30:26 +0000
341@@ -814,17 +814,6 @@
342 return GitMemoryTree(self, self.repository._git.object_store,
343 self.head)
344
345- def reference_parent(self, path, possible_transports=None):
346- """Return the parent branch for a tree-reference.
347-
348- :param path: The path of the nested tree in the tree
349- :return: A branch associated with the nested tree
350- """
351- # FIXME should provide multiple branches, based on config
352- url = urlutils.strip_segment_parameters(self.user_url)
353- url = urlutils.join(url, path)
354- return branch.Branch.open(url, possible_transports=possible_transports)
355-
356
357 def _quick_lookup_revno(local_branch, remote_branch, revid):
358 if not isinstance(revid, bytes):
359
360=== modified file 'breezy/git/dir.py'
361--- breezy/git/dir.py 2020-01-12 14:46:56 +0000
362+++ breezy/git/dir.py 2020-01-19 02:30:26 +0000
363@@ -207,8 +207,13 @@
364 subtrees = []
365 for path in subtrees:
366 target = urlutils.join(url, urlutils.escape(path))
367- sublocation = source_branch.reference_parent(
368+ sublocation = wt.reference_parent(
369 path, possible_transports=possible_transports)
370+ if sublocation is None:
371+ trace.warning(
372+ 'Ignoring nested tree %s, parent location unknown.',
373+ path)
374+ continue
375 sublocation.controldir.sprout(
376 target, basis.get_reference_revision(path),
377 force_new_repo=force_new_repo, recurse=recurse,
378
379=== modified file 'breezy/git/workingtree.py'
380--- breezy/git/workingtree.py 2020-01-10 01:37:30 +0000
381+++ breezy/git/workingtree.py 2020-01-19 02:30:26 +0000
382@@ -25,6 +25,7 @@
383 from dulwich.ignore import (
384 IgnoreFilterManager,
385 )
386+from dulwich.config import ConfigFile as GitConfigFile
387 from dulwich.file import GitFile, FileLocked
388 from dulwich.index import (
389 Index,
390@@ -49,6 +50,7 @@
391 import sys
392
393 from .. import (
394+ branch as _mod_branch,
395 conflicts as _mod_conflicts,
396 errors,
397 controldir as _mod_controldir,
398@@ -61,6 +63,7 @@
399 trace,
400 transport as _mod_transport,
401 tree,
402+ urlutils,
403 workingtree,
404 )
405 from ..decorators import (
406@@ -1240,7 +1243,7 @@
407 def _read_submodule_head(self, path):
408 return read_submodule_head(self.abspath(path))
409
410- def get_reference_revision(self, path):
411+ def get_reference_revision(self, path, branch=None):
412 hexsha = self._read_submodule_head(path)
413 if hexsha is None:
414 return _mod_revision.NULL_REVISION
415@@ -1325,6 +1328,48 @@
416 new_parents = [revision_id]
417 tree.set_parent_ids(new_parents)
418
419+ def reference_parent(self, path, possible_transports=None):
420+ remote_url = self.get_reference_info(path)
421+ if remote_url is None:
422+ trace.warning("Unable to find submodule info for %s", path)
423+ return None
424+ return _mod_branch.Branch.open(remote_url, possible_transports=possible_transports)
425+
426+ def get_reference_info(self, path):
427+ submodule_info = self._submodule_info()
428+ info = submodule_info.get(path.encode('utf-8'))
429+ if info is None:
430+ return None
431+ return info[0].decode('utf-8')
432+
433+ def set_reference_info(self, tree_path, branch_location):
434+ path = self.abspath('.gitmodules')
435+ try:
436+ config = GitConfigFile.from_path(path)
437+ except EnvironmentError as e:
438+ if e.errno == errno.ENOENT:
439+ config = GitConfigFile()
440+ else:
441+ raise
442+ section = (b'submodule', tree_path.encode('utf-8'))
443+ if branch_location is None:
444+ try:
445+ del config[section]
446+ except KeyError:
447+ pass
448+ else:
449+ branch_location = urlutils.join(
450+ urlutils.strip_segment_parameters(self.branch.user_url),
451+ branch_location)
452+ config.set(
453+ section,
454+ b'path', tree_path.encode('utf-8'))
455+ config.set(
456+ section,
457+ b'url', branch_location.encode('utf-8'))
458+ config.write_to_path(path)
459+ self.add('.gitmodules')
460+
461
462 class GitWorkingTreeFormat(workingtree.WorkingTreeFormat):
463
464
465=== modified file 'breezy/merge.py'
466--- breezy/merge.py 2019-10-13 17:31:55 +0000
467+++ breezy/merge.py 2020-01-19 02:30:26 +0000
468@@ -641,7 +641,7 @@
469 continue
470 sub_merge = Merger(sub_tree.branch, this_tree=sub_tree)
471 sub_merge.merge_type = self.merge_type
472- other_branch = self.other_branch.reference_parent(relpath)
473+ other_branch = self.other_tree.reference_parent(relpath)
474 sub_merge.set_other_revision(other_revision, other_branch)
475 base_tree_path = _mod_tree.find_previous_path(
476 self.this_tree, self.base_tree, relpath)
477
478=== modified file 'breezy/tests/blackbox/test_branch.py'
479--- breezy/tests/blackbox/test_branch.py 2019-10-19 23:18:56 +0000
480+++ breezy/tests/blackbox/test_branch.py 2020-01-19 02:30:26 +0000
481@@ -367,6 +367,7 @@
482 subtree.add(['a'])
483 subtree.commit('add subtree contents')
484 orig.add_reference(subtree)
485+ orig.branch.set_reference_info('subtree', subtree.branch.user_url)
486 orig.commit('add subtree')
487
488 self.run_bzr('branch source target')
489@@ -376,6 +377,20 @@
490 self.assertTreesEqual(orig, target)
491 self.assertTreesEqual(subtree, target_subtree)
492
493+ def test_branch_with_nested_trees_reference_unset(self):
494+ orig = self.make_branch_and_tree('source', format='development-subtree')
495+ subtree = self.make_branch_and_tree('source/subtree')
496+ self.build_tree(['source/subtree/a'])
497+ subtree.add(['a'])
498+ subtree.commit('add subtree contents')
499+ orig.add_reference(subtree)
500+ orig.commit('add subtree')
501+
502+ self.run_bzr('branch source target')
503+
504+ target = WorkingTree.open('target')
505+ self.assertRaises(errors.NotBranchError, WorkingTree.open, 'target/subtree')
506+
507 def test_branch_with_nested_trees_no_recurse(self):
508 orig = self.make_branch_and_tree('source', format='development-subtree')
509 subtree = self.make_branch_and_tree('source/subtree')
510
511=== modified file 'breezy/tests/blackbox/test_reference.py'
512--- breezy/tests/blackbox/test_reference.py 2018-11-16 11:37:47 +0000
513+++ breezy/tests/blackbox/test_reference.py 2020-01-19 02:30:26 +0000
514@@ -30,9 +30,12 @@
515 return controldir.format_registry.make_controldir('development-subtree')
516
517 def test_no_args_lists(self):
518- branch = self.make_branch('branch')
519- branch.set_reference_info('path', 'http://example.org', b'file-id')
520- branch.set_reference_info('lath', 'http://example.org/2', b'file-id2')
521+ tree = self.make_branch_and_tree('branch')
522+ branch = tree.branch
523+ branch.set_reference_info('path', 'http://example.org')
524+ tree.add_reference(self.make_branch_and_tree('branch/path'))
525+ tree.add_reference(self.make_branch_and_tree('branch/lath'))
526+ branch.set_reference_info('lath', 'http://example.org/2')
527 out, err = self.run_bzr('reference', working_dir='branch')
528 lines = out.splitlines()
529 self.assertEqual('lath http://example.org/2', lines[0])
530@@ -40,12 +43,11 @@
531
532 def make_tree_with_reference(self):
533 tree = self.make_branch_and_tree('tree')
534- self.build_tree(['tree/newpath'])
535- tree.add('newpath', b'file-id')
536- tree.branch.set_reference_info(
537- 'newpath', 'http://example.org', b'file-id')
538- tree.branch.set_reference_info('lath', 'http://example.org/2',
539- b'file-id2')
540+ subtree = self.make_branch_and_tree('tree/newpath')
541+ tree.add_reference(subtree)
542+ tree.commit('add reference')
543+ tree.set_reference_info('newpath', 'http://example.org')
544+ tree.set_reference_info('lath', 'http://example.org/2')
545 return tree
546
547 def test_uses_working_tree_location(self):
548@@ -67,17 +69,16 @@
549
550 def test_one_arg_uses_containing_tree(self):
551 tree = self.make_tree_with_reference()
552- out, err = self.run_bzr('reference tree/newpath')
553+ out, err = self.run_bzr('reference -d tree newpath')
554 self.assertEqual('newpath http://example.org\n', out)
555
556 def test_two_args_sets(self):
557 tree = self.make_branch_and_tree('tree')
558 self.build_tree(['tree/file'])
559- tree.add('file', b'file-id')
560- out, err = self.run_bzr('reference tree/file http://example.org')
561- location, file_id = tree.branch.get_reference_info('file')
562+ tree.add('file')
563+ out, err = self.run_bzr('reference -d tree file http://example.org')
564+ location = tree.get_reference_info('file')
565 self.assertEqual('http://example.org', location)
566- self.assertEqual(b'file-id', file_id)
567 self.assertEqual('', out)
568 self.assertEqual('', err)
569
570
571=== modified file 'breezy/tests/per_branch/test_branch.py'
572--- breezy/tests/per_branch/test_branch.py 2020-01-12 15:16:27 +0000
573+++ breezy/tests/per_branch/test_branch.py 2020-01-19 02:30:26 +0000
574@@ -846,195 +846,6 @@
575 self.assertLength(1, reopened.repository._fallback_repositories)
576
577
578-class TestReferenceLocation(per_branch.TestCaseWithBranch):
579-
580- def test_reference_parent(self):
581- tree = self.make_branch_and_tree('tree')
582- subtree = self.make_branch_and_tree('tree/subtree')
583- subtree.commit('a change')
584- try:
585- tree.add_reference(subtree)
586- except errors.UnsupportedOperation:
587- raise tests.TestNotApplicable('Tree cannot hold references.')
588- reference_parent = tree.branch.reference_parent(
589- urlutils.relative_url(
590- urlutils.split_segment_parameters(tree.branch.user_url)[0],
591- urlutils.split_segment_parameters(subtree.branch.user_url)[0]))
592- self.assertEqual(subtree.branch.user_url, reference_parent.user_url)
593-
594- def test_reference_parent_accepts_possible_transports(self):
595- tree = self.make_branch_and_tree('tree')
596- subtree = self.make_branch_and_tree('tree/subtree')
597- subtree.commit('a change')
598- try:
599- tree.add_reference(subtree)
600- except errors.UnsupportedOperation:
601- raise tests.TestNotApplicable('Tree cannot hold references.')
602- reference_parent = tree.branch.reference_parent(
603- urlutils.relative_url(
604- urlutils.split_segment_parameters(tree.branch.user_url)[0],
605- urlutils.split_segment_parameters(subtree.branch.user_url)[0]),
606- possible_transports=[subtree.controldir.root_transport])
607-
608- def test_get_reference_info(self):
609- branch = self.make_branch('branch')
610- try:
611- path, loc = branch.get_reference_info('file')
612- except errors.UnsupportedOperation:
613- raise tests.TestNotApplicable('Branch cannot hold references.')
614- self.assertIs(None, path)
615- self.assertIs(None, loc)
616-
617- def test_set_reference_info(self):
618- branch = self.make_branch('branch')
619- try:
620- branch.set_reference_info('path/to/file', 'path/to/location',
621- b'file-id')
622- except errors.UnsupportedOperation:
623- raise tests.TestNotApplicable('Branch cannot hold references.')
624-
625- def test_set_get_reference_info(self):
626- branch = self.make_branch('branch')
627- try:
628- branch.set_reference_info('path/to/file',
629- 'path/to/location', b'file-id')
630- except errors.UnsupportedOperation:
631- raise tests.TestNotApplicable('Branch cannot hold references.')
632- # Create a new instance to ensure storage is permanent
633- branch = _mod_branch.Branch.open('branch')
634- branch_location, file_id = branch.get_reference_info('path/to/file')
635- self.assertEqual('path/to/location', branch_location)
636-
637- def test_set_null_reference_info(self):
638- branch = self.make_branch('branch')
639- try:
640- branch.set_reference_info('path/to/file',
641- 'path/to/location', b'file-id')
642- except errors.UnsupportedOperation:
643- raise tests.TestNotApplicable('Branch cannot hold references.')
644- branch.set_reference_info('path/to/file', None, None)
645- branch_location, file_id = branch.get_reference_info('path/to/file')
646- self.assertIs(None, file_id)
647- self.assertIs(None, branch_location)
648-
649- def test_set_null_reference_info_when_null(self):
650- branch = self.make_branch('branch')
651- try:
652- branch_location, file_id = branch.get_reference_info('file')
653- except errors.UnsupportedOperation:
654- raise tests.TestNotApplicable('Branch cannot hold references.')
655- self.assertIs(None, file_id)
656- self.assertIs(None, branch_location)
657- branch.set_reference_info('path/to/file', None, None)
658-
659- def make_branch_with_reference(self, location, reference_location,
660- file_id='file-id'):
661- branch = self.make_branch(location)
662- try:
663- branch.set_reference_info('path/to/file',
664- reference_location, file_id)
665- except errors.UnsupportedOperation:
666- raise tests.TestNotApplicable('Branch cannot hold references.')
667- return branch
668-
669- def test_reference_parent_from_reference_info_(self):
670- referenced_branch = self.make_branch('reference_branch')
671- branch = self.make_branch_with_reference('branch',
672- referenced_branch.base)
673- parent = branch.reference_parent('path/to/file')
674- self.assertEqual(parent.base, referenced_branch.base)
675-
676- def test_branch_relative_reference_location(self):
677- branch = self.make_branch('branch')
678- try:
679- branch.set_reference_info('path/to/file',
680- '../reference_branch', b'file-id')
681- except errors.UnsupportedOperation:
682- raise tests.TestNotApplicable('Branch cannot hold references.')
683- referenced_branch = self.make_branch('reference_branch')
684- parent = branch.reference_parent('path/to/file')
685- self.assertEqual(parent.base, referenced_branch.base)
686-
687- def test_sprout_copies_reference_location(self):
688- branch = self.make_branch_with_reference('branch', '../reference')
689- new_branch = branch.controldir.sprout('new-branch').open_branch()
690- self.assertEqual('../reference',
691- new_branch.get_reference_info('path/to/file')[0])
692-
693- def test_clone_copies_reference_location(self):
694- branch = self.make_branch_with_reference('branch', '../reference')
695- new_branch = branch.controldir.clone('new-branch').open_branch()
696- self.assertEqual('../reference',
697- new_branch.get_reference_info('path/to/file')[0])
698-
699- def test_copied_locations_are_rebased(self):
700- branch = self.make_branch_with_reference('branch', 'reference')
701- new_branch = branch.controldir.sprout(
702- 'branch/new-branch').open_branch()
703- self.assertEqual('../reference',
704- new_branch.get_reference_info('path/to/file')[0])
705-
706- def test_update_references_retains_old_references(self):
707- branch = self.make_branch_with_reference('branch', 'reference')
708- new_branch = self.make_branch_with_reference(
709- 'new_branch', 'reference', b'file-id2')
710- new_branch.update_references(branch)
711- self.assertEqual('reference',
712- branch.get_reference_info('path/to/file')[0])
713-
714- def test_update_references_retains_known_references(self):
715- branch = self.make_branch_with_reference('branch', 'reference')
716- new_branch = self.make_branch_with_reference(
717- 'new_branch', 'reference2')
718- new_branch.update_references(branch)
719- self.assertEqual('reference',
720- branch.get_reference_info('path/to/file')[0])
721-
722- def test_update_references_skips_known_references(self):
723- branch = self.make_branch_with_reference('branch', 'reference')
724- new_branch = branch.controldir.sprout(
725- 'branch/new-branch').open_branch()
726- new_branch.set_reference_info('../foo', '../foo', b'file-id')
727- new_branch.update_references(branch)
728- self.assertEqual('reference',
729- branch.get_reference_info('path/to/file')[0])
730-
731- def test_pull_updates_references(self):
732- branch = self.make_branch_with_reference('branch', 'reference')
733- new_branch = branch.controldir.sprout(
734- 'branch/new-branch').open_branch()
735- new_branch.set_reference_info('../foo', '../foo', b'file-id2')
736- branch.pull(new_branch)
737- self.assertEqual('foo',
738- branch.get_reference_info('../foo')[0])
739-
740- def test_push_updates_references(self):
741- branch = self.make_branch_with_reference('branch', 'reference')
742- new_branch = branch.controldir.sprout(
743- 'branch/new-branch').open_branch()
744- new_branch.set_reference_info('../foo', '../foo', b'file-id2')
745- new_branch.push(branch)
746- self.assertEqual('foo',
747- branch.get_reference_info('../foo')[0])
748-
749- def test_merge_updates_references(self):
750- branch = self.make_branch_with_reference('branch', 'reference')
751- tree = self.make_branch_and_tree('tree')
752- tree.commit('foo')
753- branch.pull(tree.branch)
754- checkout = branch.create_checkout('checkout', lightweight=True)
755- checkout.commit('bar')
756- tree.lock_write()
757- self.addCleanup(tree.unlock)
758- merger = merge.Merger.from_revision_ids(tree,
759- branch.last_revision(),
760- other_branch=branch)
761- merger.merge_type = merge.Merge3Merger
762- merger.do_merge()
763- self.assertEqual('../branch/reference',
764- tree.branch.get_reference_info('path/to/file')[0])
765-
766-
767 class TestBranchControlComponent(per_branch.TestCaseWithBranch):
768 """Branch implementations adequately implement ControlComponent."""
769
770
771=== modified file 'breezy/tests/per_workingtree/test_workingtree.py'
772--- breezy/tests/per_workingtree/test_workingtree.py 2019-10-15 19:05:47 +0000
773+++ breezy/tests/per_workingtree/test_workingtree.py 2020-01-19 02:30:26 +0000
774@@ -20,10 +20,11 @@
775 import os
776
777 from ... import (
778- branch,
779+ branch as _mod_branch,
780 config,
781 controldir,
782 errors,
783+ merge,
784 osutils,
785 revision as _mod_revision,
786 tests,
787@@ -79,7 +80,7 @@
788 def test_branch_builder(self):
789 # Just a smoke test that we get a branch at the specified relpath
790 builder = self.make_branch_builder('foobar')
791- br = branch.Branch.open(self.get_url('foobar'))
792+ br = _mod_branch.Branch.open(self.get_url('foobar'))
793
794 def test_list_files(self):
795 tree = self.make_branch_and_tree('.')
796@@ -299,7 +300,7 @@
797 def test_initialize(self):
798 # initialize should create a working tree and branch in an existing dir
799 t = self.make_branch_and_tree('.')
800- b = branch.Branch.open('.')
801+ b = _mod_branch.Branch.open('.')
802 self.assertEqual(t.branch.base, b.base)
803 t2 = WorkingTree.open('.')
804 self.assertEqual(t.basedir, t2.basedir)
805@@ -1329,3 +1330,213 @@
806 self.assertSubset(
807 [self.workingtree_format.supports_store_uncommitted],
808 (True, False))
809+
810+
811+class TestReferenceLocation(TestCaseWithWorkingTree):
812+
813+ def test_reference_parent(self):
814+ tree = self.make_branch_and_tree('tree')
815+ subtree = self.make_branch_and_tree('tree/subtree')
816+ subtree.commit('a change')
817+ try:
818+ tree.add_reference(subtree)
819+ except errors.UnsupportedOperation:
820+ raise tests.TestNotApplicable('Tree cannot hold references.')
821+ if not getattr(tree.branch._format, 'supports_reference_locations', False):
822+ raise tests.TestNotApplicable('Branch cannot hold reference locations.')
823+ tree.commit('Add reference.')
824+ reference_parent = tree.reference_parent(
825+ urlutils.relative_url(
826+ urlutils.strip_segment_parameters(tree.branch.user_url),
827+ urlutils.strip_segment_parameters(subtree.branch.user_url)))
828+ self.assertEqual(subtree.branch.user_url, reference_parent.user_url)
829+
830+ def test_reference_parent_accepts_possible_transports(self):
831+ tree = self.make_branch_and_tree('tree')
832+ subtree = self.make_branch_and_tree('tree/subtree')
833+ subtree.commit('a change')
834+ try:
835+ tree.add_reference(subtree)
836+ except errors.UnsupportedOperation:
837+ raise tests.TestNotApplicable('Tree cannot hold references.')
838+ if not getattr(tree.branch._format, 'supports_reference_locations', False):
839+ raise tests.TestNotApplicable('Branch cannot hold reference locations.')
840+ tree.commit('Add reference')
841+ reference_parent = tree.reference_parent(
842+ urlutils.relative_url(
843+ urlutils.strip_segment_parameters(tree.branch.user_url),
844+ urlutils.strip_segment_parameters(subtree.branch.user_url)),
845+ possible_transports=[subtree.controldir.root_transport])
846+
847+ def test_get_reference_info(self):
848+ tree = self.make_branch_and_tree('branch')
849+ try:
850+ loc = tree.get_reference_info('file')
851+ except errors.UnsupportedOperation:
852+ raise tests.TestNotApplicable('Branch cannot hold references.')
853+ self.assertIs(None, loc)
854+
855+ def test_set_reference_info(self):
856+ tree = self.make_branch_and_tree('branch')
857+ try:
858+ tree.set_reference_info('path/to/file', 'path/to/location')
859+ except errors.UnsupportedOperation:
860+ raise tests.TestNotApplicable('Branch cannot hold references.')
861+
862+ def test_set_get_reference_info(self):
863+ tree = self.make_branch_and_tree('branch')
864+ try:
865+ tree.set_reference_info('path/to/file', 'path/to/location')
866+ except errors.UnsupportedOperation:
867+ raise tests.TestNotApplicable('Branch cannot hold references.')
868+ # Create a new instance to ensure storage is permanent
869+ tree = WorkingTree.open('branch')
870+ branch_location = tree.get_reference_info('path/to/file')
871+ self.assertEqual(
872+ urlutils.local_path_to_url('branch/path/to/location'),
873+ urlutils.join(tree.branch.user_url, branch_location))
874+
875+ def test_set_null_reference_info(self):
876+ tree = self.make_branch_and_tree('branch')
877+ try:
878+ tree.set_reference_info('path/to/file', 'path/to/location')
879+ except errors.UnsupportedOperation:
880+ raise tests.TestNotApplicable('Branch cannot hold references.')
881+ tree.set_reference_info('path/to/file', None)
882+ branch_location = tree.get_reference_info('path/to/file')
883+ self.assertIs(None, branch_location)
884+
885+ def test_set_null_reference_info_when_null(self):
886+ tree = self.make_branch_and_tree('branch')
887+ try:
888+ branch_location = tree.get_reference_info('file')
889+ except errors.UnsupportedOperation:
890+ raise tests.TestNotApplicable('Branch cannot hold references.')
891+ self.assertIs(None, branch_location)
892+ tree.set_reference_info('path/to/file', None)
893+
894+ def make_tree_with_reference(self, location, reference_location):
895+ tree = self.make_branch_and_tree(location)
896+ try:
897+ tree.set_reference_info('path/to/file', reference_location)
898+ except errors.UnsupportedOperation:
899+ raise tests.TestNotApplicable('Branch cannot hold references.')
900+ tree.commit('commit reference')
901+ return tree
902+
903+ def test_reference_parent_from_reference_info_(self):
904+ referenced_branch = self.make_branch('reference_branch')
905+ tree = self.make_tree_with_reference('branch', referenced_branch.base)
906+ parent = tree.reference_parent('path/to/file')
907+ self.assertEqual(parent.base, referenced_branch.base)
908+
909+ def test_branch_relative_reference_location(self):
910+ tree = self.make_branch_and_tree('branch')
911+ try:
912+ tree.set_reference_info('path/to/file', '../reference_branch')
913+ except errors.UnsupportedOperation:
914+ raise tests.TestNotApplicable('Branch cannot hold references.')
915+ tree.commit('add reference')
916+ referenced_branch = self.make_branch('reference_branch')
917+ parent = tree.reference_parent('path/to/file')
918+ self.assertEqual(parent.base, referenced_branch.base)
919+
920+ def test_sprout_copies_reference_location(self):
921+ tree = self.make_tree_with_reference('branch', '../reference')
922+ new_tree = tree.branch.controldir.sprout('new-branch').open_workingtree()
923+ self.assertEqual(
924+ urlutils.local_path_to_url('reference'),
925+ urlutils.join(urlutils.strip_segment_parameters(new_tree.branch.user_url),
926+ new_tree.get_reference_info('path/to/file')))
927+
928+ def test_clone_copies_reference_location(self):
929+ tree = self.make_tree_with_reference('branch', '../reference')
930+ new_tree = tree.controldir.clone('new-branch').open_workingtree()
931+ self.assertEqual(
932+ urlutils.local_path_to_url('reference'),
933+ urlutils.join(urlutils.strip_segment_parameters(new_tree.branch.user_url),
934+ new_tree.get_reference_info('path/to/file')))
935+
936+ def test_copied_locations_are_rebased(self):
937+ tree = self.make_tree_with_reference('branch', 'reference')
938+ new_tree = tree.controldir.sprout(
939+ 'branch/new-branch').open_workingtree()
940+ self.assertEqual(
941+ urlutils.local_path_to_url('branch/reference'),
942+ urlutils.join(urlutils.strip_segment_parameters(new_tree.branch.user_url),
943+ new_tree.get_reference_info('path/to/file')))
944+
945+ def test_update_references_retains_old_references(self):
946+ tree = self.make_tree_with_reference('branch', 'reference')
947+ new_tree = self.make_tree_with_reference(
948+ 'new_branch', 'reference2')
949+ new_tree.branch.update_references(tree.branch)
950+ self.assertEqual(
951+ urlutils.local_path_to_url('branch/reference'),
952+ urlutils.join(
953+ urlutils.strip_segment_parameters(tree.branch.user_url),
954+ tree.get_reference_info('path/to/file')))
955+
956+ def test_update_references_retains_known_references(self):
957+ tree = self.make_tree_with_reference('branch', 'reference')
958+ new_tree = self.make_tree_with_reference(
959+ 'new_branch', 'reference2')
960+ new_tree.branch.update_references(tree.branch)
961+ self.assertEqual(
962+ urlutils.local_path_to_url('branch/reference'),
963+ urlutils.join(
964+ urlutils.strip_segment_parameters(tree.branch.user_url),
965+ tree.get_reference_info('path/to/file')))
966+
967+ def test_update_references_skips_known_references(self):
968+ tree = self.make_tree_with_reference('branch', 'reference')
969+ new_tree = tree.controldir.sprout(
970+ 'branch/new-branch').open_workingtree()
971+ new_tree.set_reference_info('foo', '../foo')
972+ new_tree.branch.update_references(tree.branch)
973+ self.assertEqual(
974+ urlutils.local_path_to_url('branch/reference'),
975+ urlutils.join(
976+ urlutils.strip_segment_parameters(tree.branch.user_url),
977+ tree.get_reference_info('path/to/file')))
978+
979+ def test_pull_updates_references(self):
980+ tree = self.make_tree_with_reference('branch', 'reference')
981+ new_tree = tree.controldir.sprout(
982+ 'branch/new-branch').open_workingtree()
983+ new_tree.set_reference_info('foo', '../foo')
984+ new_tree.commit('set reference')
985+ tree.pull(new_tree.branch)
986+ self.assertEqual(
987+ urlutils.local_path_to_url('branch/foo'),
988+ urlutils.join(tree.branch.user_url, tree.get_reference_info('foo')))
989+
990+ def test_push_updates_references(self):
991+ tree = self.make_tree_with_reference('branch', 'reference')
992+ new_tree = tree.controldir.sprout(
993+ 'branch/new-branch').open_workingtree()
994+ new_tree.set_reference_info('foo', '../foo')
995+ new_tree.commit('add reference')
996+ tree.pull(new_tree.branch)
997+ tree.update()
998+ self.assertEqual(
999+ urlutils.local_path_to_url('branch/foo'),
1000+ urlutils.join(tree.branch.user_url, tree.get_reference_info('foo')))
1001+
1002+ def test_merge_updates_references(self):
1003+ orig_tree = self.make_tree_with_reference('branch', 'reference')
1004+ tree = orig_tree.controldir.sprout('tree').open_workingtree()
1005+ tree.commit('foo')
1006+ orig_tree.pull(tree.branch)
1007+ checkout = orig_tree.branch.create_checkout('checkout', lightweight=True)
1008+ checkout.commit('bar')
1009+ tree.lock_write()
1010+ self.addCleanup(tree.unlock)
1011+ merger = merge.Merger.from_revision_ids(tree,
1012+ orig_tree.branch.last_revision(),
1013+ other_branch=orig_tree.branch)
1014+ merger.merge_type = merge.Merge3Merger
1015+ merger.do_merge()
1016+ self.assertEqual(
1017+ urlutils.local_path_to_url('branch/reference'),
1018+ urlutils.join(urlutils.strip_segment_parameters(tree.branch.user_url), tree.get_reference_info('path/to/file')))
1019
1020=== modified file 'breezy/tests/test_branch.py'
1021--- breezy/tests/test_branch.py 2019-06-16 01:03:51 +0000
1022+++ breezy/tests/test_branch.py 2020-01-19 02:30:26 +0000
1023@@ -327,7 +327,7 @@
1024 self.assertPathDoesNotExist('a/.bzr/branch/bound')
1025 self.assertEqual('ftp://example.com', branch.get_bound_location())
1026
1027- def do_checkout_test(self, lightweight=False):
1028+ def do_checkout_test(self, lightweight):
1029 tree = self.make_branch_and_tree('source',
1030 format=self.get_format_name_subtree())
1031 subtree = self.make_branch_and_tree('source/subtree',
1032@@ -339,7 +339,9 @@
1033 subsubtree.add('file')
1034 subtree.add('file')
1035 subtree.add_reference(subsubtree)
1036+ subtree.set_reference_info('subsubtree', subsubtree.branch.user_url)
1037 tree.add_reference(subtree)
1038+ tree.set_reference_info('subtree', subtree.branch.user_url)
1039 tree.commit('a revision')
1040 subtree.commit('a subtree file')
1041 subsubtree.commit('a subsubtree file')
1042@@ -355,7 +357,7 @@
1043 self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
1044
1045 def test_checkout_with_references(self):
1046- self.do_checkout_test()
1047+ self.do_checkout_test(lightweight=False)
1048
1049 def test_light_checkout_with_references(self):
1050 self.do_checkout_test(lightweight=True)
1051
1052=== modified file 'breezy/tests/test_bzrdir.py'
1053--- breezy/tests/test_bzrdir.py 2020-01-11 02:39:17 +0000
1054+++ breezy/tests/test_bzrdir.py 2020-01-19 02:30:26 +0000
1055@@ -842,12 +842,11 @@
1056 self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport, t)
1057
1058 def test_sprout_recursive(self):
1059- tree = self.make_branch_and_tree('tree1',
1060- format='development-subtree')
1061- sub_tree = self.make_branch_and_tree('tree1/subtree',
1062- format='development-subtree')
1063+ tree = self.make_branch_and_tree('tree1')
1064+ sub_tree = self.make_branch_and_tree('tree1/subtree')
1065 sub_tree.set_root_id(b'subtree-root')
1066 tree.add_reference(sub_tree)
1067+ tree.set_reference_info('subtree', sub_tree.branch.user_url)
1068 self.build_tree(['tree1/subtree/file'])
1069 sub_tree.add('file')
1070 tree.commit('Initial commit')
1071@@ -872,6 +871,7 @@
1072 sub_tree = self.make_branch_and_tree('tree1/subtree',
1073 format='development-subtree')
1074 tree.add_reference(sub_tree)
1075+ tree.set_reference_info('subtree', sub_tree.branch.user_url)
1076 self.build_tree(['tree1/subtree/file'])
1077 sub_tree.add('file')
1078 tree.commit('Initial commit')
1079
1080=== modified file 'breezy/tree.py'
1081--- breezy/tree.py 2020-01-10 01:40:18 +0000
1082+++ breezy/tree.py 2020-01-19 02:30:26 +0000
1083@@ -428,7 +428,7 @@
1084 """
1085 raise NotImplementedError(self.path_content_summary)
1086
1087- def get_reference_revision(self, path):
1088+ def get_reference_revision(self, path, branch=None):
1089 raise NotImplementedError("Tree subclass %s must implement "
1090 "get_reference_revision"
1091 % self.__class__.__name__)
1092
1093=== modified file 'breezy/workingtree.py'
1094--- breezy/workingtree.py 2020-01-11 17:50:28 +0000
1095+++ breezy/workingtree.py 2020-01-19 02:30:26 +0000
1096@@ -1325,6 +1325,15 @@
1097 with self.lock_read():
1098 return next(self.get_canonical_paths([path]))
1099
1100+ def reference_parent(self, path, branch=None, possible_transports=None):
1101+ raise errors.UnsupportedOperation(self.reference_parent, self)
1102+
1103+ def get_reference_info(self, path, branch=None):
1104+ raise errors.UnsupportedOperation(self.get_reference_info, self)
1105+
1106+ def set_reference_info(self, tree_path, branch_location):
1107+ raise errors.UnsupportedOperation(self.set_reference_info, self)
1108+
1109
1110 class WorkingTreeFormatRegistry(ControlComponentFormatRegistry):
1111 """Registry for working tree formats."""

Subscribers

People subscribed via source and target branches