Merge lp:~jelmer/brz/delta-copied into lp:brz
- delta-copied
- Merge into trunk
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 |
Related bugs: |
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
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
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' |
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.