Merge lp:~jelmer/brz/transform into lp:brz/3.1

Proposed by Jelmer Vernooij on 2020-07-05
Status: Merged
Approved by: Jelmer Vernooij on 2020-07-05
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/transform
Merge into: lp:brz/3.1
Diff against target: 1696 lines (+770/-696)
8 files modified
breezy/git/tree.py (+8/-0)
breezy/merge.py (+2/-8)
breezy/tests/per_tree/__init__.py (+1/-0)
breezy/tests/per_tree/test_transform.py (+719/-0)
breezy/tests/per_workingtree/test_transform.py (+14/-6)
breezy/tests/test_transform.py (+0/-665)
breezy/tests/test_tree.py (+7/-0)
breezy/transform.py (+19/-17)
To merge this branch: bzr merge lp:~jelmer/brz/transform
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve on 2020-07-05
Review via email: mp+386857@code.launchpad.net

Commit message

More work towards supporting file-id-independent Transform.

Description of the change

More work towards supporting file-id-independent Transform.

To post a comment you must log in.
Jelmer Vernooij (jelmer) :
review: Approve
lp:~jelmer/brz/transform updated on 2020-07-05
7576. By Jelmer Vernooij on 2020-07-05

More work towards supporting file-id-independent Transform.

Merged from https://code.launchpad.net/~jelmer/brz/transform/+merge/386857

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/git/tree.py'
2--- breezy/git/tree.py 2020-07-04 00:38:37 +0000
3+++ breezy/git/tree.py 2020-07-05 00:45:38 +0000
4@@ -724,6 +724,10 @@
5 file_id, mode_kind(mode)))
6 yield (path_decoded, parent_id), children
7
8+ def preview_transform(self, pb=None):
9+ from ..transform import TransformPreview
10+ return TransformPreview(self, pb=pb)
11+
12
13 def tree_delta_from_git_changes(changes, mappings,
14 specific_files=None,
15@@ -1634,6 +1638,10 @@
16 from ..transform import TreeTransform
17 return TreeTransform(self, pb=pb)
18
19+ def preview_transform(self, pb=None):
20+ from ..transform import TransformPreview
21+ return TransformPreview(self, pb=pb)
22+
23
24
25 class InterToIndexGitTree(InterGitTrees):
26
27=== modified file 'breezy/merge.py'
28--- breezy/merge.py 2020-07-04 14:58:52 +0000
29+++ breezy/merge.py 2020-07-05 00:45:38 +0000
30@@ -1465,14 +1465,8 @@
31 data.append(('BASE', self.base_tree, base_path, base_lines))
32
33 # We need to use the actual path in the working tree of the file here,
34- # ignoring the conflict suffixes
35- wt = self.this_tree
36- if wt.supports_content_filtering():
37- try:
38- filter_tree_path = wt.id2path(file_id)
39- except errors.NoSuchId:
40- # file has been deleted
41- filter_tree_path = None
42+ if self.this_tree.supports_content_filtering():
43+ filter_tree_path = this_path
44 else:
45 # Skip the id2path lookup for older formats
46 filter_tree_path = None
47
48=== modified file 'breezy/tests/per_tree/__init__.py'
49--- breezy/tests/per_tree/__init__.py 2020-07-04 01:15:59 +0000
50+++ breezy/tests/per_tree/__init__.py 2020-07-05 00:45:38 +0000
51@@ -354,6 +354,7 @@
52 'revision_tree',
53 'symlinks',
54 'test_trees',
55+ 'transform',
56 'tree',
57 'walkdirs',
58 ]
59
60=== added file 'breezy/tests/per_tree/test_transform.py'
61--- breezy/tests/per_tree/test_transform.py 1970-01-01 00:00:00 +0000
62+++ breezy/tests/per_tree/test_transform.py 2020-07-05 00:45:38 +0000
63@@ -0,0 +1,719 @@
64+# Copyright (C) 2006-2012, 2016 Canonical Ltd
65+#
66+# This program is free software; you can redistribute it and/or modify
67+# it under the terms of the GNU General Public License as published by
68+# the Free Software Foundation; either version 2 of the License, or
69+# (at your option) any later version.
70+#
71+# This program is distributed in the hope that it will be useful,
72+# but WITHOUT ANY WARRANTY; without even the implied warranty of
73+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74+# GNU General Public License for more details.
75+#
76+# You should have received a copy of the GNU General Public License
77+# along with this program; if not, write to the Free Software
78+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
79+
80+from io import BytesIO
81+import os
82+
83+from ... import (
84+ revision as _mod_revision,
85+ trace,
86+ )
87+from ...diff import show_diff_trees
88+from ...merge import Merger, Merge3Merger
89+from ...transform import (
90+ ROOT_PARENT,
91+ resolve_conflicts,
92+ )
93+from ...tree import (
94+ find_previous_path,
95+ )
96+
97+
98+from breezy.tests.per_tree import TestCaseWithTree
99+
100+
101+from ..features import (
102+ HardlinkFeature,
103+ SymlinkFeature,
104+ UnicodeFilenameFeature,
105+ )
106+
107+
108+
109+A_ENTRY = (b'a-id', ('a', 'a'), True, (True, True),
110+ (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
111+ (False, False), False)
112+ROOT_ENTRY = (b'TREE_ROOT', ('', ''), False, (True, True), (None, None),
113+ ('', ''), ('directory', 'directory'), (False, False), False)
114+
115+
116+class TestTransformPreview(TestCaseWithTree):
117+
118+ def setUp(self):
119+ super(TestTransformPreview, self).setUp()
120+ if not self.workingtree_format.supports_setting_file_ids:
121+ self.skipTest('test not compatible with non-file-id trees yet')
122+
123+ def create_tree(self):
124+ tree = self.make_branch_and_tree('.')
125+ self.build_tree_contents([('a', b'content 1')])
126+ tree.set_root_id(b'TREE_ROOT')
127+ tree.add('a', b'a-id')
128+ revid1 = tree.commit('rev1')
129+ return tree.branch.repository.revision_tree(revid1)
130+
131+ def get_empty_preview(self):
132+ repository = self.make_repository('repo')
133+ tree = repository.revision_tree(_mod_revision.NULL_REVISION)
134+ preview = tree.preview_transform()
135+ self.addCleanup(preview.finalize)
136+ return preview
137+
138+ def test_transform_preview(self):
139+ revision_tree = self.create_tree()
140+ preview = revision_tree.preview_transform()
141+ self.addCleanup(preview.finalize)
142+
143+ def test_transform_preview_tree(self):
144+ revision_tree = self.create_tree()
145+ preview = revision_tree.preview_transform()
146+ self.addCleanup(preview.finalize)
147+ preview.get_preview_tree()
148+
149+ def test_transform_new_file(self):
150+ revision_tree = self.create_tree()
151+ preview = revision_tree.preview_transform()
152+ self.addCleanup(preview.finalize)
153+ preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
154+ preview_tree = preview.get_preview_tree()
155+ self.assertEqual(preview_tree.kind('file2'), 'file')
156+ with preview_tree.get_file('file2') as f:
157+ self.assertEqual(f.read(), b'content B\n')
158+
159+ def test_diff_preview_tree(self):
160+ revision_tree = self.create_tree()
161+ preview = revision_tree.preview_transform()
162+ self.addCleanup(preview.finalize)
163+ preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
164+ preview_tree = preview.get_preview_tree()
165+ out = BytesIO()
166+ show_diff_trees(revision_tree, preview_tree, out)
167+ lines = out.getvalue().splitlines()
168+ self.assertEqual(lines[0], b"=== added file 'file2'")
169+ # 3 lines of diff administrivia
170+ self.assertEqual(lines[4], b"+content B")
171+
172+ def test_unsupported_symlink_diff(self):
173+ self.requireFeature(SymlinkFeature)
174+ tree = self.make_branch_and_tree('.')
175+ self.build_tree_contents([('a', 'content 1')])
176+ tree.set_root_id(b'TREE_ROOT')
177+ tree.add('a')
178+ os.symlink('a', 'foo')
179+ tree.add('foo', b'foo-id')
180+ revid1 = tree.commit('rev1')
181+ revision_tree = tree.branch.repository.revision_tree(revid1)
182+ preview = revision_tree.preview_transform()
183+ self.addCleanup(preview.finalize)
184+ preview.delete_versioned(preview.trans_id_tree_path('foo'))
185+ preview_tree = preview.get_preview_tree()
186+ out = BytesIO()
187+ log = BytesIO()
188+ trace.push_log_file(log)
189+ os_symlink = getattr(os, 'symlink', None)
190+ os.symlink = None
191+ try:
192+ show_diff_trees(revision_tree, preview_tree, out)
193+ lines = out.getvalue().splitlines()
194+ finally:
195+ os.symlink = os_symlink
196+ self.assertContainsRe(
197+ log.getvalue(),
198+ b'Ignoring "foo" as symlinks are not supported on this filesystem')
199+
200+ def test_transform_conflicts(self):
201+ revision_tree = self.create_tree()
202+ preview = revision_tree.preview_transform()
203+ self.addCleanup(preview.finalize)
204+ preview.new_file('a', preview.root, [b'content 2'])
205+ resolve_conflicts(preview)
206+ trans_id = preview.trans_id_file_id(b'a-id')
207+ self.assertEqual('a.moved', preview.final_name(trans_id))
208+
209+ def get_tree_and_preview_tree(self):
210+ revision_tree = self.create_tree()
211+ preview = revision_tree.preview_transform()
212+ self.addCleanup(preview.finalize)
213+ a_trans_id = preview.trans_id_file_id(b'a-id')
214+ preview.delete_contents(a_trans_id)
215+ preview.create_file([b'b content'], a_trans_id)
216+ preview_tree = preview.get_preview_tree()
217+ return revision_tree, preview_tree
218+
219+ def test_iter_changes(self):
220+ revision_tree, preview_tree = self.get_tree_and_preview_tree()
221+ root = revision_tree.path2id('')
222+ self.assertEqual([(b'a-id', ('a', 'a'), True, (True, True),
223+ (root, root), ('a', 'a'), ('file', 'file'),
224+ (False, False), False)],
225+ list(preview_tree.iter_changes(revision_tree)))
226+
227+ def test_include_unchanged_succeeds(self):
228+ revision_tree, preview_tree = self.get_tree_and_preview_tree()
229+ changes = preview_tree.iter_changes(revision_tree,
230+ include_unchanged=True)
231+ self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
232+
233+ def test_specific_files(self):
234+ revision_tree, preview_tree = self.get_tree_and_preview_tree()
235+ changes = preview_tree.iter_changes(revision_tree,
236+ specific_files=[''])
237+ self.assertEqual([A_ENTRY], list(changes))
238+
239+ def test_want_unversioned(self):
240+ revision_tree, preview_tree = self.get_tree_and_preview_tree()
241+ changes = preview_tree.iter_changes(revision_tree,
242+ want_unversioned=True)
243+ self.assertEqual([A_ENTRY], list(changes))
244+
245+ def test_ignore_extra_trees_no_specific_files(self):
246+ # extra_trees is harmless without specific_files, so we'll silently
247+ # accept it, even though we won't use it.
248+ revision_tree, preview_tree = self.get_tree_and_preview_tree()
249+ preview_tree.iter_changes(revision_tree, extra_trees=[preview_tree])
250+
251+ def test_ignore_require_versioned_no_specific_files(self):
252+ # require_versioned is meaningless without specific_files.
253+ revision_tree, preview_tree = self.get_tree_and_preview_tree()
254+ preview_tree.iter_changes(revision_tree, require_versioned=False)
255+
256+ def test_ignore_pb(self):
257+ # pb could be supported, but TT.iter_changes doesn't support it.
258+ revision_tree, preview_tree = self.get_tree_and_preview_tree()
259+ preview_tree.iter_changes(revision_tree)
260+
261+ def test_kind(self):
262+ revision_tree = self.create_tree()
263+ preview = revision_tree.preview_transform()
264+ self.addCleanup(preview.finalize)
265+ preview.new_file('file', preview.root, [b'contents'], b'file-id')
266+ preview.new_directory('directory', preview.root, b'dir-id')
267+ preview_tree = preview.get_preview_tree()
268+ self.assertEqual('file', preview_tree.kind('file'))
269+ self.assertEqual('directory', preview_tree.kind('directory'))
270+
271+ def test_get_file_mtime(self):
272+ preview = self.get_empty_preview()
273+ file_trans_id = preview.new_file('file', preview.root, [b'contents'],
274+ b'file-id')
275+ limbo_path = preview._limbo_name(file_trans_id)
276+ preview_tree = preview.get_preview_tree()
277+ self.assertEqual(os.stat(limbo_path).st_mtime,
278+ preview_tree.get_file_mtime('file'))
279+
280+ def test_get_file_mtime_renamed(self):
281+ work_tree = self.make_branch_and_tree('tree')
282+ self.build_tree(['tree/file'])
283+ work_tree.add('file', b'file-id')
284+ preview = work_tree.preview_transform()
285+ self.addCleanup(preview.finalize)
286+ file_trans_id = preview.trans_id_tree_path('file')
287+ preview.adjust_path('renamed', preview.root, file_trans_id)
288+ preview_tree = preview.get_preview_tree()
289+ preview_mtime = preview_tree.get_file_mtime('renamed')
290+ work_mtime = work_tree.get_file_mtime('file')
291+
292+ def test_get_file_size(self):
293+ work_tree = self.make_branch_and_tree('tree')
294+ self.build_tree_contents([('tree/old', b'old')])
295+ work_tree.add('old', b'old-id')
296+ preview = work_tree.preview_transform()
297+ self.addCleanup(preview.finalize)
298+ preview.new_file('name', preview.root, [b'contents'], b'new-id',
299+ 'executable')
300+ tree = preview.get_preview_tree()
301+ self.assertEqual(len('old'), tree.get_file_size('old'))
302+ self.assertEqual(len('contents'), tree.get_file_size('name'))
303+
304+ def test_get_file(self):
305+ preview = self.get_empty_preview()
306+ preview.new_file('file', preview.root, [b'contents'], b'file-id')
307+ preview_tree = preview.get_preview_tree()
308+ with preview_tree.get_file('file') as tree_file:
309+ self.assertEqual(b'contents', tree_file.read())
310+
311+ def test_get_symlink_target(self):
312+ self.requireFeature(SymlinkFeature)
313+ preview = self.get_empty_preview()
314+ preview.new_symlink('symlink', preview.root, 'target', b'symlink-id')
315+ preview_tree = preview.get_preview_tree()
316+ self.assertEqual('target',
317+ preview_tree.get_symlink_target('symlink'))
318+
319+ def test_all_file_ids(self):
320+ tree = self.make_branch_and_tree('tree')
321+ self.build_tree(['tree/a', 'tree/b', 'tree/c'])
322+ tree.add(['a', 'b', 'c'], [b'a-id', b'b-id', b'c-id'])
323+ preview = tree.preview_transform()
324+ self.addCleanup(preview.finalize)
325+ preview.unversion_file(preview.trans_id_file_id(b'b-id'))
326+ c_trans_id = preview.trans_id_file_id(b'c-id')
327+ preview.unversion_file(c_trans_id)
328+ preview.version_file(c_trans_id, file_id=b'c-id')
329+ preview_tree = preview.get_preview_tree()
330+ self.assertEqual({b'a-id', b'c-id', tree.path2id('')},
331+ preview_tree.all_file_ids())
332+
333+ def test_path2id_deleted_unchanged(self):
334+ tree = self.make_branch_and_tree('tree')
335+ self.build_tree(['tree/unchanged', 'tree/deleted'])
336+ tree.add(['unchanged', 'deleted'])
337+ preview = tree.preview_transform()
338+ self.addCleanup(preview.finalize)
339+ preview.unversion_file(preview.trans_id_tree_path('deleted'))
340+ preview_tree = preview.get_preview_tree()
341+ self.assertEqual(
342+ 'unchanged',
343+ find_previous_path(preview_tree, tree, 'unchanged'))
344+ self.assertFalse(preview_tree.is_versioned('deleted'))
345+
346+ def test_path2id_created(self):
347+ tree = self.make_branch_and_tree('tree')
348+ self.build_tree(['tree/unchanged'])
349+ tree.add(['unchanged'])
350+ preview = tree.preview_transform()
351+ self.addCleanup(preview.finalize)
352+ preview.new_file('new', preview.trans_id_tree_path('unchanged'),
353+ [b'contents'], b'new-id')
354+ preview_tree = preview.get_preview_tree()
355+ self.assertEqual(b'new-id', preview_tree.path2id('unchanged/new'))
356+
357+ def test_path2id_moved(self):
358+ tree = self.make_branch_and_tree('tree')
359+ self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
360+ tree.add(['old_parent', 'old_parent/child'],
361+ [b'old_parent-id', b'child-id'])
362+ preview = tree.preview_transform()
363+ self.addCleanup(preview.finalize)
364+ new_parent = preview.new_directory('new_parent', preview.root,
365+ b'new_parent-id')
366+ preview.adjust_path('child', new_parent,
367+ preview.trans_id_file_id(b'child-id'))
368+ preview_tree = preview.get_preview_tree()
369+ self.assertFalse(preview_tree.is_versioned('old_parent/child'))
370+ self.assertEqual(b'child-id', preview_tree.path2id('new_parent/child'))
371+
372+ def test_path2id_renamed_parent(self):
373+ tree = self.make_branch_and_tree('tree')
374+ self.build_tree(['tree/old_name/', 'tree/old_name/child'])
375+ tree.add(['old_name', 'old_name/child'],
376+ [b'parent-id', b'child-id'])
377+ preview = tree.preview_transform()
378+ self.addCleanup(preview.finalize)
379+ preview.adjust_path('new_name', preview.root,
380+ preview.trans_id_file_id(b'parent-id'))
381+ preview_tree = preview.get_preview_tree()
382+ self.assertFalse(preview_tree.is_versioned('old_name/child'))
383+ self.assertEqual(b'child-id', preview_tree.path2id('new_name/child'))
384+
385+ def assertMatchingIterEntries(self, tt, specific_files=None):
386+ preview_tree = tt.get_preview_tree()
387+ preview_result = list(preview_tree.iter_entries_by_dir(
388+ specific_files=specific_files))
389+ tree = tt._tree
390+ tt.apply()
391+ actual_result = list(tree.iter_entries_by_dir(
392+ specific_files=specific_files))
393+ self.assertEqual(actual_result, preview_result)
394+
395+ def test_iter_entries_by_dir_new(self):
396+ tree = self.make_branch_and_tree('tree')
397+ tt = tree.transform()
398+ tt.new_file('new', tt.root, [b'contents'], b'new-id')
399+ self.assertMatchingIterEntries(tt)
400+
401+ def test_iter_entries_by_dir_deleted(self):
402+ tree = self.make_branch_and_tree('tree')
403+ self.build_tree(['tree/deleted'])
404+ tree.add('deleted', b'deleted-id')
405+ tt = tree.transform()
406+ tt.delete_contents(tt.trans_id_file_id(b'deleted-id'))
407+ self.assertMatchingIterEntries(tt)
408+
409+ def test_iter_entries_by_dir_unversioned(self):
410+ tree = self.make_branch_and_tree('tree')
411+ self.build_tree(['tree/removed'])
412+ tree.add('removed', b'removed-id')
413+ tt = tree.transform()
414+ tt.unversion_file(tt.trans_id_file_id(b'removed-id'))
415+ self.assertMatchingIterEntries(tt)
416+
417+ def test_iter_entries_by_dir_moved(self):
418+ tree = self.make_branch_and_tree('tree')
419+ self.build_tree(['tree/moved', 'tree/new_parent/'])
420+ tree.add(['moved', 'new_parent'], [b'moved-id', b'new_parent-id'])
421+ tt = tree.transform()
422+ tt.adjust_path('moved', tt.trans_id_file_id(b'new_parent-id'),
423+ tt.trans_id_file_id(b'moved-id'))
424+ self.assertMatchingIterEntries(tt)
425+
426+ def test_iter_entries_by_dir_specific_files(self):
427+ tree = self.make_branch_and_tree('tree')
428+ tree.set_root_id(b'tree-root-id')
429+ self.build_tree(['tree/parent/', 'tree/parent/child'])
430+ tree.add(['parent', 'parent/child'], [b'parent-id', b'child-id'])
431+ tt = tree.transform()
432+ self.assertMatchingIterEntries(tt, ['', 'parent/child'])
433+
434+ def test_symlink_content_summary(self):
435+ self.requireFeature(SymlinkFeature)
436+ preview = self.get_empty_preview()
437+ preview.new_symlink('path', preview.root, 'target', b'path-id')
438+ summary = preview.get_preview_tree().path_content_summary('path')
439+ self.assertEqual(('symlink', None, None, 'target'), summary)
440+
441+ def test_missing_content_summary(self):
442+ preview = self.get_empty_preview()
443+ summary = preview.get_preview_tree().path_content_summary('path')
444+ self.assertEqual(('missing', None, None, None), summary)
445+
446+ def test_deleted_content_summary(self):
447+ tree = self.make_branch_and_tree('tree')
448+ self.build_tree(['tree/path/'])
449+ tree.add('path')
450+ preview = tree.preview_transform()
451+ self.addCleanup(preview.finalize)
452+ preview.delete_contents(preview.trans_id_tree_path('path'))
453+ summary = preview.get_preview_tree().path_content_summary('path')
454+ self.assertEqual(('missing', None, None, None), summary)
455+
456+ def test_file_content_summary_executable(self):
457+ preview = self.get_empty_preview()
458+ path_id = preview.new_file('path', preview.root, [
459+ b'contents'], b'path-id')
460+ preview.set_executability(True, path_id)
461+ summary = preview.get_preview_tree().path_content_summary('path')
462+ self.assertEqual(4, len(summary))
463+ self.assertEqual('file', summary[0])
464+ # size must be known
465+ self.assertEqual(len('contents'), summary[1])
466+ # executable
467+ self.assertEqual(True, summary[2])
468+ # will not have hash (not cheap to determine)
469+ self.assertIs(None, summary[3])
470+
471+ def test_change_executability(self):
472+ tree = self.make_branch_and_tree('tree')
473+ self.build_tree(['tree/path'])
474+ tree.add('path')
475+ preview = tree.preview_transform()
476+ self.addCleanup(preview.finalize)
477+ path_id = preview.trans_id_tree_path('path')
478+ preview.set_executability(True, path_id)
479+ summary = preview.get_preview_tree().path_content_summary('path')
480+ self.assertEqual(True, summary[2])
481+
482+ def test_file_content_summary_non_exec(self):
483+ preview = self.get_empty_preview()
484+ preview.new_file('path', preview.root, [b'contents'], b'path-id')
485+ summary = preview.get_preview_tree().path_content_summary('path')
486+ self.assertEqual(4, len(summary))
487+ self.assertEqual('file', summary[0])
488+ # size must be known
489+ self.assertEqual(len('contents'), summary[1])
490+ # not executable
491+ self.assertEqual(False, summary[2])
492+ # will not have hash (not cheap to determine)
493+ self.assertIs(None, summary[3])
494+
495+ def test_dir_content_summary(self):
496+ preview = self.get_empty_preview()
497+ preview.new_directory('path', preview.root, b'path-id')
498+ summary = preview.get_preview_tree().path_content_summary('path')
499+ self.assertEqual(('directory', None, None, None), summary)
500+
501+ def test_tree_content_summary(self):
502+ preview = self.get_empty_preview()
503+ path = preview.new_directory('path', preview.root, b'path-id')
504+ preview.set_tree_reference(b'rev-1', path)
505+ summary = preview.get_preview_tree().path_content_summary('path')
506+ self.assertEqual(4, len(summary))
507+ self.assertEqual('tree-reference', summary[0])
508+
509+ def test_annotate(self):
510+ tree = self.make_branch_and_tree('tree')
511+ self.build_tree_contents([('tree/file', b'a\n')])
512+ tree.add('file', b'file-id')
513+ revid1 = tree.commit('a')
514+ self.build_tree_contents([('tree/file', b'a\nb\n')])
515+ preview = tree.preview_transform()
516+ self.addCleanup(preview.finalize)
517+ file_trans_id = preview.trans_id_file_id(b'file-id')
518+ preview.delete_contents(file_trans_id)
519+ preview.create_file([b'a\nb\nc\n'], file_trans_id)
520+ preview_tree = preview.get_preview_tree()
521+ expected = [
522+ (revid1, b'a\n'),
523+ (b'me:', b'b\n'),
524+ (b'me:', b'c\n'),
525+ ]
526+ annotation = preview_tree.annotate_iter(
527+ 'file', default_revision=b'me:')
528+ self.assertEqual(expected, annotation)
529+
530+ def test_annotate_missing(self):
531+ preview = self.get_empty_preview()
532+ preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
533+ preview_tree = preview.get_preview_tree()
534+ expected = [
535+ (b'me:', b'a\n'),
536+ (b'me:', b'b\n'),
537+ (b'me:', b'c\n'),
538+ ]
539+ annotation = preview_tree.annotate_iter(
540+ 'file', default_revision=b'me:')
541+ self.assertEqual(expected, annotation)
542+
543+ def test_annotate_rename(self):
544+ tree = self.make_branch_and_tree('tree')
545+ self.build_tree_contents([('tree/file', b'a\n')])
546+ tree.add('file')
547+ revid1 = tree.commit('a')
548+ preview = tree.preview_transform()
549+ self.addCleanup(preview.finalize)
550+ file_trans_id = preview.trans_id_tree_path('file')
551+ preview.adjust_path('newname', preview.root, file_trans_id)
552+ preview_tree = preview.get_preview_tree()
553+ expected = [
554+ (revid1, b'a\n'),
555+ ]
556+ annotation = preview_tree.annotate_iter(
557+ 'file', default_revision=b'me:')
558+ self.assertEqual(expected, annotation)
559+
560+ def test_annotate_deleted(self):
561+ tree = self.make_branch_and_tree('tree')
562+ self.build_tree_contents([('tree/file', b'a\n')])
563+ tree.add('file')
564+ tree.commit('a')
565+ self.build_tree_contents([('tree/file', b'a\nb\n')])
566+ preview = tree.preview_transform()
567+ self.addCleanup(preview.finalize)
568+ file_trans_id = preview.trans_id_tree_path('file')
569+ preview.delete_contents(file_trans_id)
570+ preview_tree = preview.get_preview_tree()
571+ annotation = preview_tree.annotate_iter(
572+ 'file', default_revision=b'me:')
573+ self.assertIs(None, annotation)
574+
575+ def test_stored_kind(self):
576+ preview = self.get_empty_preview()
577+ preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
578+ preview_tree = preview.get_preview_tree()
579+ self.assertEqual('file', preview_tree.stored_kind('file'))
580+
581+ def test_is_executable(self):
582+ preview = self.get_empty_preview()
583+ preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
584+ preview.set_executability(True, preview.trans_id_file_id(b'file-id'))
585+ preview_tree = preview.get_preview_tree()
586+ self.assertEqual(True, preview_tree.is_executable('file'))
587+
588+ def test_get_set_parent_ids(self):
589+ revision_tree, preview_tree = self.get_tree_and_preview_tree()
590+ self.assertEqual([], preview_tree.get_parent_ids())
591+ preview_tree.set_parent_ids([revision_tree.get_revision_id()])
592+ self.assertEqual(
593+ [revision_tree.get_revision_id()],
594+ preview_tree.get_parent_ids())
595+
596+ def test_plan_file_merge(self):
597+ work_a = self.make_branch_and_tree('wta')
598+ self.build_tree_contents([('wta/file', b'a\nb\nc\nd\n')])
599+ work_a.add('file')
600+ base_id = work_a.commit('base version')
601+ tree_b = work_a.controldir.sprout('wtb').open_workingtree()
602+ preview = work_a.preview_transform()
603+ self.addCleanup(preview.finalize)
604+ trans_id = preview.trans_id_tree_path('file')
605+ preview.delete_contents(trans_id)
606+ preview.create_file([b'b\nc\nd\ne\n'], trans_id)
607+ self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
608+ tree_a = preview.get_preview_tree()
609+ tree_a.set_parent_ids([base_id])
610+ self.addCleanup(tree_b.lock_read().unlock)
611+ self.assertEqual([
612+ ('killed-a', b'a\n'),
613+ ('killed-b', b'b\n'),
614+ ('unchanged', b'c\n'),
615+ ('unchanged', b'd\n'),
616+ ('new-a', b'e\n'),
617+ ('new-b', b'f\n'),
618+ ], list(tree_a.plan_file_merge('file', tree_b)))
619+
620+ def test_plan_file_merge_revision_tree(self):
621+ work_a = self.make_branch_and_tree('wta')
622+ self.build_tree_contents([('wta/file', b'a\nb\nc\nd\n')])
623+ work_a.add('file')
624+ base_id = work_a.commit('base version')
625+ tree_b = work_a.controldir.sprout('wtb').open_workingtree()
626+ preview = work_a.basis_tree().preview_transform()
627+ self.addCleanup(preview.finalize)
628+ trans_id = preview.trans_id_tree_path('file')
629+ preview.delete_contents(trans_id)
630+ preview.create_file([b'b\nc\nd\ne\n'], trans_id)
631+ self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
632+ tree_a = preview.get_preview_tree()
633+ tree_a.set_parent_ids([base_id])
634+ self.addCleanup(tree_b.lock_read().unlock)
635+ self.assertEqual([
636+ ('killed-a', b'a\n'),
637+ ('killed-b', b'b\n'),
638+ ('unchanged', b'c\n'),
639+ ('unchanged', b'd\n'),
640+ ('new-a', b'e\n'),
641+ ('new-b', b'f\n'),
642+ ], list(tree_a.plan_file_merge('file', tree_b)))
643+
644+ def test_walkdirs(self):
645+ preview = self.get_empty_preview()
646+ preview.new_directory('', ROOT_PARENT, b'tree-root')
647+ # FIXME: new_directory should mark root.
648+ preview.fixup_new_roots()
649+ preview_tree = preview.get_preview_tree()
650+ preview.new_file('a', preview.root, [b'contents'], b'a-id')
651+ expected = [(('', b'tree-root'),
652+ [('a', 'a', 'file', None, b'a-id', 'file')])]
653+ self.assertEqual(expected, list(preview_tree.walkdirs()))
654+
655+ def test_extras(self):
656+ work_tree = self.make_branch_and_tree('tree')
657+ self.build_tree(['tree/removed-file', 'tree/existing-file',
658+ 'tree/not-removed-file'])
659+ work_tree.add(['removed-file', 'not-removed-file'])
660+ preview = work_tree.preview_transform()
661+ self.addCleanup(preview.finalize)
662+ preview.new_file('new-file', preview.root, [b'contents'])
663+ preview.new_file('new-versioned-file', preview.root, [b'contents'],
664+ b'new-versioned-id')
665+ tree = preview.get_preview_tree()
666+ preview.unversion_file(preview.trans_id_tree_path('removed-file'))
667+ self.assertEqual({'new-file', 'removed-file', 'existing-file'},
668+ set(tree.extras()))
669+
670+ def test_merge_into_preview(self):
671+ work_tree = self.make_branch_and_tree('tree')
672+ self.build_tree_contents([('tree/file', b'b\n')])
673+ work_tree.add('file')
674+ work_tree.commit('first commit')
675+ child_tree = work_tree.controldir.sprout('child').open_workingtree()
676+ self.build_tree_contents([('child/file', b'b\nc\n')])
677+ child_tree.commit('child commit')
678+ child_tree.lock_write()
679+ self.addCleanup(child_tree.unlock)
680+ work_tree.lock_write()
681+ self.addCleanup(work_tree.unlock)
682+ preview = work_tree.preview_transform()
683+ self.addCleanup(preview.finalize)
684+ file_trans_id = preview.trans_id_tree_path('file')
685+ preview.delete_contents(file_trans_id)
686+ preview.create_file([b'a\nb\n'], file_trans_id)
687+ preview_tree = preview.get_preview_tree()
688+ merger = Merger.from_revision_ids(preview_tree,
689+ child_tree.branch.last_revision(),
690+ other_branch=child_tree.branch,
691+ tree_branch=work_tree.branch)
692+ merger.merge_type = Merge3Merger
693+ tt = merger.make_merger().make_preview_transform()
694+ self.addCleanup(tt.finalize)
695+ final_tree = tt.get_preview_tree()
696+ self.assertEqual(
697+ b'a\nb\nc\n',
698+ final_tree.get_file_text('file'))
699+
700+ def test_merge_preview_into_workingtree(self):
701+ tree = self.make_branch_and_tree('tree')
702+ tree.set_root_id(b'TREE_ROOT')
703+ tt = tree.preview_transform()
704+ self.addCleanup(tt.finalize)
705+ tt.new_file('name', tt.root, [b'content'], b'file-id')
706+ tree2 = self.make_branch_and_tree('tree2')
707+ tree2.set_root_id(b'TREE_ROOT')
708+ merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
709+ tree.basis_tree())
710+ merger.merge_type = Merge3Merger
711+ merger.do_merge()
712+
713+ def test_merge_preview_into_workingtree_handles_conflicts(self):
714+ tree = self.make_branch_and_tree('tree')
715+ self.build_tree_contents([('tree/foo', b'bar')])
716+ tree.add('foo', b'foo-id')
717+ tree.commit('foo')
718+ tt = tree.preview_transform()
719+ self.addCleanup(tt.finalize)
720+ trans_id = tt.trans_id_file_id(b'foo-id')
721+ tt.delete_contents(trans_id)
722+ tt.create_file([b'baz'], trans_id)
723+ tree2 = tree.controldir.sprout('tree2').open_workingtree()
724+ self.build_tree_contents([('tree2/foo', b'qux')])
725+ merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
726+ tree.basis_tree())
727+ merger.merge_type = Merge3Merger
728+ merger.do_merge()
729+
730+ def test_has_filename(self):
731+ wt = self.make_branch_and_tree('tree')
732+ self.build_tree(['tree/unmodified', 'tree/removed', 'tree/modified'])
733+ tt = wt.preview_transform()
734+ removed_id = tt.trans_id_tree_path('removed')
735+ tt.delete_contents(removed_id)
736+ tt.new_file('new', tt.root, [b'contents'])
737+ modified_id = tt.trans_id_tree_path('modified')
738+ tt.delete_contents(modified_id)
739+ tt.create_file([b'modified-contents'], modified_id)
740+ self.addCleanup(tt.finalize)
741+ tree = tt.get_preview_tree()
742+ self.assertTrue(tree.has_filename('unmodified'))
743+ self.assertFalse(tree.has_filename('not-present'))
744+ self.assertFalse(tree.has_filename('removed'))
745+ self.assertTrue(tree.has_filename('new'))
746+ self.assertTrue(tree.has_filename('modified'))
747+
748+ def test_is_executable(self):
749+ tree = self.make_branch_and_tree('tree')
750+ preview = tree.preview_transform()
751+ self.addCleanup(preview.finalize)
752+ preview.new_file('foo', preview.root, [b'bar'], b'baz-id')
753+ preview_tree = preview.get_preview_tree()
754+ self.assertEqual(False, preview_tree.is_executable('tree/foo'))
755+
756+ def test_commit_preview_tree(self):
757+ tree = self.make_branch_and_tree('tree')
758+ rev_id = tree.commit('rev1')
759+ tree.branch.lock_write()
760+ self.addCleanup(tree.branch.unlock)
761+ tt = tree.preview_transform()
762+ tt.new_file('file', tt.root, [b'contents'], b'file_id')
763+ self.addCleanup(tt.finalize)
764+ preview = tt.get_preview_tree()
765+ preview.set_parent_ids([rev_id])
766+ builder = tree.branch.get_commit_builder([rev_id])
767+ list(builder.record_iter_changes(preview, rev_id, tt.iter_changes()))
768+ builder.finish_inventory()
769+ rev2_id = builder.commit('rev2')
770+ rev2_tree = tree.branch.repository.revision_tree(rev2_id)
771+ self.assertEqual(b'contents', rev2_tree.get_file_text('file'))
772+
773+ def test_ascii_limbo_paths(self):
774+ self.requireFeature(UnicodeFilenameFeature)
775+ branch = self.make_branch('any')
776+ tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
777+ tt = tree.preview_transform()
778+ self.addCleanup(tt.finalize)
779+ foo_id = tt.new_directory('', ROOT_PARENT)
780+ bar_id = tt.new_file(u'\u1234bar', foo_id, [b'contents'])
781+ limbo_path = tt._limbo_name(bar_id)
782+ self.assertEqual(limbo_path, limbo_path)
783
784=== modified file 'breezy/tests/per_workingtree/test_transform.py'
785--- breezy/tests/per_workingtree/test_transform.py 2020-07-04 14:58:52 +0000
786+++ breezy/tests/per_workingtree/test_transform.py 2020-07-05 00:45:38 +0000
787@@ -72,12 +72,16 @@
788 ReusingTransform,
789 )
790
791-
792-
793-class TestTreeTransform(tests.TestCaseWithTransport):
794+from breezy.tests.per_workingtree import TestCaseWithWorkingTree
795+
796+
797+
798+class TestTreeTransform(TestCaseWithWorkingTree):
799
800 def setUp(self):
801 super(TestTreeTransform, self).setUp()
802+ if not self.workingtree_format.supports_setting_file_ids:
803+ self.skipTest('test not compatible with non-file-id trees yet')
804 self.wt = self.make_branch_and_tree('wt')
805
806 def transform(self):
807@@ -385,6 +389,10 @@
808 def test_tree_reference(self):
809 transform, root = self.transform()
810 tree = transform._tree
811+ if not tree.supports_tree_reference():
812+ raise tests.TestNotApplicable(
813+ 'Tree format does not support references')
814+
815 trans_id = transform.new_directory('reference', root, b'subtree-id')
816 transform.set_tree_reference(b'subtree-revision', trans_id)
817 transform.apply()
818@@ -1643,7 +1651,7 @@
819 def test_create_from_tree(self):
820 tree1 = self.make_branch_and_tree('tree1')
821 self.build_tree_contents([('tree1/foo/',), ('tree1/bar', b'baz')])
822- tree1.add(['foo', 'bar'], [b'foo-id', b'bar-id'])
823+ tree1.add(['foo', 'bar'])
824 tree2 = self.make_branch_and_tree('tree2')
825 tt = tree2.transform()
826 foo_trans_id = tt.create_path('foo', tt.root)
827@@ -1658,7 +1666,7 @@
828 """Provided lines are used instead of tree content."""
829 tree1 = self.make_branch_and_tree('tree1')
830 self.build_tree_contents([('tree1/foo', b'bar'), ])
831- tree1.add('foo', b'foo-id')
832+ tree1.add('foo')
833 tree2 = self.make_branch_and_tree('tree2')
834 tt = tree2.transform()
835 foo_trans_id = tt.create_path('foo', tt.root)
836@@ -1670,7 +1678,7 @@
837 self.requireFeature(SymlinkFeature)
838 tree1 = self.make_branch_and_tree('tree1')
839 os.symlink('bar', 'tree1/foo')
840- tree1.add('foo', b'foo-id')
841+ tree1.add('foo')
842 tt = self.make_branch_and_tree('tree2').transform()
843 foo_trans_id = tt.create_path('foo', tt.root)
844 create_from_tree(tt, foo_trans_id, tree1, 'foo')
845
846=== modified file 'breezy/tests/test_transform.py'
847--- breezy/tests/test_transform.py 2020-07-04 13:53:04 +0000
848+++ breezy/tests/test_transform.py 2020-07-05 00:45:38 +0000
849@@ -1160,671 +1160,6 @@
850 conflicts.pop())
851
852
853-A_ENTRY = (b'a-id', ('a', 'a'), True, (True, True),
854- (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
855- (False, False), False)
856-ROOT_ENTRY = (b'TREE_ROOT', ('', ''), False, (True, True), (None, None),
857- ('', ''), ('directory', 'directory'), (False, False), False)
858-
859-
860-class TestTransformPreview(tests.TestCaseWithTransport):
861-
862- def create_tree(self):
863- tree = self.make_branch_and_tree('.')
864- self.build_tree_contents([('a', b'content 1')])
865- tree.set_root_id(b'TREE_ROOT')
866- tree.add('a', b'a-id')
867- tree.commit('rev1', rev_id=b'rev1')
868- return tree.branch.repository.revision_tree(b'rev1')
869-
870- def get_empty_preview(self):
871- repository = self.make_repository('repo')
872- tree = repository.revision_tree(_mod_revision.NULL_REVISION)
873- preview = tree.preview_transform()
874- self.addCleanup(preview.finalize)
875- return preview
876-
877- def test_transform_preview(self):
878- revision_tree = self.create_tree()
879- preview = revision_tree.preview_transform()
880- self.addCleanup(preview.finalize)
881-
882- def test_transform_preview_tree(self):
883- revision_tree = self.create_tree()
884- preview = revision_tree.preview_transform()
885- self.addCleanup(preview.finalize)
886- preview.get_preview_tree()
887-
888- def test_transform_new_file(self):
889- revision_tree = self.create_tree()
890- preview = revision_tree.preview_transform()
891- self.addCleanup(preview.finalize)
892- preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
893- preview_tree = preview.get_preview_tree()
894- self.assertEqual(preview_tree.kind('file2'), 'file')
895- with preview_tree.get_file('file2') as f:
896- self.assertEqual(f.read(), b'content B\n')
897-
898- def test_diff_preview_tree(self):
899- revision_tree = self.create_tree()
900- preview = revision_tree.preview_transform()
901- self.addCleanup(preview.finalize)
902- preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
903- preview_tree = preview.get_preview_tree()
904- out = BytesIO()
905- show_diff_trees(revision_tree, preview_tree, out)
906- lines = out.getvalue().splitlines()
907- self.assertEqual(lines[0], b"=== added file 'file2'")
908- # 3 lines of diff administrivia
909- self.assertEqual(lines[4], b"+content B")
910-
911- def test_unsupported_symlink_diff(self):
912- self.requireFeature(SymlinkFeature)
913- tree = self.make_branch_and_tree('.')
914- self.build_tree_contents([('a', 'content 1')])
915- tree.set_root_id(b'TREE_ROOT')
916- tree.add('a', b'a-id')
917- os.symlink('a', 'foo')
918- tree.add('foo', b'foo-id')
919- tree.commit('rev1', rev_id=b'rev1')
920- revision_tree = tree.branch.repository.revision_tree(b'rev1')
921- preview = revision_tree.preview_transform()
922- self.addCleanup(preview.finalize)
923- preview.delete_versioned(preview.trans_id_tree_path('foo'))
924- preview_tree = preview.get_preview_tree()
925- out = BytesIO()
926- log = BytesIO()
927- trace.push_log_file(log)
928- os_symlink = getattr(os, 'symlink', None)
929- os.symlink = None
930- try:
931- show_diff_trees(revision_tree, preview_tree, out)
932- lines = out.getvalue().splitlines()
933- finally:
934- os.symlink = os_symlink
935- self.assertContainsRe(
936- log.getvalue(),
937- b'Ignoring "foo" as symlinks are not supported on this filesystem')
938-
939- def test_transform_conflicts(self):
940- revision_tree = self.create_tree()
941- preview = revision_tree.preview_transform()
942- self.addCleanup(preview.finalize)
943- preview.new_file('a', preview.root, [b'content 2'])
944- resolve_conflicts(preview)
945- trans_id = preview.trans_id_file_id(b'a-id')
946- self.assertEqual('a.moved', preview.final_name(trans_id))
947-
948- def get_tree_and_preview_tree(self):
949- revision_tree = self.create_tree()
950- preview = revision_tree.preview_transform()
951- self.addCleanup(preview.finalize)
952- a_trans_id = preview.trans_id_file_id(b'a-id')
953- preview.delete_contents(a_trans_id)
954- preview.create_file([b'b content'], a_trans_id)
955- preview_tree = preview.get_preview_tree()
956- return revision_tree, preview_tree
957-
958- def test_iter_changes(self):
959- revision_tree, preview_tree = self.get_tree_and_preview_tree()
960- root = revision_tree.path2id('')
961- self.assertEqual([(b'a-id', ('a', 'a'), True, (True, True),
962- (root, root), ('a', 'a'), ('file', 'file'),
963- (False, False), False)],
964- list(preview_tree.iter_changes(revision_tree)))
965-
966- def test_include_unchanged_succeeds(self):
967- revision_tree, preview_tree = self.get_tree_and_preview_tree()
968- changes = preview_tree.iter_changes(revision_tree,
969- include_unchanged=True)
970- self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
971-
972- def test_specific_files(self):
973- revision_tree, preview_tree = self.get_tree_and_preview_tree()
974- changes = preview_tree.iter_changes(revision_tree,
975- specific_files=[''])
976- self.assertEqual([A_ENTRY], list(changes))
977-
978- def test_want_unversioned(self):
979- revision_tree, preview_tree = self.get_tree_and_preview_tree()
980- changes = preview_tree.iter_changes(revision_tree,
981- want_unversioned=True)
982- self.assertEqual([A_ENTRY], list(changes))
983-
984- def test_ignore_extra_trees_no_specific_files(self):
985- # extra_trees is harmless without specific_files, so we'll silently
986- # accept it, even though we won't use it.
987- revision_tree, preview_tree = self.get_tree_and_preview_tree()
988- preview_tree.iter_changes(revision_tree, extra_trees=[preview_tree])
989-
990- def test_ignore_require_versioned_no_specific_files(self):
991- # require_versioned is meaningless without specific_files.
992- revision_tree, preview_tree = self.get_tree_and_preview_tree()
993- preview_tree.iter_changes(revision_tree, require_versioned=False)
994-
995- def test_ignore_pb(self):
996- # pb could be supported, but TT.iter_changes doesn't support it.
997- revision_tree, preview_tree = self.get_tree_and_preview_tree()
998- preview_tree.iter_changes(revision_tree)
999-
1000- def test_kind(self):
1001- revision_tree = self.create_tree()
1002- preview = revision_tree.preview_transform()
1003- self.addCleanup(preview.finalize)
1004- preview.new_file('file', preview.root, [b'contents'], b'file-id')
1005- preview.new_directory('directory', preview.root, b'dir-id')
1006- preview_tree = preview.get_preview_tree()
1007- self.assertEqual('file', preview_tree.kind('file'))
1008- self.assertEqual('directory', preview_tree.kind('directory'))
1009-
1010- def test_get_file_mtime(self):
1011- preview = self.get_empty_preview()
1012- file_trans_id = preview.new_file('file', preview.root, [b'contents'],
1013- b'file-id')
1014- limbo_path = preview._limbo_name(file_trans_id)
1015- preview_tree = preview.get_preview_tree()
1016- self.assertEqual(os.stat(limbo_path).st_mtime,
1017- preview_tree.get_file_mtime('file'))
1018-
1019- def test_get_file_mtime_renamed(self):
1020- work_tree = self.make_branch_and_tree('tree')
1021- self.build_tree(['tree/file'])
1022- work_tree.add('file', b'file-id')
1023- preview = work_tree.preview_transform()
1024- self.addCleanup(preview.finalize)
1025- file_trans_id = preview.trans_id_tree_path('file')
1026- preview.adjust_path('renamed', preview.root, file_trans_id)
1027- preview_tree = preview.get_preview_tree()
1028- preview_mtime = preview_tree.get_file_mtime('renamed')
1029- work_mtime = work_tree.get_file_mtime('file')
1030-
1031- def test_get_file_size(self):
1032- work_tree = self.make_branch_and_tree('tree')
1033- self.build_tree_contents([('tree/old', b'old')])
1034- work_tree.add('old', b'old-id')
1035- preview = work_tree.preview_transform()
1036- self.addCleanup(preview.finalize)
1037- preview.new_file('name', preview.root, [b'contents'], b'new-id',
1038- 'executable')
1039- tree = preview.get_preview_tree()
1040- self.assertEqual(len('old'), tree.get_file_size('old'))
1041- self.assertEqual(len('contents'), tree.get_file_size('name'))
1042-
1043- def test_get_file(self):
1044- preview = self.get_empty_preview()
1045- preview.new_file('file', preview.root, [b'contents'], b'file-id')
1046- preview_tree = preview.get_preview_tree()
1047- with preview_tree.get_file('file') as tree_file:
1048- self.assertEqual(b'contents', tree_file.read())
1049-
1050- def test_get_symlink_target(self):
1051- self.requireFeature(SymlinkFeature)
1052- preview = self.get_empty_preview()
1053- preview.new_symlink('symlink', preview.root, 'target', b'symlink-id')
1054- preview_tree = preview.get_preview_tree()
1055- self.assertEqual('target',
1056- preview_tree.get_symlink_target('symlink'))
1057-
1058- def test_all_file_ids(self):
1059- tree = self.make_branch_and_tree('tree')
1060- self.build_tree(['tree/a', 'tree/b', 'tree/c'])
1061- tree.add(['a', 'b', 'c'], [b'a-id', b'b-id', b'c-id'])
1062- preview = tree.preview_transform()
1063- self.addCleanup(preview.finalize)
1064- preview.unversion_file(preview.trans_id_file_id(b'b-id'))
1065- c_trans_id = preview.trans_id_file_id(b'c-id')
1066- preview.unversion_file(c_trans_id)
1067- preview.version_file(c_trans_id, file_id=b'c-id')
1068- preview_tree = preview.get_preview_tree()
1069- self.assertEqual({b'a-id', b'c-id', tree.path2id('')},
1070- preview_tree.all_file_ids())
1071-
1072- def test_path2id_deleted_unchanged(self):
1073- tree = self.make_branch_and_tree('tree')
1074- self.build_tree(['tree/unchanged', 'tree/deleted'])
1075- tree.add(['unchanged', 'deleted'], [b'unchanged-id', b'deleted-id'])
1076- preview = tree.preview_transform()
1077- self.addCleanup(preview.finalize)
1078- preview.unversion_file(preview.trans_id_file_id(b'deleted-id'))
1079- preview_tree = preview.get_preview_tree()
1080- self.assertEqual(b'unchanged-id', preview_tree.path2id('unchanged'))
1081- self.assertFalse(preview_tree.is_versioned('deleted'))
1082-
1083- def test_path2id_created(self):
1084- tree = self.make_branch_and_tree('tree')
1085- self.build_tree(['tree/unchanged'])
1086- tree.add(['unchanged'], [b'unchanged-id'])
1087- preview = tree.preview_transform()
1088- self.addCleanup(preview.finalize)
1089- preview.new_file('new', preview.trans_id_file_id(b'unchanged-id'),
1090- [b'contents'], b'new-id')
1091- preview_tree = preview.get_preview_tree()
1092- self.assertEqual(b'new-id', preview_tree.path2id('unchanged/new'))
1093-
1094- def test_path2id_moved(self):
1095- tree = self.make_branch_and_tree('tree')
1096- self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
1097- tree.add(['old_parent', 'old_parent/child'],
1098- [b'old_parent-id', b'child-id'])
1099- preview = tree.preview_transform()
1100- self.addCleanup(preview.finalize)
1101- new_parent = preview.new_directory('new_parent', preview.root,
1102- b'new_parent-id')
1103- preview.adjust_path('child', new_parent,
1104- preview.trans_id_file_id(b'child-id'))
1105- preview_tree = preview.get_preview_tree()
1106- self.assertFalse(preview_tree.is_versioned('old_parent/child'))
1107- self.assertEqual(b'child-id', preview_tree.path2id('new_parent/child'))
1108-
1109- def test_path2id_renamed_parent(self):
1110- tree = self.make_branch_and_tree('tree')
1111- self.build_tree(['tree/old_name/', 'tree/old_name/child'])
1112- tree.add(['old_name', 'old_name/child'],
1113- [b'parent-id', b'child-id'])
1114- preview = tree.preview_transform()
1115- self.addCleanup(preview.finalize)
1116- preview.adjust_path('new_name', preview.root,
1117- preview.trans_id_file_id(b'parent-id'))
1118- preview_tree = preview.get_preview_tree()
1119- self.assertFalse(preview_tree.is_versioned('old_name/child'))
1120- self.assertEqual(b'child-id', preview_tree.path2id('new_name/child'))
1121-
1122- def assertMatchingIterEntries(self, tt, specific_files=None):
1123- preview_tree = tt.get_preview_tree()
1124- preview_result = list(preview_tree.iter_entries_by_dir(
1125- specific_files=specific_files))
1126- tree = tt._tree
1127- tt.apply()
1128- actual_result = list(tree.iter_entries_by_dir(
1129- specific_files=specific_files))
1130- self.assertEqual(actual_result, preview_result)
1131-
1132- def test_iter_entries_by_dir_new(self):
1133- tree = self.make_branch_and_tree('tree')
1134- tt = tree.transform()
1135- tt.new_file('new', tt.root, [b'contents'], b'new-id')
1136- self.assertMatchingIterEntries(tt)
1137-
1138- def test_iter_entries_by_dir_deleted(self):
1139- tree = self.make_branch_and_tree('tree')
1140- self.build_tree(['tree/deleted'])
1141- tree.add('deleted', b'deleted-id')
1142- tt = tree.transform()
1143- tt.delete_contents(tt.trans_id_file_id(b'deleted-id'))
1144- self.assertMatchingIterEntries(tt)
1145-
1146- def test_iter_entries_by_dir_unversioned(self):
1147- tree = self.make_branch_and_tree('tree')
1148- self.build_tree(['tree/removed'])
1149- tree.add('removed', b'removed-id')
1150- tt = tree.transform()
1151- tt.unversion_file(tt.trans_id_file_id(b'removed-id'))
1152- self.assertMatchingIterEntries(tt)
1153-
1154- def test_iter_entries_by_dir_moved(self):
1155- tree = self.make_branch_and_tree('tree')
1156- self.build_tree(['tree/moved', 'tree/new_parent/'])
1157- tree.add(['moved', 'new_parent'], [b'moved-id', b'new_parent-id'])
1158- tt = tree.transform()
1159- tt.adjust_path('moved', tt.trans_id_file_id(b'new_parent-id'),
1160- tt.trans_id_file_id(b'moved-id'))
1161- self.assertMatchingIterEntries(tt)
1162-
1163- def test_iter_entries_by_dir_specific_files(self):
1164- tree = self.make_branch_and_tree('tree')
1165- tree.set_root_id(b'tree-root-id')
1166- self.build_tree(['tree/parent/', 'tree/parent/child'])
1167- tree.add(['parent', 'parent/child'], [b'parent-id', b'child-id'])
1168- tt = tree.transform()
1169- self.assertMatchingIterEntries(tt, ['', 'parent/child'])
1170-
1171- def test_symlink_content_summary(self):
1172- self.requireFeature(SymlinkFeature)
1173- preview = self.get_empty_preview()
1174- preview.new_symlink('path', preview.root, 'target', b'path-id')
1175- summary = preview.get_preview_tree().path_content_summary('path')
1176- self.assertEqual(('symlink', None, None, 'target'), summary)
1177-
1178- def test_missing_content_summary(self):
1179- preview = self.get_empty_preview()
1180- summary = preview.get_preview_tree().path_content_summary('path')
1181- self.assertEqual(('missing', None, None, None), summary)
1182-
1183- def test_deleted_content_summary(self):
1184- tree = self.make_branch_and_tree('tree')
1185- self.build_tree(['tree/path/'])
1186- tree.add('path')
1187- preview = tree.preview_transform()
1188- self.addCleanup(preview.finalize)
1189- preview.delete_contents(preview.trans_id_tree_path('path'))
1190- summary = preview.get_preview_tree().path_content_summary('path')
1191- self.assertEqual(('missing', None, None, None), summary)
1192-
1193- def test_file_content_summary_executable(self):
1194- preview = self.get_empty_preview()
1195- path_id = preview.new_file('path', preview.root, [
1196- b'contents'], b'path-id')
1197- preview.set_executability(True, path_id)
1198- summary = preview.get_preview_tree().path_content_summary('path')
1199- self.assertEqual(4, len(summary))
1200- self.assertEqual('file', summary[0])
1201- # size must be known
1202- self.assertEqual(len('contents'), summary[1])
1203- # executable
1204- self.assertEqual(True, summary[2])
1205- # will not have hash (not cheap to determine)
1206- self.assertIs(None, summary[3])
1207-
1208- def test_change_executability(self):
1209- tree = self.make_branch_and_tree('tree')
1210- self.build_tree(['tree/path'])
1211- tree.add('path')
1212- preview = tree.preview_transform()
1213- self.addCleanup(preview.finalize)
1214- path_id = preview.trans_id_tree_path('path')
1215- preview.set_executability(True, path_id)
1216- summary = preview.get_preview_tree().path_content_summary('path')
1217- self.assertEqual(True, summary[2])
1218-
1219- def test_file_content_summary_non_exec(self):
1220- preview = self.get_empty_preview()
1221- preview.new_file('path', preview.root, [b'contents'], b'path-id')
1222- summary = preview.get_preview_tree().path_content_summary('path')
1223- self.assertEqual(4, len(summary))
1224- self.assertEqual('file', summary[0])
1225- # size must be known
1226- self.assertEqual(len('contents'), summary[1])
1227- # not executable
1228- self.assertEqual(False, summary[2])
1229- # will not have hash (not cheap to determine)
1230- self.assertIs(None, summary[3])
1231-
1232- def test_dir_content_summary(self):
1233- preview = self.get_empty_preview()
1234- preview.new_directory('path', preview.root, b'path-id')
1235- summary = preview.get_preview_tree().path_content_summary('path')
1236- self.assertEqual(('directory', None, None, None), summary)
1237-
1238- def test_tree_content_summary(self):
1239- preview = self.get_empty_preview()
1240- path = preview.new_directory('path', preview.root, b'path-id')
1241- preview.set_tree_reference(b'rev-1', path)
1242- summary = preview.get_preview_tree().path_content_summary('path')
1243- self.assertEqual(4, len(summary))
1244- self.assertEqual('tree-reference', summary[0])
1245-
1246- def test_annotate(self):
1247- tree = self.make_branch_and_tree('tree')
1248- self.build_tree_contents([('tree/file', b'a\n')])
1249- tree.add('file', b'file-id')
1250- tree.commit('a', rev_id=b'one')
1251- self.build_tree_contents([('tree/file', b'a\nb\n')])
1252- preview = tree.preview_transform()
1253- self.addCleanup(preview.finalize)
1254- file_trans_id = preview.trans_id_file_id(b'file-id')
1255- preview.delete_contents(file_trans_id)
1256- preview.create_file([b'a\nb\nc\n'], file_trans_id)
1257- preview_tree = preview.get_preview_tree()
1258- expected = [
1259- (b'one', b'a\n'),
1260- (b'me:', b'b\n'),
1261- (b'me:', b'c\n'),
1262- ]
1263- annotation = preview_tree.annotate_iter(
1264- 'file', default_revision=b'me:')
1265- self.assertEqual(expected, annotation)
1266-
1267- def test_annotate_missing(self):
1268- preview = self.get_empty_preview()
1269- preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
1270- preview_tree = preview.get_preview_tree()
1271- expected = [
1272- (b'me:', b'a\n'),
1273- (b'me:', b'b\n'),
1274- (b'me:', b'c\n'),
1275- ]
1276- annotation = preview_tree.annotate_iter(
1277- 'file', default_revision=b'me:')
1278- self.assertEqual(expected, annotation)
1279-
1280- def test_annotate_rename(self):
1281- tree = self.make_branch_and_tree('tree')
1282- self.build_tree_contents([('tree/file', b'a\n')])
1283- tree.add('file', b'file-id')
1284- tree.commit('a', rev_id=b'one')
1285- preview = tree.preview_transform()
1286- self.addCleanup(preview.finalize)
1287- file_trans_id = preview.trans_id_file_id(b'file-id')
1288- preview.adjust_path('newname', preview.root, file_trans_id)
1289- preview_tree = preview.get_preview_tree()
1290- expected = [
1291- (b'one', b'a\n'),
1292- ]
1293- annotation = preview_tree.annotate_iter(
1294- 'file', default_revision=b'me:')
1295- self.assertEqual(expected, annotation)
1296-
1297- def test_annotate_deleted(self):
1298- tree = self.make_branch_and_tree('tree')
1299- self.build_tree_contents([('tree/file', b'a\n')])
1300- tree.add('file', b'file-id')
1301- tree.commit('a', rev_id=b'one')
1302- self.build_tree_contents([('tree/file', b'a\nb\n')])
1303- preview = tree.preview_transform()
1304- self.addCleanup(preview.finalize)
1305- file_trans_id = preview.trans_id_file_id(b'file-id')
1306- preview.delete_contents(file_trans_id)
1307- preview_tree = preview.get_preview_tree()
1308- annotation = preview_tree.annotate_iter(
1309- 'file', default_revision=b'me:')
1310- self.assertIs(None, annotation)
1311-
1312- def test_stored_kind(self):
1313- preview = self.get_empty_preview()
1314- preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
1315- preview_tree = preview.get_preview_tree()
1316- self.assertEqual('file', preview_tree.stored_kind('file'))
1317-
1318- def test_is_executable(self):
1319- preview = self.get_empty_preview()
1320- preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
1321- preview.set_executability(True, preview.trans_id_file_id(b'file-id'))
1322- preview_tree = preview.get_preview_tree()
1323- self.assertEqual(True, preview_tree.is_executable('file'))
1324-
1325- def test_get_set_parent_ids(self):
1326- revision_tree, preview_tree = self.get_tree_and_preview_tree()
1327- self.assertEqual([], preview_tree.get_parent_ids())
1328- preview_tree.set_parent_ids([b'rev-1'])
1329- self.assertEqual([b'rev-1'], preview_tree.get_parent_ids())
1330-
1331- def test_plan_file_merge(self):
1332- work_a = self.make_branch_and_tree('wta')
1333- self.build_tree_contents([('wta/file', b'a\nb\nc\nd\n')])
1334- work_a.add('file', b'file-id')
1335- base_id = work_a.commit('base version')
1336- tree_b = work_a.controldir.sprout('wtb').open_workingtree()
1337- preview = work_a.preview_transform()
1338- self.addCleanup(preview.finalize)
1339- trans_id = preview.trans_id_file_id(b'file-id')
1340- preview.delete_contents(trans_id)
1341- preview.create_file([b'b\nc\nd\ne\n'], trans_id)
1342- self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
1343- tree_a = preview.get_preview_tree()
1344- tree_a.set_parent_ids([base_id])
1345- self.assertEqual([
1346- ('killed-a', b'a\n'),
1347- ('killed-b', b'b\n'),
1348- ('unchanged', b'c\n'),
1349- ('unchanged', b'd\n'),
1350- ('new-a', b'e\n'),
1351- ('new-b', b'f\n'),
1352- ], list(tree_a.plan_file_merge('file', tree_b)))
1353-
1354- def test_plan_file_merge_revision_tree(self):
1355- work_a = self.make_branch_and_tree('wta')
1356- self.build_tree_contents([('wta/file', b'a\nb\nc\nd\n')])
1357- work_a.add('file', b'file-id')
1358- base_id = work_a.commit('base version')
1359- tree_b = work_a.controldir.sprout('wtb').open_workingtree()
1360- preview = work_a.basis_tree().preview_transform()
1361- self.addCleanup(preview.finalize)
1362- trans_id = preview.trans_id_file_id(b'file-id')
1363- preview.delete_contents(trans_id)
1364- preview.create_file([b'b\nc\nd\ne\n'], trans_id)
1365- self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
1366- tree_a = preview.get_preview_tree()
1367- tree_a.set_parent_ids([base_id])
1368- self.assertEqual([
1369- ('killed-a', b'a\n'),
1370- ('killed-b', b'b\n'),
1371- ('unchanged', b'c\n'),
1372- ('unchanged', b'd\n'),
1373- ('new-a', b'e\n'),
1374- ('new-b', b'f\n'),
1375- ], list(tree_a.plan_file_merge('file', tree_b)))
1376-
1377- def test_walkdirs(self):
1378- preview = self.get_empty_preview()
1379- preview.new_directory('', ROOT_PARENT, b'tree-root')
1380- # FIXME: new_directory should mark root.
1381- preview.fixup_new_roots()
1382- preview_tree = preview.get_preview_tree()
1383- preview.new_file('a', preview.root, [b'contents'], b'a-id')
1384- expected = [(('', b'tree-root'),
1385- [('a', 'a', 'file', None, b'a-id', 'file')])]
1386- self.assertEqual(expected, list(preview_tree.walkdirs()))
1387-
1388- def test_extras(self):
1389- work_tree = self.make_branch_and_tree('tree')
1390- self.build_tree(['tree/removed-file', 'tree/existing-file',
1391- 'tree/not-removed-file'])
1392- work_tree.add(['removed-file', 'not-removed-file'])
1393- preview = work_tree.preview_transform()
1394- self.addCleanup(preview.finalize)
1395- preview.new_file('new-file', preview.root, [b'contents'])
1396- preview.new_file('new-versioned-file', preview.root, [b'contents'],
1397- b'new-versioned-id')
1398- tree = preview.get_preview_tree()
1399- preview.unversion_file(preview.trans_id_tree_path('removed-file'))
1400- self.assertEqual({'new-file', 'removed-file', 'existing-file'},
1401- set(tree.extras()))
1402-
1403- def test_merge_into_preview(self):
1404- work_tree = self.make_branch_and_tree('tree')
1405- self.build_tree_contents([('tree/file', b'b\n')])
1406- work_tree.add('file', b'file-id')
1407- work_tree.commit('first commit')
1408- child_tree = work_tree.controldir.sprout('child').open_workingtree()
1409- self.build_tree_contents([('child/file', b'b\nc\n')])
1410- child_tree.commit('child commit')
1411- child_tree.lock_write()
1412- self.addCleanup(child_tree.unlock)
1413- work_tree.lock_write()
1414- self.addCleanup(work_tree.unlock)
1415- preview = work_tree.preview_transform()
1416- self.addCleanup(preview.finalize)
1417- file_trans_id = preview.trans_id_file_id(b'file-id')
1418- preview.delete_contents(file_trans_id)
1419- preview.create_file([b'a\nb\n'], file_trans_id)
1420- preview_tree = preview.get_preview_tree()
1421- merger = Merger.from_revision_ids(preview_tree,
1422- child_tree.branch.last_revision(),
1423- other_branch=child_tree.branch,
1424- tree_branch=work_tree.branch)
1425- merger.merge_type = Merge3Merger
1426- tt = merger.make_merger().make_preview_transform()
1427- self.addCleanup(tt.finalize)
1428- final_tree = tt.get_preview_tree()
1429- self.assertEqual(
1430- b'a\nb\nc\n',
1431- final_tree.get_file_text(final_tree.id2path(b'file-id')))
1432-
1433- def test_merge_preview_into_workingtree(self):
1434- tree = self.make_branch_and_tree('tree')
1435- tree.set_root_id(b'TREE_ROOT')
1436- tt = tree.preview_transform()
1437- self.addCleanup(tt.finalize)
1438- tt.new_file('name', tt.root, [b'content'], b'file-id')
1439- tree2 = self.make_branch_and_tree('tree2')
1440- tree2.set_root_id(b'TREE_ROOT')
1441- merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
1442- tree.basis_tree())
1443- merger.merge_type = Merge3Merger
1444- merger.do_merge()
1445-
1446- def test_merge_preview_into_workingtree_handles_conflicts(self):
1447- tree = self.make_branch_and_tree('tree')
1448- self.build_tree_contents([('tree/foo', b'bar')])
1449- tree.add('foo', b'foo-id')
1450- tree.commit('foo')
1451- tt = tree.preview_transform()
1452- self.addCleanup(tt.finalize)
1453- trans_id = tt.trans_id_file_id(b'foo-id')
1454- tt.delete_contents(trans_id)
1455- tt.create_file([b'baz'], trans_id)
1456- tree2 = tree.controldir.sprout('tree2').open_workingtree()
1457- self.build_tree_contents([('tree2/foo', b'qux')])
1458- merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
1459- tree.basis_tree())
1460- merger.merge_type = Merge3Merger
1461- merger.do_merge()
1462-
1463- def test_has_filename(self):
1464- wt = self.make_branch_and_tree('tree')
1465- self.build_tree(['tree/unmodified', 'tree/removed', 'tree/modified'])
1466- tt = wt.preview_transform()
1467- removed_id = tt.trans_id_tree_path('removed')
1468- tt.delete_contents(removed_id)
1469- tt.new_file('new', tt.root, [b'contents'])
1470- modified_id = tt.trans_id_tree_path('modified')
1471- tt.delete_contents(modified_id)
1472- tt.create_file([b'modified-contents'], modified_id)
1473- self.addCleanup(tt.finalize)
1474- tree = tt.get_preview_tree()
1475- self.assertTrue(tree.has_filename('unmodified'))
1476- self.assertFalse(tree.has_filename('not-present'))
1477- self.assertFalse(tree.has_filename('removed'))
1478- self.assertTrue(tree.has_filename('new'))
1479- self.assertTrue(tree.has_filename('modified'))
1480-
1481- def test_is_executable(self):
1482- tree = self.make_branch_and_tree('tree')
1483- preview = tree.preview_transform()
1484- self.addCleanup(preview.finalize)
1485- preview.new_file('foo', preview.root, [b'bar'], b'baz-id')
1486- preview_tree = preview.get_preview_tree()
1487- self.assertEqual(False, preview_tree.is_executable('tree/foo'))
1488-
1489- def test_commit_preview_tree(self):
1490- tree = self.make_branch_and_tree('tree')
1491- rev_id = tree.commit('rev1')
1492- tree.branch.lock_write()
1493- self.addCleanup(tree.branch.unlock)
1494- tt = tree.preview_transform()
1495- tt.new_file('file', tt.root, [b'contents'], b'file_id')
1496- self.addCleanup(tt.finalize)
1497- preview = tt.get_preview_tree()
1498- preview.set_parent_ids([rev_id])
1499- builder = tree.branch.get_commit_builder([rev_id])
1500- list(builder.record_iter_changes(preview, rev_id, tt.iter_changes()))
1501- builder.finish_inventory()
1502- rev2_id = builder.commit('rev2')
1503- rev2_tree = tree.branch.repository.revision_tree(rev2_id)
1504- self.assertEqual(b'contents', rev2_tree.get_file_text('file'))
1505-
1506- def test_ascii_limbo_paths(self):
1507- self.requireFeature(features.UnicodeFilenameFeature)
1508- branch = self.make_branch('any')
1509- tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
1510- tt = tree.preview_transform()
1511- self.addCleanup(tt.finalize)
1512- foo_id = tt.new_directory('', ROOT_PARENT)
1513- bar_id = tt.new_file(u'\u1234bar', foo_id, [b'contents'])
1514- limbo_path = tt._limbo_name(bar_id)
1515- self.assertEqual(limbo_path, limbo_path)
1516-
1517-
1518 class FakeSerializer(object):
1519 """Serializer implementation that simply returns the input.
1520
1521
1522=== modified file 'breezy/tests/test_tree.py'
1523--- breezy/tests/test_tree.py 2019-06-29 19:50:18 +0000
1524+++ breezy/tests/test_tree.py 2020-07-05 00:45:38 +0000
1525@@ -91,6 +91,10 @@
1526 include_root, want_unversioned)
1527 )
1528
1529+ def find_source_path(self, target_path, recurse='none'):
1530+ self.calls.append(
1531+ ('find_source_path', self.source, self.target, target_path, recurse))
1532+
1533 @classmethod
1534 def is_compatible(klass, source, target):
1535 return True
1536@@ -106,6 +110,7 @@
1537 RecordingOptimiser.calls = []
1538 InterTree.register_optimiser(RecordingOptimiser)
1539 tree = self.make_branch_and_tree('1')
1540+ null_tree = tree.basis_tree()
1541 tree2 = self.make_branch_and_tree('2')
1542 # do a series of calls:
1543 # trivial usage
1544@@ -126,6 +131,8 @@
1545 InterTree._optimisers = old_optimisers
1546 self.assertEqual(
1547 [
1548+ ('find_source_path', null_tree, tree, '', 'none'),
1549+ ('find_source_path', null_tree, tree2, '', 'none'),
1550 ('compare', tree2, tree, False, None, None, False, False,
1551 False),
1552 ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
1553
1554=== modified file 'breezy/transform.py'
1555--- breezy/transform.py 2020-07-04 14:58:52 +0000
1556+++ breezy/transform.py 2020-07-05 00:45:38 +0000
1557@@ -72,6 +72,7 @@
1558 from .tree import (
1559 InterTree,
1560 TreeChange,
1561+ find_previous_path,
1562 )
1563
1564
1565@@ -508,6 +509,9 @@
1566 return self._tree.path2id('')
1567 return self._tree.path2id(path)
1568
1569+ def final_is_versioned(self, trans_id):
1570+ return self.final_file_id(trans_id) is not None
1571+
1572 def final_file_id(self, trans_id):
1573 """Determine the file id after any changes are applied, or None.
1574
1575@@ -687,10 +691,10 @@
1576 for parent_id, children in viewitems(by_parent):
1577 if parent_id == ROOT_PARENT:
1578 continue
1579- if self.final_file_id(parent_id) is not None:
1580+ if self.final_is_versioned(parent_id):
1581 continue
1582 for child_id in children:
1583- if self.final_file_id(child_id) is not None:
1584+ if self.final_is_versioned(child_id):
1585 conflicts.append(('unversioned parent', parent_id))
1586 break
1587 return conflicts
1588@@ -723,7 +727,7 @@
1589 """
1590 conflicts = []
1591 for trans_id in self._new_executability:
1592- if self.final_file_id(trans_id) is None:
1593+ if not self.final_is_versioned(trans_id):
1594 conflicts.append(('unversioned executability', trans_id))
1595 else:
1596 if self.final_kind(trans_id) != "file":
1597@@ -760,8 +764,7 @@
1598 last_trans_id = None
1599 for name, trans_id in name_ids:
1600 kind = self.final_kind(trans_id)
1601- file_id = self.final_file_id(trans_id)
1602- if kind is None and file_id is None:
1603+ if kind is None and not self.final_is_versioned(trans_id):
1604 continue
1605 if name == last_name:
1606 conflicts.append(('duplicate', last_trans_id, trans_id,
1607@@ -913,7 +916,7 @@
1608 # The child is removed as part of the transform. Since it was
1609 # versioned before, it's not an orphan
1610 continue
1611- if self.final_file_id(child_tid) is None:
1612+ if not self.final_is_versioned(child_tid):
1613 # The child is not versioned
1614 orphans.append(child_tid)
1615 else:
1616@@ -1101,7 +1104,7 @@
1617 if strict:
1618 unversioned = set(self._new_contents).difference(set(self._new_id))
1619 for trans_id in unversioned:
1620- if self.final_file_id(trans_id) is None:
1621+ if not self.final_is_versioned(trans_id):
1622 raise errors.StrictCommitFailed()
1623
1624 revno, last_rev_id = branch.last_revision_info()
1625@@ -1859,7 +1862,7 @@
1626 raise
1627 else:
1628 mover.apply_deletions()
1629- if self.final_file_id(self.root) is None:
1630+ if not self.final_is_versioned(self.root):
1631 inventory_delta = [e for e in inventory_delta if e[0] != '']
1632 self._tree.apply_inventory_delta(inventory_delta)
1633 self._apply_observed_sha1s()
1634@@ -2138,7 +2141,6 @@
1635 kind = None
1636 executable = False
1637 else:
1638- file_id = self._transform.final_file_id(self._path2trans_id(path))
1639 executable = self.is_executable(path)
1640 return kind, executable, None
1641
1642@@ -2230,7 +2232,7 @@
1643 possible_extras.update(self._transform._new_contents)
1644 possible_extras.update(self._transform._removed_id)
1645 for trans_id in possible_extras:
1646- if self._transform.final_file_id(trans_id) is None:
1647+ if not self._transform.final_is_versioned(trans_id):
1648 yield self._final_paths._determine_path(trans_id)
1649
1650 def _make_inv_entries(self, ordered_entries, specific_files=None):
1651@@ -2677,7 +2679,7 @@
1652 divert = set()
1653 try:
1654 pp.next_phase()
1655- file_trans_id[wt.path2id('')] = tt.trans_id_tree_path('')
1656+ file_trans_id[find_previous_path(wt, tree, '')] = tt.trans_id_tree_path('')
1657 with ui.ui_factory.nested_progress_bar() as pb:
1658 deferred_contents = []
1659 num = 0
1660@@ -2714,19 +2716,19 @@
1661 except errors.NotBranchError:
1662 pass
1663 else:
1664- divert.add(file_id)
1665- if (file_id not in divert
1666+ divert.add(tree_path)
1667+ if (tree_path not in divert
1668 and _content_match(
1669 tree, entry, tree_path, kind, target_path)):
1670 tt.delete_contents(tt.trans_id_tree_path(tree_path))
1671 if kind == 'directory':
1672 reparent = True
1673- parent_id = file_trans_id[entry.parent_id]
1674+ parent_id = file_trans_id[osutils.dirname(tree_path)]
1675 if entry.kind == 'file':
1676 # We *almost* replicate new_by_entry, so that we can defer
1677 # getting the file text, and get them all at once.
1678 trans_id = tt.create_path(entry.name, parent_id)
1679- file_trans_id[file_id] = trans_id
1680+ file_trans_id[tree_path] = trans_id
1681 tt.version_file(trans_id, file_id=file_id)
1682 executable = tree.is_executable(tree_path)
1683 if executable:
1684@@ -2734,10 +2736,10 @@
1685 trans_data = (trans_id, tree_path, entry.text_sha1)
1686 deferred_contents.append((tree_path, trans_data))
1687 else:
1688- file_trans_id[file_id] = new_by_entry(
1689+ file_trans_id[tree_path] = new_by_entry(
1690 tree_path, tt, entry, parent_id, tree)
1691 if reparent:
1692- new_trans_id = file_trans_id[file_id]
1693+ new_trans_id = file_trans_id[tree_path]
1694 old_parent = tt.trans_id_tree_path(tree_path)
1695 _reparent_children(tt, old_parent, new_trans_id)
1696 offset = num + 1 - len(deferred_contents)

Subscribers

People subscribed via source and target branches