Merge lp:~jelmer/brz/delta-copied 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/delta-copied
Merge into: lp:brz
Prerequisite: lp:~jelmer/brz/tree-change-without-file-id
Diff against target: 1018 lines (+146/-67)
19 files modified
breezy/bzr/bundle/serializer/v08.py (+2/-1)
breezy/delta.py (+36/-16)
breezy/info.py (+1/-0)
breezy/log.py (+2/-3)
breezy/plugins/fastimport/exporter.py (+1/-1)
breezy/plugins/fastimport/tests/test_generic_processor.py (+1/-1)
breezy/plugins/fastimport/tests/test_revision_store.py (+3/-3)
breezy/plugins/upload/cmds.py (+1/-1)
breezy/plugins/weave_fmt/test_bzrdir.py (+2/-0)
breezy/tests/blackbox/test_info.py (+21/-0)
breezy/tests/per_intertree/test_compare.py (+22/-5)
breezy/tests/per_repository_vf/test_fileid_involved.py (+2/-1)
breezy/tests/per_workingtree/test_changes_from.py (+2/-0)
breezy/tests/test_delta.py (+15/-12)
breezy/tests/test_missing.py (+4/-0)
breezy/tests/test_transform.py (+18/-16)
breezy/tests/test_workingtree_4.py (+3/-3)
breezy/tree.py (+6/-4)
breezy/version_info_formats/__init__.py (+4/-0)
To merge this branch: bzr merge lp:~jelmer/brz/delta-copied
Reviewer Review Type Date Requested Status
Martin Packman Approve
Review via email: mp+369485@code.launchpad.net

Commit message

Add TreeDelta.copied and TreeChange.copied fields.

Description of the change

Add TreeDelta.copied and TreeChange.copied fields.

This in preparation of copy tracking support in Git and Svn backends.

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

I think this is all reasonable. The pattern of using `+` on lists just to iterate is slightly bogus, but guess there would need to be a lot of changes to really matter then likely other things would be slow.

review: Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/bzr/bundle/serializer/v08.py'
2--- breezy/bzr/bundle/serializer/v08.py 2019-09-21 15:38:35 +0000
3+++ breezy/bzr/bundle/serializer/v08.py 2019-09-21 23:05:30 +0000
4@@ -312,7 +312,8 @@
5 for change in delta.removed:
6 action = Action('removed', [change.kind[0], change.path[0]]).write(self.to_file)
7
8- for change in delta.added:
9+ # TODO(jelmer): Treat copied specially here?
10+ for change in delta.added + delta.copied:
11 action = Action(
12 'added', [change.kind[1], change.path[1]],
13 [('file-id', change.file_id.decode('utf-8'))])
14
15=== modified file 'breezy/delta.py'
16--- breezy/delta.py 2019-06-29 19:50:18 +0000
17+++ breezy/delta.py 2019-09-21 23:05:30 +0000
18@@ -34,6 +34,7 @@
19 added
20 removed
21 renamed
22+ copied
23 kind_changed
24 modified
25 unchanged
26@@ -41,8 +42,8 @@
27
28 Each id is listed only once.
29
30- Files that are both modified and renamed are listed only in
31- renamed, with the text_modified flag true. The text_modified
32+ Files that are both modified and renamed or copied are listed only in
33+ renamed or copied, with the text_modified flag true. The text_modified
34 applies either to the content of the file or the target of the
35 symbolic link, depending of the kind of file.
36
37@@ -57,6 +58,7 @@
38 self.added = []
39 self.removed = []
40 self.renamed = []
41+ self.copied = []
42 self.kind_changed = []
43 self.modified = []
44 self.unchanged = []
45@@ -69,6 +71,7 @@
46 return self.added == other.added \
47 and self.removed == other.removed \
48 and self.renamed == other.renamed \
49+ and self.copied == other.copied \
50 and self.modified == other.modified \
51 and self.unchanged == other.unchanged \
52 and self.kind_changed == other.kind_changed \
53@@ -79,16 +82,18 @@
54
55 def __repr__(self):
56 return "TreeDelta(added=%r, removed=%r, renamed=%r," \
57- " kind_changed=%r, modified=%r, unchanged=%r," \
58- " unversioned=%r)" % (self.added,
59- self.removed, self.renamed, self.kind_changed, self.modified,
60- self.unchanged, self.unversioned)
61+ " copied=%r, kind_changed=%r, modified=%r, unchanged=%r," \
62+ " unversioned=%r)" % (
63+ self.added, self.removed, self.renamed, self.copied,
64+ self.kind_changed, self.modified, self.unchanged,
65+ self.unversioned)
66
67 def has_changed(self):
68 return bool(self.modified
69 or self.added
70 or self.removed
71 or self.renamed
72+ or self.copied
73 or self.kind_changed)
74
75 def get_changes_as_text(self, show_ids=False, show_unchanged=False,
76@@ -130,10 +135,13 @@
77 elif fully_present[0] is False:
78 delta.missing.append(change)
79 elif change.name[0] != change.name[1] or change.parent_id[0] != change.parent_id[1]:
80- # If the name changes, or the parent_id changes, we have a rename
81+ # If the name changes, or the parent_id changes, we have a rename or copy
82 # (if we move a parent, that doesn't count as a rename for the
83 # file)
84- delta.renamed.append(change)
85+ if change.copied:
86+ delta.copied.append(change)
87+ else:
88+ delta.renamed.append(change)
89 elif change.kind[0] != change.kind[1]:
90 delta.kind_changed.append(change)
91 elif change.changed_content or change.executable[0] != change.executable[1]:
92@@ -151,6 +159,7 @@
93 delta.removed.sort(key=change_key)
94 delta.added.sort(key=change_key)
95 delta.renamed.sort(key=change_key)
96+ delta.copied.sort(key=change_key)
97 delta.missing.sort(key=change_key)
98 # TODO: jam 20060529 These lists shouldn't need to be sorted
99 # since we added them in alphabetical order.
100@@ -220,7 +229,7 @@
101 self.output("Operating on whole tree but only reporting on "
102 "'%s' view." % (self.view_name,))
103
104- def report(self, paths, versioned, renamed, modified, exe_change,
105+ def report(self, paths, versioned, renamed, copied, modified, exe_change,
106 kind):
107 """Report one change to a file
108
109@@ -228,6 +237,7 @@
110 :param versioned: may be 'added', 'removed', 'unchanged', or
111 'unversioned.
112 :param renamed: may be True or False
113+ :param copied: may be True or False
114 :param modified: may be 'created', 'deleted', 'kind changed',
115 'modified' or 'unchanged'.
116 :param exe_change: True if the execute bit has changed
117@@ -253,13 +263,13 @@
118 # ( the path is different OR
119 # the kind is different)
120 if (versioned == 'unchanged' and
121- (renamed or modified == 'kind changed')):
122- if renamed:
123- # on a rename, we show old and new
124+ (renamed or copied or modified == 'kind changed')):
125+ if renamed or copied:
126+ # on a rename or copy, we show old and new
127 old_path, path = paths
128 else:
129- # if it's not renamed, we're showing both for kind changes
130- # so only show the new path
131+ # if it's not renamed or copied, we're showing both for kind
132+ # changes so only show the new path
133 old_path, path = paths[1], paths[1]
134 # if the file is not missing in the source, we show its kind
135 # when we show two paths.
136@@ -275,6 +285,8 @@
137 path = paths[1]
138 if renamed:
139 rename = "R"
140+ elif copied:
141+ rename = "C"
142 else:
143 rename = self.versioned_map[versioned]
144 # we show the old kind on the new path when the content is deleted.
145@@ -320,8 +332,14 @@
146 # as it had a value
147 if None not in change.name and None not in change.parent_id and\
148 (change.name[0] != change.name[1] or change.parent_id[0] != change.parent_id[1]):
149- renamed = True
150+ if change.copied:
151+ copied = True
152+ renamed = False
153+ else:
154+ renamed = True
155+ copied = False
156 else:
157+ copied = False
158 renamed = False
159 if change.kind[0] != change.kind[1]:
160 if change.kind[0] is None:
161@@ -340,7 +358,7 @@
162 if change.kind[1] == "file":
163 exe_change = (change.executable[0] != change.executable[1])
164 versioned_change = versioned_change_map[change.versioned]
165- reporter.report(change.path, versioned_change, renamed, modified,
166+ reporter.report(change.path, versioned_change, renamed, copied, modified,
167 exe_change, change.kind)
168
169
170@@ -440,6 +458,8 @@
171 extra_modified = []
172 show_list(delta.renamed, 'renamed', 'R', with_file_id_format='%s',
173 show_more=show_more_renamed)
174+ show_list(delta.copied, 'copied', 'C', with_file_id_format='%s',
175+ show_more=show_more_renamed)
176 show_list(delta.kind_changed, 'kind changed', 'K',
177 with_file_id_format='%s',
178 show_more=show_more_kind_changed)
179
180=== modified file 'breezy/info.py'
181--- breezy/info.py 2019-09-05 01:42:51 +0000
182+++ breezy/info.py 2019-09-21 23:05:30 +0000
183@@ -284,6 +284,7 @@
184 outfile.write(' %8d added\n' % len(delta.added))
185 outfile.write(' %8d removed\n' % len(delta.removed))
186 outfile.write(' %8d renamed\n' % len(delta.renamed))
187+ outfile.write(' %8d copied\n' % len(delta.copied))
188
189 ignore_cnt = unknown_cnt = 0
190 for path in working.extras():
191
192=== modified file 'breezy/log.py'
193--- breezy/log.py 2019-09-21 17:08:09 +0000
194+++ breezy/log.py 2019-09-21 23:05:30 +0000
195@@ -1016,7 +1016,7 @@
196 fileids set once their add or remove entry is detected respectively
197 """
198 if stop_on == 'add':
199- for item in delta.added:
200+ for item in delta.added + delta.copied:
201 if item.file_id in fileids:
202 fileids.remove(item.file_id)
203 elif stop_on == 'delete':
204@@ -1799,8 +1799,7 @@
205 else:
206 path = c.path[0]
207 to_file.write('\t* %s:\n' % (path,))
208- for c in revision.delta.renamed:
209- oldpath, newpath = c[:2]
210+ for c in revision.delta.renamed + revision.delta.copied:
211 # For renamed files, show both the old and the new path
212 to_file.write('\t* %s:\n\t* %s:\n' % (c.path[0], c.path[1]))
213 to_file.write('\n')
214
215=== modified file 'breezy/plugins/fastimport/exporter.py'
216--- breezy/plugins/fastimport/exporter.py 2019-06-29 19:50:18 +0000
217+++ breezy/plugins/fastimport/exporter.py 2019-09-21 23:05:30 +0000
218@@ -502,7 +502,7 @@
219
220 # Record modifications
221 files_to_get = []
222- for change in changes.added + my_modified + rd_modifies:
223+ for change in changes.added + changes.copied + my_modified + rd_modifies:
224 if change.kind[1] == 'file':
225 files_to_get.append(
226 (change.path[1],
227
228=== modified file 'breezy/plugins/fastimport/tests/test_generic_processor.py'
229--- breezy/plugins/fastimport/tests/test_generic_processor.py 2019-06-29 19:50:18 +0000
230+++ breezy/plugins/fastimport/tests/test_generic_processor.py 2019-09-21 23:05:30 +0000
231@@ -125,7 +125,7 @@
232 that must have been changed in the delta.
233 """
234 renamed = changes.renamed
235- added = changes.added
236+ added = changes.added + changes.copied
237 removed = changes.removed
238 modified = changes.modified
239 kind_changed = changes.kind_changed
240
241=== modified file 'breezy/plugins/fastimport/tests/test_revision_store.py'
242--- breezy/plugins/fastimport/tests/test_revision_store.py 2018-11-16 18:33:17 +0000
243+++ breezy/plugins/fastimport/tests/test_revision_store.py 2019-09-21 23:05:30 +0000
244@@ -141,13 +141,13 @@
245 changes = list(shim._delta_to_iter_changes())
246 expected = [(b'foo-id', ('foo', 'bar/foo2'), False, (True, True),
247 (b'TREE_ROOT', b'bar-id'), ('foo', 'foo2'),
248- ('file', 'file'), (False, False)),
249+ ('file', 'file'), (False, False), False),
250 (b'baz-id', ('bar/baz', None), True, (True, False),
251 (b'bar-id', None), ('baz', None),
252- ('file', None), (False, None)),
253+ ('file', None), (False, None), False),
254 (b'link-id', (None, 'link'), True, (False, True),
255 (None, b'TREE_ROOT'), (None, 'link'),
256- (None, 'symlink'), (None, False)),
257+ (None, 'symlink'), (None, False), False),
258 ]
259 # from pprint import pformat
260 # self.assertEqualDiff(pformat(expected), pformat(changes))
261
262=== modified file 'breezy/plugins/upload/cmds.py'
263--- breezy/plugins/upload/cmds.py 2019-08-11 13:33:45 +0000
264+++ breezy/plugins/upload/cmds.py 2019-09-21 23:05:30 +0000
265@@ -414,7 +414,7 @@
266 else:
267 raise NotImplementedError
268
269- for change in changes.added:
270+ for change in changes.added + changes.copied:
271 if self.is_ignored(change.path[1]):
272 if not self.quiet:
273 self.outf.write('Ignoring %s\n' % change.path[1])
274
275=== modified file 'breezy/plugins/weave_fmt/test_bzrdir.py'
276--- breezy/plugins/weave_fmt/test_bzrdir.py 2018-11-16 18:33:17 +0000
277+++ breezy/plugins/weave_fmt/test_bzrdir.py 2019-09-21 23:05:30 +0000
278@@ -477,6 +477,7 @@
279 0 added
280 0 removed
281 0 renamed
282+ 0 copied
283 0 unknown
284 0 ignored
285 0 versioned subdirectories
286@@ -509,6 +510,7 @@
287 0 added
288 0 removed
289 0 renamed
290+ 0 copied
291 0 unknown
292 0 ignored
293 0 versioned subdirectories
294
295=== modified file 'breezy/tests/blackbox/test_info.py'
296--- breezy/tests/blackbox/test_info.py 2019-06-29 19:54:32 +0000
297+++ breezy/tests/blackbox/test_info.py 2019-09-21 23:05:30 +0000
298@@ -135,6 +135,7 @@
299 1 added
300 0 removed
301 0 renamed
302+ 0 copied
303 0 unknown
304 0 ignored
305 0 versioned subdirectories
306@@ -169,6 +170,7 @@
307 1 added
308 0 removed
309 0 renamed
310+ 0 copied
311 0 unknown
312 0 ignored
313 0 versioned subdirectories
314@@ -226,6 +228,7 @@
315 0 added
316 0 removed
317 0 renamed
318+ 0 copied
319 0 unknown
320 0 ignored
321 0 versioned subdirectories
322@@ -275,6 +278,7 @@
323 0 added
324 0 removed
325 0 renamed
326+ 0 copied
327 0 unknown
328 0 ignored
329 0 versioned subdirectories
330@@ -321,6 +325,7 @@
331 0 added
332 0 removed
333 0 renamed
334+ 0 copied
335 0 unknown
336 0 ignored
337 0 versioned subdirectories
338@@ -367,6 +372,7 @@
339 0 added
340 0 removed
341 0 renamed
342+ 0 copied
343 0 unknown
344 0 ignored
345 0 versioned subdirectories
346@@ -415,6 +421,7 @@
347 0 added
348 0 removed
349 0 renamed
350+ 0 copied
351 0 unknown
352 0 ignored
353 0 versioned subdirectories
354@@ -459,6 +466,7 @@
355 0 added
356 0 removed
357 0 renamed
358+ 0 copied
359 0 unknown
360 0 ignored
361 0 versioned subdirectories
362@@ -501,6 +509,7 @@
363 0 added
364 0 removed
365 0 renamed
366+ 0 copied
367 0 unknown
368 0 ignored
369 0 versioned subdirectories
370@@ -543,6 +552,7 @@
371 0 added
372 0 removed
373 0 renamed
374+ 0 copied
375 0 unknown
376 0 ignored
377 0 versioned subdirectories
378@@ -686,6 +696,7 @@
379 0 added
380 0 removed
381 0 renamed
382+ 0 copied
383 0 unknown
384 0 ignored
385 0 versioned subdirectories
386@@ -729,6 +740,7 @@
387 0 added
388 0 removed
389 0 renamed
390+ 0 copied
391 0 unknown
392 0 ignored
393 0 versioned subdirectories
394@@ -769,6 +781,7 @@
395 1 added
396 0 removed
397 0 renamed
398+ 0 copied
399 0 unknown
400 0 ignored
401 0 versioned subdirectories
402@@ -816,6 +829,7 @@
403 0 added
404 0 removed
405 0 renamed
406+ 0 copied
407 0 unknown
408 0 ignored
409 0 versioned subdirectories
410@@ -941,6 +955,7 @@
411 0 added
412 0 removed
413 0 renamed
414+ 0 copied
415 0 unknown
416 0 ignored
417 0 versioned subdirectories
418@@ -984,6 +999,7 @@
419 0 added
420 0 removed
421 0 renamed
422+ 0 copied
423 0 unknown
424 0 ignored
425 0 versioned subdirectories
426@@ -1028,6 +1044,7 @@
427 0 added
428 0 removed
429 0 renamed
430+ 0 copied
431 0 unknown
432 0 ignored
433 0 versioned subdirectories
434@@ -1070,6 +1087,7 @@
435 0 added
436 0 removed
437 0 renamed
438+ 0 copied
439 0 unknown
440 0 ignored
441 0 versioned subdirectories
442@@ -1165,6 +1183,7 @@
443 0 added
444 0 removed
445 0 renamed
446+ 0 copied
447 0 unknown
448 0 ignored
449 0 versioned subdirectories
450@@ -1348,6 +1367,7 @@
451 0 added
452 0 removed
453 0 renamed
454+ 0 copied
455 0 unknown
456 0 ignored
457 0 versioned subdirectories
458@@ -1498,6 +1518,7 @@
459 0 added
460 0 removed
461 0 renamed
462+ 0 copied
463 0 unknown
464 0 ignored
465 0 versioned subdirectories
466
467=== modified file 'breezy/tests/per_intertree/test_compare.py'
468--- breezy/tests/per_intertree/test_compare.py 2019-08-11 13:33:45 +0000
469+++ breezy/tests/per_intertree/test_compare.py 2019-09-21 23:05:30 +0000
470@@ -82,6 +82,7 @@
471 self.assertEqual([], d.modified)
472 self.assertEqual([], d.removed)
473 self.assertEqual([], d.renamed)
474+ self.assertEqual([], d.copied)
475 self.assertEqual([], d.unchanged)
476
477 def test_empty_to_abc_content(self):
478@@ -98,6 +99,7 @@
479 self.assertEqual([], d.modified)
480 self.assertEqual([], d.removed)
481 self.assertEqual([], d.renamed)
482+ self.assertEqual([], d.copied)
483 self.assertEqual([], d.unchanged)
484
485 def test_dangling(self):
486@@ -125,6 +127,7 @@
487 self.assertEqual([], d.modified)
488 self.assertEqual([], d.removed)
489 self.assertEqual([], d.renamed)
490+ self.assertEqual([], d.copied)
491 self.assertEqual([], d.unchanged)
492
493 def test_abc_content_to_empty(self):
494@@ -142,6 +145,7 @@
495 ('b/c', 'file'),
496 ], [(c.path[0], c.kind[0]) for c in d.removed])
497 self.assertEqual([], d.renamed)
498+ self.assertEqual([], d.copied)
499 self.assertEqual([], d.unchanged)
500
501 def test_content_modification(self):
502@@ -159,6 +163,7 @@
503 for c in d.modified])
504 self.assertEqual([], d.removed)
505 self.assertEqual([], d.renamed)
506+ self.assertEqual([], d.copied)
507 self.assertEqual([], d.unchanged)
508
509 def test_meta_modification(self):
510@@ -176,6 +181,7 @@
511 for c in d.modified])
512 self.assertEqual([], d.removed)
513 self.assertEqual([], d.renamed)
514+ self.assertEqual([], d.copied)
515 self.assertEqual([], d.unchanged)
516
517 def test_file_rename(self):
518@@ -189,6 +195,7 @@
519 self.assertEqual([], d.added)
520 self.assertEqual([], d.modified)
521 self.assertEqual([], d.removed)
522+ self.assertEqual([], d.copied)
523 self.assertEqual(
524 [('a', 'd', 'file', False, False)],
525 [(c.path[0], c.path[1], c.kind[1], c.changed_content, c.meta_modified())
526@@ -206,6 +213,7 @@
527 self.assertEqual([], d.added)
528 self.assertEqual([], d.modified)
529 self.assertEqual([], d.removed)
530+ self.assertEqual([], d.copied)
531 self.assertEqual(
532 [('a', 'd', 'file', True, False)],
533 [(c.path[0], c.path[1], c.kind[1], c.changed_content, c.meta_modified())
534@@ -227,6 +235,7 @@
535 [('b/c', 'e', 'file', False, True)],
536 [(c.path[0], c.path[1], c.kind[1], c.changed_content, c.meta_modified())
537 for c in d.renamed])
538+ self.assertEqual([], d.copied)
539 self.assertEqual([], d.unchanged)
540
541 def test_empty_to_abc_content_a_only(self):
542@@ -243,6 +252,7 @@
543 self.assertEqual([], d.modified)
544 self.assertEqual([], d.removed)
545 self.assertEqual([], d.renamed)
546+ self.assertEqual([], d.copied)
547 self.assertEqual([], d.unchanged)
548
549 def test_empty_to_abc_content_a_and_c_only(self):
550@@ -261,6 +271,7 @@
551 self.assertEqual([], d.modified)
552 self.assertEqual([], d.removed)
553 self.assertEqual([], d.renamed)
554+ self.assertEqual([], d.copied)
555 self.assertEqual([], d.unchanged)
556
557 def test_empty_to_abc_content_c_only(self):
558@@ -277,6 +288,7 @@
559 self.assertEqual([], d.modified)
560 self.assertEqual([], d.removed)
561 self.assertEqual([], d.renamed)
562+ self.assertEqual([], d.copied)
563 self.assertEqual([], d.unchanged)
564
565 def test_empty_to_abc_content_b_only(self):
566@@ -293,6 +305,7 @@
567 self.assertEqual([], d.modified)
568 self.assertEqual([], d.removed)
569 self.assertEqual([], d.renamed)
570+ self.assertEqual([], d.copied)
571 self.assertEqual([], d.unchanged)
572
573 def test_unchanged_with_renames_and_modifications(self):
574@@ -312,6 +325,7 @@
575 self.assertEqual(
576 [(u'b', 'directory'), (u'b/c', 'file')],
577 [(c.path[0], c.kind[0]) for c in d.unchanged])
578+ self.assertEqual([], d.copied)
579
580 def test_extra_trees_finds_ids(self):
581 """Ask for a delta between two trees with a path present in a third."""
582@@ -345,6 +359,7 @@
583 [(c.path[1], c.kind[1], c.changed_content, c.meta_modified()) for c in d.modified])
584 self.assertEqual([], d.removed)
585 self.assertEqual([], d.renamed)
586+ self.assertEqual([], d.copied)
587 self.assertEqual([], d.unchanged)
588
589 def test_require_versioned(self):
590@@ -380,6 +395,7 @@
591 for c in d.modified])
592 self.assertEqual([], d.removed)
593 self.assertEqual([], d.renamed)
594+ self.assertEqual([], d.copied)
595 self.assertEqual([], d.unchanged)
596 self.assertEqual([], d.unversioned)
597
598@@ -400,6 +416,7 @@
599 self.assertEqual([], d.modified)
600 self.assertEqual([], d.removed)
601 self.assertEqual([], d.renamed)
602+ self.assertEqual([], d.copied)
603 self.assertEqual([], d.unchanged)
604 expected_unversioned = [(u'dir', 'directory'),
605 (u'file', 'file')]
606@@ -765,7 +782,7 @@
607 root_id = tree1.path2id('')
608 self.assertEqual([(b'a-id', ('a', 'a'), True, (True, True),
609 (root_id, root_id), ('a', 'a'),
610- ('file', 'file'), (False, False))],
611+ ('file', 'file'), (False, False), False)],
612 self.do_iter_changes(tree1, tree2))
613 self.check_has_changes(True, tree1, tree2)
614
615@@ -777,7 +794,7 @@
616 tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
617 self.assertEqual([(b'c-id', ('b/c', 'b/c'), False, (True, True),
618 (b'b-id', b'b-id'), ('c', 'c'), ('file', 'file'),
619- (False, True))],
620+ (False, True), False)],
621 self.do_iter_changes(tree1, tree2))
622
623 def test_empty_dir(self):
624@@ -803,7 +820,7 @@
625 root_id = tree1.path2id('')
626 self.assertEqual([(tree1.path2id('a'), ('a', 'd'), False, (True, True),
627 (root_id, root_id), ('a', 'd'), ('file', 'file'),
628- (False, False))],
629+ (False, False), False)],
630 self.do_iter_changes(tree1, tree2))
631
632 def test_file_rename_and_modification(self):
633@@ -815,7 +832,7 @@
634 root_id = tree1.path2id('')
635 self.assertEqual([(b'a-id', ('a', 'd'), True, (True, True),
636 (root_id, root_id), ('a', 'd'), ('file', 'file'),
637- (False, False))],
638+ (False, False), False)],
639 self.do_iter_changes(tree1, tree2))
640
641 def test_specific_content_modification_grabs_parents(self):
642@@ -1030,7 +1047,7 @@
643 root_id = tree1.path2id('')
644 self.assertEqual([(b'c-id', ('b/c', 'e'), False, (True, True),
645 (b'b-id', root_id), ('c', 'e'), ('file', 'file'),
646- (False, True))],
647+ (False, True), False)],
648 self.do_iter_changes(tree1, tree2))
649
650 def test_file_becomes_unversionable_bug_438569(self):
651
652=== modified file 'breezy/tests/per_repository_vf/test_fileid_involved.py'
653--- breezy/tests/per_repository_vf/test_fileid_involved.py 2019-08-11 13:33:45 +0000
654+++ breezy/tests/per_repository_vf/test_fileid_involved.py 2019-09-21 23:05:30 +0000
655@@ -138,7 +138,8 @@
656
657 l2 = [change.file_id for change in delta.added] + \
658 [change.file_id for change in delta.renamed] + \
659- [change.file_id for change in delta.modified]
660+ [change.file_id for change in delta.modified] + \
661+ [change.file_id for change in delta.copied]
662 return set(l2)
663
664
665
666=== modified file 'breezy/tests/per_workingtree/test_changes_from.py'
667--- breezy/tests/per_workingtree/test_changes_from.py 2018-11-11 04:08:32 +0000
668+++ breezy/tests/per_workingtree/test_changes_from.py 2019-09-21 23:05:30 +0000
669@@ -37,6 +37,7 @@
670 self.assertEqual([], d.added)
671 self.assertEqual([], d.removed)
672 self.assertEqual([], d.renamed)
673+ self.assertEqual([], d.copied)
674 self.assertEqual([], d.modified)
675
676 def test_unknown_specific_file(self):
677@@ -51,4 +52,5 @@
678 self.assertEqual([], d.added)
679 self.assertEqual([], d.removed)
680 self.assertEqual([], d.renamed)
681+ self.assertEqual([], d.copied)
682 self.assertEqual([], d.modified)
683
684=== modified file 'breezy/tests/test_delta.py'
685--- breezy/tests/test_delta.py 2019-06-29 19:50:18 +0000
686+++ breezy/tests/test_delta.py 2019-09-21 23:05:30 +0000
687@@ -32,10 +32,10 @@
688 def __init__(self):
689 self.calls = []
690
691- def report(self, path, versioned, renamed, modified, exe_change,
692+ def report(self, path, versioned, renamed, copied, modified, exe_change,
693 kind):
694 self.calls.append(
695- (path, versioned, renamed, modified, exe_change, kind))
696+ (path, versioned, renamed, copied, modified, exe_change, kind))
697
698
699 class TestReportChanges(tests.TestCase):
700@@ -43,7 +43,7 @@
701
702 def assertReport(self, expected, file_id=b'fid', path='path',
703 versioned_change='unchanged', renamed=False,
704- modified='unchanged', exe_change=False,
705+ copied=False, modified='unchanged', exe_change=False,
706 kind=('file', 'file'), old_path=None,
707 unversioned_filter=None, view_info=None):
708 if expected is None:
709@@ -52,12 +52,12 @@
710 expected_lines = [expected]
711 self.assertReportLines(expected_lines, file_id, path,
712 versioned_change, renamed,
713- modified, exe_change,
714+ copied, modified, exe_change,
715 kind, old_path,
716 unversioned_filter, view_info)
717
718 def assertReportLines(self, expected_lines, file_id=b'fid', path='path',
719- versioned_change='unchanged', renamed=False,
720+ versioned_change='unchanged', renamed=False, copied=False,
721 modified='unchanged', exe_change=False,
722 kind=('file', 'file'), old_path=None,
723 unversioned_filter=None, view_info=None):
724@@ -65,9 +65,10 @@
725
726 def result_line(format, *args):
727 result.append(format % args)
728- reporter = _mod_delta._ChangeReporter(result_line,
729- unversioned_filter=unversioned_filter, view_info=view_info)
730- reporter.report((old_path, path), versioned_change, renamed,
731+ reporter = _mod_delta._ChangeReporter(
732+ result_line, unversioned_filter=unversioned_filter,
733+ view_info=view_info)
734+ reporter.report((old_path, path), versioned_change, renamed, copied,
735 modified, exe_change, kind)
736 if expected_lines is not None:
737 self.assertEqualDiff('\n'.join(expected_lines), '\n'.join(result))
738@@ -158,20 +159,22 @@
739 executable=(False, False),
740 versioned_change='unchanged',
741 renamed=False,
742+ copied=False,
743 modified='unchanged',
744 exe_change=False):
745 reporter = InstrumentedReporter()
746 _mod_delta.report_changes([
747 TreeChange(
748 file_id, paths, content_change, versioned, parent_id,
749- name, kind, executable)], reporter)
750+ name, kind, executable, copied)], reporter)
751 output = reporter.calls[0]
752 self.assertEqual(paths, output[0])
753 self.assertEqual(versioned_change, output[1])
754 self.assertEqual(renamed, output[2])
755- self.assertEqual(modified, output[3])
756- self.assertEqual(exe_change, output[4])
757- self.assertEqual(kind, output[5])
758+ self.assertEqual(copied, output[3])
759+ self.assertEqual(modified, output[4])
760+ self.assertEqual(exe_change, output[5])
761+ self.assertEqual(kind, output[6])
762
763 def test_report_changes(self):
764 """Test change detection of report_changes"""
765
766=== modified file 'breezy/tests/test_missing.py'
767--- breezy/tests/test_missing.py 2019-06-29 19:50:18 +0000
768+++ breezy/tests/test_missing.py 2019-09-21 23:05:30 +0000
769@@ -106,6 +106,7 @@
770 self.assertEqual([('b', 'file')], [(c.path[1], c.kind[1]) for c in delta0.added])
771 self.assertEqual([], delta0.removed)
772 self.assertEqual([], delta0.renamed)
773+ self.assertEqual([], delta0.copied)
774 self.assertEqual([], delta0.modified)
775
776 delta1 = r1.delta
777@@ -113,6 +114,7 @@
778 self.assertEqual([], delta1.added)
779 self.assertEqual([('a', 'file')], [(c.path[0], c.kind[0]) for c in delta1.removed])
780 self.assertEqual([], delta1.renamed)
781+ self.assertEqual([], delta1.copied)
782 self.assertEqual([], delta1.modified)
783
784 delta2 = r2.delta
785@@ -120,6 +122,7 @@
786 self.assertEqual([], delta2.added)
787 self.assertEqual([], delta2.removed)
788 self.assertEqual([], delta2.renamed)
789+ self.assertEqual([], delta2.copied)
790 self.assertEqual(
791 [('b', 'file', True, False)],
792 [(c.path[1], c.kind[1], c.changed_content, c.meta_modified()) for c in delta2.modified])
793@@ -127,6 +130,7 @@
794 delta3 = r3.delta
795 self.assertNotEqual(None, delta3)
796 self.assertEqual([], delta3.added)
797+ self.assertEqual([], delta3.copied)
798 self.assertEqual([], delta3.removed)
799 self.assertEqual(
800 [('b', 'c', 'file', False, False)],
801
802=== modified file 'breezy/tests/test_transform.py'
803--- breezy/tests/test_transform.py 2019-06-29 13:16:26 +0000
804+++ breezy/tests/test_transform.py 2019-09-21 23:05:30 +0000
805@@ -1147,12 +1147,14 @@
806 self.assertEqual([(b'id-1', ('old', None), False, (True, False),
807 (b'eert_toor', b'eert_toor'),
808 ('old', 'old'), ('file', 'file'),
809- (True, True))], list(transform.iter_changes()))
810+ (True, True), False)],
811+ list(transform.iter_changes()))
812 transform.new_directory('new', root, b'id-1')
813 self.assertEqual([(b'id-1', ('old', 'new'), True, (True, True),
814 (b'eert_toor', b'eert_toor'), ('old', 'new'),
815 ('file', 'directory'),
816- (True, False))], list(transform.iter_changes()))
817+ (True, False), False)],
818+ list(transform.iter_changes()))
819 finally:
820 transform.finalize()
821
822@@ -1168,7 +1170,7 @@
823 self.assertEqual([(b'id-1', (None, 'old'), False, (False, True),
824 (b'eert_toor', b'eert_toor'),
825 ('old', 'old'), ('file', 'file'),
826- (False, False))],
827+ (False, False), False)],
828 list(transform.iter_changes()))
829 finally:
830 transform.finalize()
831@@ -1192,7 +1194,7 @@
832 self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
833 (b'eert_toor', b'eert_toor'),
834 ('old', 'old'), ('file', None),
835- (False, False))],
836+ (False, False), False)],
837 list(transform.iter_changes()))
838
839 # content change
840@@ -1200,13 +1202,13 @@
841 self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
842 (b'eert_toor', b'eert_toor'),
843 ('old', 'old'), ('file', 'file'),
844- (False, False))],
845+ (False, False), False)],
846 list(transform.iter_changes()))
847 transform.cancel_deletion(old)
848 self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
849 (b'eert_toor', b'eert_toor'),
850 ('old', 'old'), ('file', 'file'),
851- (False, False))],
852+ (False, False), False)],
853 list(transform.iter_changes()))
854 transform.cancel_creation(old)
855
856@@ -1218,7 +1220,7 @@
857 self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
858 (b'eert_toor', b'eert_toor'),
859 ('old', 'old'), ('file', 'file'),
860- (False, False))],
861+ (False, False), False)],
862 list(transform.iter_changes()))
863 transform.cancel_versioning(new)
864 transform._removed_id = set()
865@@ -1229,7 +1231,7 @@
866 self.assertEqual([(b'id-1', ('old', 'old'), False, (True, True),
867 (b'eert_toor', b'eert_toor'),
868 ('old', 'old'), ('file', 'file'),
869- (False, True))],
870+ (False, True), False)],
871 list(transform.iter_changes()))
872 transform.set_executability(None, old)
873
874@@ -1240,7 +1242,7 @@
875 self.assertEqual([(b'id-1', ('old', 'new'), False, (True, True),
876 (b'eert_toor', b'eert_toor'),
877 ('old', 'new'), ('file', 'file'),
878- (False, False))],
879+ (False, False), False)],
880 list(transform.iter_changes()))
881 transform._new_name = {}
882
883@@ -1251,7 +1253,7 @@
884 self.assertEqual([(b'id-1', ('old', 'subdir/old'), False,
885 (True, True), (b'eert_toor',
886 b'subdir-id'), ('old', 'old'),
887- ('file', 'file'), (False, False))],
888+ ('file', 'file'), (False, False), False)],
889 list(transform.iter_changes()))
890 transform._new_path = {}
891
892@@ -1277,10 +1279,10 @@
893 self.assertEqual(
894 [(b'id-1', (u'file1', u'file1'), True, (True, True),
895 (b'eert_toor', b'eert_toor'), ('file1', u'file1'),
896- ('file', None), (False, False)),
897+ ('file', None), (False, False), False),
898 (b'id-2', (u'file2', u'file2'), False, (True, True),
899 (b'eert_toor', b'eert_toor'), ('file2', u'file2'),
900- ('file', 'file'), (False, True))],
901+ ('file', 'file'), (False, True), False)],
902 list(transform.iter_changes()))
903 finally:
904 transform.finalize()
905@@ -1303,7 +1305,7 @@
906 (True, True),
907 (b'toor_eert', b'toor_eert'),
908 ('floater', 'flitter'),
909- (None, None), (False, False))],
910+ (None, None), (False, False), False)],
911 list(transform.iter_changes()))
912 finally:
913 transform.finalize()
914@@ -2767,9 +2769,9 @@
915
916 A_ENTRY = (b'a-id', ('a', 'a'), True, (True, True),
917 (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
918- (False, False))
919+ (False, False), False)
920 ROOT_ENTRY = (b'TREE_ROOT', ('', ''), False, (True, True), (None, None),
921- ('', ''), ('directory', 'directory'), (False, False))
922+ ('', ''), ('directory', 'directory'), (False, False), False)
923
924
925 class TestTransformPreview(tests.TestCaseWithTransport):
926@@ -2875,7 +2877,7 @@
927 root = revision_tree.path2id('')
928 self.assertEqual([(b'a-id', ('a', 'a'), True, (True, True),
929 (root, root), ('a', 'a'), ('file', 'file'),
930- (False, False))],
931+ (False, False), False)],
932 list(preview_tree.iter_changes(revision_tree)))
933
934 def test_include_unchanged_succeeds(self):
935
936=== modified file 'breezy/tests/test_workingtree_4.py'
937--- breezy/tests/test_workingtree_4.py 2019-09-21 17:08:09 +0000
938+++ breezy/tests/test_workingtree_4.py 2019-09-21 23:05:30 +0000
939@@ -592,9 +592,9 @@
940 (None, b'root'),
941 (None, u'dir'),
942 (None, 'directory'),
943- (None, False)),
944+ (None, False), False),
945 (b'root', (None, u''), True, (False, True), (None, None),
946- (None, u''), (None, 'directory'), (None, 0))]
947+ (None, u''), (None, 'directory'), (None, False), False)]
948 self.assertEqual(
949 expected,
950 list(tree.iter_changes(tree.basis_tree(), specific_files=['dir'])))
951@@ -613,7 +613,7 @@
952 (b'root', b'root'),
953 ('dir', 'dir'),
954 ('directory', None),
955- (False, False))]
956+ (False, False), False)]
957 self.assertEqual(expected, list(tree.iter_changes(tree.basis_tree())))
958 tree.unlock()
959
960
961=== modified file 'breezy/tree.py'
962--- breezy/tree.py 2019-09-21 17:08:09 +0000
963+++ breezy/tree.py 2019-09-21 23:05:30 +0000
964@@ -134,10 +134,10 @@
965 """Describes the changes between the same item in two different trees."""
966
967 __slots__ = ['file_id', 'path', 'changed_content', 'versioned', 'parent_id',
968- 'name', 'kind', 'executable']
969+ 'name', 'kind', 'executable', 'copied']
970
971 def __init__(self, file_id, path, changed_content, versioned, parent_id,
972- name, kind, executable):
973+ name, kind, executable, copied=False):
974 self.file_id = file_id
975 self.path = path
976 self.changed_content = changed_content
977@@ -146,6 +146,7 @@
978 self.name = name
979 self.kind = kind
980 self.executable = executable
981+ self.copied = copied
982
983 def __repr__(self):
984 return "%s%r" % (self.__class__.__name__, self._as_tuple())
985@@ -155,7 +156,7 @@
986
987 def _as_tuple(self):
988 return (self.file_id, self.path, self.changed_content, self.versioned,
989- self.parent_id, self.name, self.kind, self.executable)
990+ self.parent_id, self.name, self.kind, self.executable, self.copied)
991
992 def __eq__(self, other):
993 if isinstance(other, TreeChange):
994@@ -180,7 +181,8 @@
995 self.file_id, (self.path[0], None), self.changed_content,
996 (self.versioned[0], None), (self.parent_id[0], None),
997 (self.name[0], None), (self.kind[0], None),
998- (self.executable[0], None))
999+ (self.executable[0], None),
1000+ copied=False)
1001
1002
1003 class Tree(object):
1004
1005=== modified file 'breezy/version_info_formats/__init__.py'
1006--- breezy/version_info_formats/__init__.py 2019-06-29 19:50:18 +0000
1007+++ breezy/version_info_formats/__init__.py 2019-09-21 23:05:30 +0000
1008@@ -134,6 +134,10 @@
1009 self._clean = False
1010 self._file_revisions[change.path[1]] = u'renamed from %s' % (
1011 change.path[0],)
1012+ for change in delta.copied:
1013+ self._clean = False
1014+ self._file_revisions[change.path[1]] = u'copied from %s' % (
1015+ change.path[0],)
1016 for change in delta.modified:
1017 self._clean = False
1018 self._file_revisions[change.path[1]] = 'modified'

Subscribers

People subscribed via source and target branches