Merge lp:~jelmer/brz/delta-no-file-ids 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-no-file-ids
Merge into: lp:brz
Diff against target: 1906 lines (+524/-495)
25 files modified
breezy/builtins.py (+4/-4)
breezy/bzr/bundle/bundle_data.py (+5/-1)
breezy/bzr/bundle/serializer/v08.py (+26/-27)
breezy/bzr/bundle/serializer/v09.py (+2/-2)
breezy/delta.py (+65/-91)
breezy/git/tests/test_workingtree.py (+2/-1)
breezy/git/tree.py (+71/-26)
breezy/log.py (+9/-6)
breezy/plugins/fastimport/exporter.py (+35/-37)
breezy/plugins/fastimport/tests/test_generic_processor.py (+5/-5)
breezy/plugins/upload/cmds.py (+60/-62)
breezy/status.py (+2/-2)
breezy/tests/blackbox/test_status.py (+1/-1)
breezy/tests/blackbox/test_versioning.py (+6/-6)
breezy/tests/per_branch/test_commit.py (+73/-88)
breezy/tests/per_intertree/test_compare.py (+64/-44)
breezy/tests/per_repository/test_repository.py (+16/-19)
breezy/tests/per_repository_vf/test_fileid_involved.py (+3/-5)
breezy/tests/test_bundle.py (+1/-6)
breezy/tests/test_delta.py (+35/-32)
breezy/tests/test_log.py (+1/-1)
breezy/tests/test_missing.py (+8/-5)
breezy/tests/test_tree.py (+1/-1)
breezy/tree.py (+8/-0)
breezy/version_info_formats/__init__.py (+21/-23)
To merge this branch: bzr merge lp:~jelmer/brz/delta-no-file-ids
Reviewer Review Type Date Requested Status
Martin Packman Approve
Review via email: mp+369480@code.launchpad.net

Commit message

TreeDelta holds TreeChange objects rather than tuples of various sizes.

Description of the change

TreeDelta holds TreeChange objects rather than tuples of various sizes.

This simplifies some of the code which can now just iterate over multiple
attributes of TreeDelta object. It also means we can easily drop the file id
element in the future.

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

Okay, I think all the changes here make sense to me. Bit of a risk when adapting tuple code but the test coverage should be reasonable?

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 :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
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/builtins.py'
2--- breezy/builtins.py 2019-07-27 22:47:49 +0000
3+++ breezy/builtins.py 2019-09-21 16:12:34 +0000
4@@ -1909,7 +1909,7 @@
5 if new:
6 added = tree.changes_from(tree.basis_tree(),
7 specific_files=file_list).added
8- file_list = sorted([f[0] for f in added], reverse=True)
9+ file_list = sorted([f.path[1] for f in added], reverse=True)
10 if len(file_list) == 0:
11 raise errors.BzrCommandError(gettext('No matching files.'))
12 elif file_list is None:
13@@ -2409,11 +2409,11 @@
14 self.enter_context(tree.lock_read())
15 td = tree.changes_from(tree.basis_tree())
16 self.cleanup_now()
17- for path, id, kind, text_modified, meta_modified in td.modified:
18+ for change in td.modified:
19 if null:
20- self.outf.write(path + '\0')
21+ self.outf.write(change.path[1] + '\0')
22 else:
23- self.outf.write(osutils.quotefn(path) + '\n')
24+ self.outf.write(osutils.quotefn(change.path[1]) + '\n')
25
26
27 class cmd_added(Command):
28
29=== modified file 'breezy/bzr/bundle/bundle_data.py'
30--- breezy/bzr/bundle/bundle_data.py 2019-07-25 23:22:30 +0000
31+++ breezy/bzr/bundle/bundle_data.py 2019-09-21 16:12:34 +0000
32@@ -294,6 +294,9 @@
33 warning('Inventory sha hash mismatch for revision %s. %s'
34 ' != %s' % (revision_id, sha1, rev.inventory_sha1))
35
36+ def _testament(self, revision, tree):
37+ raise NotImplementedError(self._testament)
38+
39 def _validate_revision(self, tree, revision_id):
40 """Make sure all revision entries match their checksum."""
41
42@@ -306,7 +309,8 @@
43 raise AssertionError()
44 if not (rev.revision_id == revision_id):
45 raise AssertionError()
46- sha1 = self._testament_sha1(rev, tree)
47+ testament = self._testament(rev, tree)
48+ sha1 = testament.as_sha1()
49 if sha1 != rev_info.sha1:
50 raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
51 if rev.revision_id in rev_to_sha1:
52
53=== modified file 'breezy/bzr/bundle/serializer/v08.py'
54--- breezy/bzr/bundle/serializer/v08.py 2019-06-30 10:50:40 +0000
55+++ breezy/bzr/bundle/serializer/v08.py 2019-09-21 16:12:34 +0000
56@@ -309,36 +309,35 @@
57
58 delta = new_tree.changes_from(old_tree, want_unchanged=True,
59 include_root=True)
60- for path, file_id, kind in delta.removed:
61- action = Action('removed', [kind, path]).write(self.to_file)
62+ for change in delta.removed:
63+ action = Action('removed', [change.kind[0], change.path[0]]).write(self.to_file)
64
65- for path, file_id, kind in delta.added:
66+ for change in delta.added:
67 action = Action(
68- 'added', [kind, path], [('file-id', file_id.decode('utf-8'))])
69- meta_modified = (kind == 'file' and
70- new_tree.is_executable(path))
71- finish_action(action, file_id, kind, meta_modified, True,
72- DEVNULL, path)
73-
74- for (old_path, new_path, file_id, kind,
75- text_modified, meta_modified) in delta.renamed:
76- action = Action('renamed', [kind, old_path], [(new_path,)])
77- finish_action(action, file_id, kind, meta_modified, text_modified,
78- old_path, new_path)
79-
80- for (path, file_id, kind,
81- text_modified, meta_modified) in delta.modified:
82- action = Action('modified', [kind, path])
83- finish_action(action, file_id, kind, meta_modified, text_modified,
84- path, path)
85-
86- for path, file_id, kind in delta.unchanged:
87- new_rev = new_tree.get_file_revision(path)
88+ 'added', [change.kind[1], change.path[1]],
89+ [('file-id', change.file_id.decode('utf-8'))])
90+ meta_modified = (change.kind[1] == 'file' and
91+ change.executable[1])
92+ finish_action(action, change.file_id, change.kind[1], meta_modified, change.changed_content,
93+ DEVNULL, change.path[1])
94+
95+ for change in delta.renamed:
96+ action = Action('renamed', [change.kind[1], change.path[0]], [(change.path[1],)])
97+ finish_action(action, change.file_id, change.kind[1], change.meta_modified(), change.changed_content,
98+ change.path[0], change.path[1])
99+
100+ for change in delta.modified:
101+ action = Action('modified', [change.kind[1], change.path[1]])
102+ finish_action(action, change.file_id, change.kind[1], change.meta_modified(), change.changed_content,
103+ change.path[0], change.path[1])
104+
105+ for change in delta.unchanged:
106+ new_rev = new_tree.get_file_revision(change.path[1])
107 if new_rev is None:
108 continue
109- old_rev = old_tree.get_file_revision(old_tree.id2path(file_id))
110+ old_rev = old_tree.get_file_revision(change.path[0])
111 if new_rev != old_rev:
112- action = Action('modified', [new_tree.kind(path), path])
113+ action = Action('modified', [change.kind[1], change.path[1]])
114 action.add_utf8_property('last-changed', new_rev)
115 action.write(self.to_file)
116
117@@ -562,5 +561,5 @@
118 testament = StrictTestament.from_revision(repository, revision_id)
119 return testament.as_sha1()
120
121- def _testament_sha1(self, revision, tree):
122- return StrictTestament(revision, tree).as_sha1()
123+ def _testament(self, revision, tree):
124+ return StrictTestament(revision, tree)
125
126=== modified file 'breezy/bzr/bundle/serializer/v09.py'
127--- breezy/bzr/bundle/serializer/v09.py 2019-06-30 10:50:40 +0000
128+++ breezy/bzr/bundle/serializer/v09.py 2019-09-21 16:12:34 +0000
129@@ -66,8 +66,8 @@
130 testament = StrictTestament3.from_revision(repository, revision_id)
131 return testament.as_sha1()
132
133- def _testament_sha1(self, revision, tree):
134- return StrictTestament3(revision, tree).as_sha1()
135+ def _testament(self, revision, tree):
136+ return StrictTestament3(revision, tree)
137
138
139 class BundleReaderV09(BundleReader):
140
141=== modified file 'breezy/delta.py'
142--- breezy/delta.py 2019-06-23 14:08:06 +0000
143+++ breezy/delta.py 2019-09-21 16:12:34 +0000
144@@ -23,27 +23,21 @@
145 from .sixish import (
146 StringIO,
147 )
148+from .tree import TreeChange
149
150
151 class TreeDelta(object):
152 """Describes changes from one tree to another.
153
154- Contains seven lists:
155+ Contains seven lists with TreeChange objects.
156
157 added
158- (path, id, kind)
159 removed
160- (path, id, kind)
161 renamed
162- (oldpath, newpath, id, kind, text_modified, meta_modified)
163 kind_changed
164- (path, id, old_kind, new_kind)
165 modified
166- (path, id, kind, text_modified, meta_modified)
167 unchanged
168- (path, id, kind)
169 unversioned
170- (path, None, kind)
171
172 Each id is listed only once.
173
174@@ -97,20 +91,6 @@
175 or self.renamed
176 or self.kind_changed)
177
178- def touches_file_id(self, file_id):
179- """Return True if file_id is modified by this delta."""
180- for l in self.added, self.removed, self.modified:
181- for v in l:
182- if v[1] == file_id:
183- return True
184- for v in self.renamed:
185- if v[2] == file_id:
186- return True
187- for v in self.kind_changed:
188- if v[1] == file_id:
189- return True
190- return False
191-
192 def get_changes_as_text(self, show_ids=False, show_unchanged=False,
193 short_status=False):
194 output = StringIO()
195@@ -130,7 +110,7 @@
196 require_versioned=require_versioned,
197 want_unversioned=want_unversioned):
198 if change.versioned == (False, False):
199- delta.unversioned.append((change.path[1], None, change.kind[1]))
200+ delta.unversioned.append(change)
201 continue
202 if not include_root and (None, None) == change.parent_id:
203 continue
204@@ -139,47 +119,44 @@
205 for x in range(2))
206 if fully_present[0] != fully_present[1]:
207 if fully_present[1] is True:
208- delta.added.append((change.path[1], change.file_id, change.kind[1]))
209+ delta.added.append(change)
210 else:
211 if change.kind[0] == 'symlink' and not new_tree.supports_symlinks():
212 trace.warning(
213 'Ignoring "%s" as symlinks '
214 'are not supported on this filesystem.' % (change.path[0],))
215 else:
216- delta.removed.append(
217- (change.path[0], change.file_id, change.kind[0]))
218+ delta.removed.append(change)
219 elif fully_present[0] is False:
220- delta.missing.append((change.path[1], change.file_id, change.kind[1]))
221+ delta.missing.append(change)
222 elif change.name[0] != change.name[1] or change.parent_id[0] != change.parent_id[1]:
223 # If the name changes, or the parent_id changes, we have a rename
224 # (if we move a parent, that doesn't count as a rename for the
225 # file)
226- delta.renamed.append(
227- (change.path[0], change.path[1], change.file_id,
228- change.kind[1], change.changed_content,
229- (change.executable[0] != change.executable[1])))
230+ delta.renamed.append(change)
231 elif change.kind[0] != change.kind[1]:
232- delta.kind_changed.append(
233- (change.path[1], change.file_id, change.kind[0], change.kind[1]))
234+ delta.kind_changed.append(change)
235 elif change.changed_content or change.executable[0] != change.executable[1]:
236- delta.modified.append((change.path[1], change.file_id, change.kind[1],
237- change.changed_content,
238- (change.executable[0] != change.executable[1])))
239- else:
240- delta.unchanged.append((change.path[1], change.file_id, change.kind[1]))
241-
242- delta.removed.sort()
243- delta.added.sort()
244- delta.renamed.sort()
245-
246- def missing_key(change):
247- return (change[0] or '', change[1])
248- delta.missing.sort(key=missing_key)
249+ delta.modified.append(change)
250+ else:
251+ delta.unchanged.append(change)
252+
253+ def change_key(change):
254+ if change.path[0] is None:
255+ path = change.path[1]
256+ else:
257+ path = change.path[0]
258+ return (path, change.file_id)
259+
260+ delta.removed.sort(key=change_key)
261+ delta.added.sort(key=change_key)
262+ delta.renamed.sort(key=change_key)
263+ delta.missing.sort(key=change_key)
264 # TODO: jam 20060529 These lists shouldn't need to be sorted
265 # since we added them in alphabetical order.
266- delta.modified.sort()
267- delta.unchanged.sort()
268- delta.unversioned.sort()
269+ delta.modified.sort(key=change_key)
270+ delta.unchanged.sort(key=change_key)
271+ delta.unversioned.sort(key=change_key)
272
273 return delta
274
275@@ -243,11 +220,10 @@
276 self.output("Operating on whole tree but only reporting on "
277 "'%s' view." % (self.view_name,))
278
279- def report(self, file_id, paths, versioned, renamed, modified, exe_change,
280+ def report(self, paths, versioned, renamed, modified, exe_change,
281 kind):
282 """Report one change to a file
283
284- :param file_id: The file_id of the file
285 :param path: The old and new paths as generated by Tree.iter_changes.
286 :param versioned: may be 'added', 'removed', 'unchanged', or
287 'unversioned.
288@@ -333,40 +309,39 @@
289 }
290
291 def path_key(change):
292- if change[1][0] is not None:
293- path = change[1][0]
294+ if change.path[0] is not None:
295+ path = change.path[0]
296 else:
297- path = change[1][1]
298+ path = change.path[1]
299 return osutils.splitpath(path)
300- for (file_id, path, content_change, versioned, parent_id, name, kind,
301- executable) in sorted(change_iterator, key=path_key):
302+ for change in sorted(change_iterator, key=path_key):
303 exe_change = False
304 # files are "renamed" if they are moved or if name changes, as long
305 # as it had a value
306- if None not in name and None not in parent_id and\
307- (name[0] != name[1] or parent_id[0] != parent_id[1]):
308+ if None not in change.name and None not in change.parent_id and\
309+ (change.name[0] != change.name[1] or change.parent_id[0] != change.parent_id[1]):
310 renamed = True
311 else:
312 renamed = False
313- if kind[0] != kind[1]:
314- if kind[0] is None:
315+ if change.kind[0] != change.kind[1]:
316+ if change.kind[0] is None:
317 modified = "created"
318- elif kind[1] is None:
319+ elif change.kind[1] is None:
320 modified = "deleted"
321 else:
322 modified = "kind changed"
323 else:
324- if content_change:
325+ if change.changed_content:
326 modified = "modified"
327- elif kind[0] is None:
328+ elif change.kind[0] is None:
329 modified = "missing"
330 else:
331 modified = "unchanged"
332- if kind[1] == "file":
333- exe_change = (executable[0] != executable[1])
334- versioned_change = versioned_change_map[versioned]
335- reporter.report(file_id, path, versioned_change, renamed, modified,
336- exe_change, kind)
337+ if change.kind[1] == "file":
338+ exe_change = (change.executable[0] != change.executable[1])
339+ versioned_change = versioned_change_map[change.versioned]
340+ reporter.report(change.path, versioned_change, renamed, modified,
341+ exe_change, change.kind)
342
343
344 def report_delta(to_file, delta, short_status=False, show_ids=False,
345@@ -404,17 +379,20 @@
346 return path
347
348 def show_more_renamed(item):
349- (oldpath, file_id, kind,
350- text_modified, meta_modified, newpath) = item
351- dec_new_path = decorate_path(newpath, kind, meta_modified)
352+ dec_new_path = decorate_path(item.path[1], item.kind[1], item.meta_modified())
353 to_file.write(' => %s' % dec_new_path)
354- if text_modified or meta_modified:
355- extra_modified.append((newpath, file_id, kind,
356- text_modified, meta_modified))
357+ if item.changed_content or item.meta_modified():
358+ extra_modified.append(TreeChange(
359+ item.file_id, (item.path[1], item.path[1]),
360+ item.changed_content,
361+ item.versioned,
362+ (item.parent_id[1], item.parent_id[1]),
363+ (item.name[1], item.name[1]),
364+ (item.kind[1], item.kind[1]),
365+ item.executable))
366
367 def show_more_kind_changed(item):
368- (path, file_id, old_kind, new_kind) = item
369- to_file.write(' (%s => %s)' % (old_kind, new_kind))
370+ to_file.write(' (%s => %s)' % (item.kind[0], item.kind[1]))
371
372 def show_path(path, kind, meta_modified,
373 default_format, with_file_id_format):
374@@ -436,35 +414,31 @@
375 prefix = indent + prefix + ' '
376
377 for item in files:
378- path, file_id, kind = item[:3]
379- if (predicate is not None and not predicate(path)):
380+ if item.path[0] is None:
381+ path = item.path[1]
382+ kind = item.kind[1]
383+ else:
384+ path = item.path[0]
385+ kind = item.kind[0]
386+ if predicate is not None and not predicate(path):
387 continue
388 if not header_shown and not short_status:
389 to_file.write(indent + long_status_name + ':\n')
390 header_shown = True
391- meta_modified = None
392- if len(item) == 5:
393- meta_modified = item[4]
394-
395 to_file.write(prefix)
396- show_path(path, kind, meta_modified,
397+ show_path(path, kind, item.meta_modified(),
398 default_format, with_file_id_format)
399 if show_more is not None:
400 show_more(item)
401- if show_ids:
402- to_file.write(' %s' % file_id.decode('utf-8'))
403+ if show_ids and getattr(item, 'file_id', None):
404+ to_file.write(' %s' % item.file_id.decode('utf-8'))
405 to_file.write('\n')
406
407 show_list(delta.removed, 'removed', 'D')
408 show_list(delta.added, 'added', 'A')
409 show_list(delta.missing, 'missing', '!')
410 extra_modified = []
411- # Reorder delta.renamed tuples so that all lists share the same
412- # order for their 3 first fields and that they also begin like
413- # the delta.modified tuples
414- renamed = [(p, i, k, tm, mm, np)
415- for p, np, i, k, tm, mm in delta.renamed]
416- show_list(renamed, 'renamed', 'R', with_file_id_format='%s',
417+ show_list(delta.renamed, 'renamed', 'R', with_file_id_format='%s',
418 show_more=show_more_renamed)
419 show_list(delta.kind_changed, 'kind changed', 'K',
420 with_file_id_format='%s',
421
422=== modified file 'breezy/git/tests/test_workingtree.py'
423--- breezy/git/tests/test_workingtree.py 2019-06-29 15:50:22 +0000
424+++ breezy/git/tests/test_workingtree.py 2019-09-21 16:12:34 +0000
425@@ -35,6 +35,7 @@
426 workingtree as _mod_workingtree,
427 )
428 from ...delta import TreeDelta
429+from ...tree import TreeChange
430 from ..mapping import (
431 default_mapping,
432 )
433@@ -140,7 +141,7 @@
434
435 def test_missing(self):
436 delta = TreeDelta()
437- delta.removed.append(('a', b'git:a', 'file'))
438+ delta.removed.append(TreeChange(b'git:a', ('a', 'a'), False, (True, True), (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', None), (True, False)))
439 changes = [((b'a', b'a'), (stat.S_IFREG | 0o755, 0),
440 (b'a' * 40, b'a' * 40))]
441 self.assertEqual(
442
443=== modified file 'breezy/git/tree.py'
444--- breezy/git/tree.py 2019-07-25 23:22:30 +0000
445+++ breezy/git/tree.py 2019-09-21 16:12:34 +0000
446@@ -699,14 +699,14 @@
447 for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
448 if newpath == b'' and not include_root:
449 continue
450- if oldpath is None:
451+ if oldpath is not None:
452+ oldpath_decoded = oldpath.decode('utf-8')
453+ else:
454 oldpath_decoded = None
455+ if newpath is not None:
456+ newpath_decoded = newpath.decode('utf-8')
457 else:
458- oldpath_decoded = oldpath.decode('utf-8')
459- if newpath is None:
460 newpath_decoded = None
461- else:
462- newpath_decoded = newpath.decode('utf-8')
463 if not (specific_files is None or
464 (oldpath is not None and
465 osutils.is_inside_or_parent_of_any(
466@@ -715,39 +715,74 @@
467 osutils.is_inside_or_parent_of_any(
468 specific_files, newpath_decoded))):
469 continue
470+
471+ if oldpath_decoded is None:
472+ fileid = new_mapping.generate_file_id(newpath_decoded)
473+ oldexe = None
474+ oldkind = None
475+ oldname = None
476+ oldparent = None
477+ oldversioned = False
478+ else:
479+ oldversioned = True
480+ if oldmode:
481+ oldexe = mode_is_executable(oldmode)
482+ oldkind = mode_kind(oldmode)
483+ else:
484+ oldexe = False
485+ oldkind = None
486+ if oldpath_decoded == u'':
487+ oldparent = None
488+ oldname = u''
489+ else:
490+ (oldparentpath, oldname) = osutils.split(oldpath_decoded)
491+ oldparent = old_mapping.generate_file_id(oldparentpath)
492+ fileid = old_mapping.generate_file_id(oldpath_decoded)
493+ if newpath_decoded is None:
494+ newexe = None
495+ newkind = None
496+ newname = None
497+ newparent = None
498+ newversioned = False
499+ else:
500+ newversioned = (newpath_decoded not in target_extras)
501+ if newmode:
502+ newexe = mode_is_executable(newmode)
503+ newkind = mode_kind(newmode)
504+ else:
505+ newexe = False
506+ newkind = None
507+ if newpath_decoded == u'':
508+ newparent = None
509+ newname = u''
510+ else:
511+ newparentpath, newname = osutils.split(newpath_decoded)
512+ newparent = new_mapping.generate_file_id(newparentpath)
513 if old_mapping.is_special_file(oldpath):
514 oldpath = None
515 if new_mapping.is_special_file(newpath):
516 newpath = None
517 if oldpath is None and newpath is None:
518 continue
519+ change = _mod_tree.TreeChange(
520+ fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
521+ (oldversioned, newversioned),
522+ (oldparent, newparent), (oldname, newname),
523+ (oldkind, newkind), (oldexe, newexe))
524 if oldpath is None:
525- added.append((newpath, mode_kind(newmode)))
526+ added.append((newpath, newkind))
527 elif newpath is None or newmode == 0:
528- file_id = old_mapping.generate_file_id(oldpath_decoded)
529- ret.removed.append((oldpath_decoded, file_id, mode_kind(oldmode)))
530+ ret.removed.append(change)
531 elif oldpath != newpath:
532- file_id = old_mapping.generate_file_id(oldpath_decoded)
533- ret.renamed.append(
534- (oldpath_decoded, newpath.decode('utf-8'), file_id,
535- mode_kind(newmode), (oldsha != newsha),
536- (oldmode != newmode)))
537+ ret.renamed.append(change)
538 elif mode_kind(oldmode) != mode_kind(newmode):
539- file_id = new_mapping.generate_file_id(newpath_decoded)
540- ret.kind_changed.append(
541- (newpath_decoded, file_id, mode_kind(oldmode),
542- mode_kind(newmode)))
543+ ret.kind_changed.append(change)
544 elif oldsha != newsha or oldmode != newmode:
545 if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
546 continue
547- file_id = new_mapping.generate_file_id(newpath_decoded)
548- ret.modified.append(
549- (newpath_decoded, file_id, mode_kind(newmode),
550- (oldsha != newsha), (oldmode != newmode)))
551+ ret.modified.append(change)
552 else:
553- file_id = new_mapping.generate_file_id(newpath_decoded)
554- ret.unchanged.append(
555- (newpath_decoded, file_id, mode_kind(newmode)))
556+ ret.unchanged.append(change)
557
558 implicit_dirs = {b''}
559 for path, kind in added:
560@@ -759,11 +794,21 @@
561 if kind == 'directory' and path not in implicit_dirs:
562 continue
563 path_decoded = osutils.normalized_filename(path)[0]
564+ parent_path, basename = osutils.split(path_decoded)
565+ parent_id = new_mapping.generate_file_id(parent_path)
566 if path in target_extras:
567- ret.unversioned.append((path_decoded, None, kind))
568+ ret.unversioned.append(_mod_tree.TreeChange(
569+ None, (None, path_decoded),
570+ True, (False, False), (None, parent_id),
571+ (None, basename), (None, kind), (None, False)))
572 else:
573 file_id = new_mapping.generate_file_id(path_decoded)
574- ret.added.append((path_decoded, file_id, kind))
575+ ret.added.append(
576+ _mod_tree.TreeChange(
577+ file_id, (None, path_decoded), True,
578+ (False, True),
579+ (None, parent_id),
580+ (None, basename), (None, kind), (None, False)))
581
582 return ret
583
584
585=== modified file 'breezy/log.py'
586--- breezy/log.py 2019-07-07 17:22:07 +0000
587+++ breezy/log.py 2019-09-21 16:12:34 +0000
588@@ -1017,12 +1017,12 @@
589 """
590 if stop_on == 'add':
591 for item in delta.added:
592- if item[1] in fileids:
593- fileids.remove(item[1])
594+ if item.file_id in fileids:
595+ fileids.remove(item.file_id)
596 elif stop_on == 'delete':
597 for item in delta.removed:
598- if item[1] in fileids:
599- fileids.remove(item[1])
600+ if item.file_id in fileids:
601+ fileids.remove(item.file_id)
602
603
604 def _make_revision_objects(branch, generate_delta, search, log_rev_iterator):
605@@ -1794,12 +1794,15 @@
606
607 if revision.delta is not None and revision.delta.has_changed():
608 for c in revision.delta.added + revision.delta.removed + revision.delta.modified:
609- path, = c[:1]
610+ if c.path[0] is None:
611+ path = c.path[1]
612+ else:
613+ path = c.path[0]
614 to_file.write('\t* %s:\n' % (path,))
615 for c in revision.delta.renamed:
616 oldpath, newpath = c[:2]
617 # For renamed files, show both the old and the new path
618- to_file.write('\t* %s:\n\t* %s:\n' % (oldpath, newpath))
619+ to_file.write('\t* %s:\n\t* %s:\n' % (c.path[0], c.path[1]))
620 to_file.write('\n')
621
622 if not revision.rev.message:
623
624=== modified file 'breezy/plugins/fastimport/exporter.py'
625--- breezy/plugins/fastimport/exporter.py 2019-02-04 18:52:53 +0000
626+++ breezy/plugins/fastimport/exporter.py 2019-09-21 16:12:34 +0000
627@@ -481,8 +481,7 @@
628
629 changes = tree_new.changes_from(tree_old)
630
631- # Make "modified" have 3-tuples, as added does
632- my_modified = [x[0:3] for x in changes.modified]
633+ my_modified = list(changes.modified)
634
635 # The potential interaction between renames and deletes is messy.
636 # Handle it here ...
637@@ -493,36 +492,36 @@
638 yield cmd
639
640 # Map kind changes to a delete followed by an add
641- for path, id_, kind1, kind2 in changes.kind_changed:
642+ for change in changes.kind_changed:
643 path = self._adjust_path_for_renames(path, renamed, revision_id)
644 # IGC: I don't understand why a delete is needed here.
645 # In fact, it seems harmful? If you uncomment this line,
646 # please file a bug explaining why you needed to.
647 # yield commands.FileDeleteCommand(path)
648- my_modified.append((path, id_, kind2))
649+ my_modified.append(change)
650
651 # Record modifications
652 files_to_get = []
653- for path, id_, kind in changes.added + my_modified + rd_modifies:
654- if kind == 'file':
655+ for change in changes.added + my_modified + rd_modifies:
656+ if change.kind[1] == 'file':
657 files_to_get.append(
658- (path,
659- (path, helpers.kind_to_mode(
660- 'file', tree_new.is_executable(path)))))
661- elif kind == 'symlink':
662+ (change.path[1],
663+ (change.path[1], helpers.kind_to_mode(
664+ 'file', change.executable[1]))))
665+ elif change.kind[1] == 'symlink':
666 yield commands.FileModifyCommand(
667- path.encode("utf-8"),
668+ change.path[1].encode("utf-8"),
669 helpers.kind_to_mode('symlink', False),
670- None, tree_new.get_symlink_target(path))
671- elif kind == 'directory':
672+ None, tree_new.get_symlink_target(change.path[1]))
673+ elif change.kind[1] == 'directory':
674 if not self.plain_format:
675 yield commands.FileModifyCommand(
676- path.encode("utf-8"),
677+ change.path[1].encode("utf-8"),
678 helpers.kind_to_mode('directory', False), None,
679 None)
680 else:
681 self.warning("cannot export '%s' of kind %s yet - ignoring" %
682- (path, kind))
683+ (change.path[1], change.kind[1]))
684 for (path, mode), chunks in tree_new.iter_files_bytes(
685 files_to_get):
686 yield commands.FileModifyCommand(
687@@ -556,37 +555,36 @@
688
689 must_be_renamed = {}
690 old_to_new = {}
691- deleted_paths = set([p for p, _, _ in deletes])
692- for (oldpath, newpath, id_, kind,
693- text_modified, meta_modified) in renames:
694- emit = kind != 'directory' or not self.plain_format
695- if newpath in deleted_paths:
696+ deleted_paths = set([change.path[0] for change in deletes])
697+ for change in renames:
698+ emit = change.kind[1] != 'directory' or not self.plain_format
699+ if change.path[1] in deleted_paths:
700 if emit:
701 file_cmds.append(commands.FileDeleteCommand(
702- newpath.encode("utf-8")))
703- deleted_paths.remove(newpath)
704- if (self.is_empty_dir(tree_old, oldpath)):
705- self.note("Skipping empty dir %s in rev %s" % (oldpath,
706+ change.path[1].encode("utf-8")))
707+ deleted_paths.remove(change.path[1])
708+ if (self.is_empty_dir(tree_old, change.path[0])):
709+ self.note("Skipping empty dir %s in rev %s" % (change.path[0],
710 revision_id))
711 continue
712 # oldpath = self._adjust_path_for_renames(oldpath, renamed,
713 # revision_id)
714- renamed.append([oldpath, newpath])
715- old_to_new[oldpath] = newpath
716+ renamed.append(change.path)
717+ old_to_new[change.path[0]] = change.path[1]
718 if emit:
719 file_cmds.append(
720- commands.FileRenameCommand(oldpath.encode("utf-8"), newpath.encode("utf-8")))
721- if text_modified or meta_modified:
722- modifies.append((newpath, id_, kind))
723+ commands.FileRenameCommand(change.path[0].encode("utf-8"), change.path[1].encode("utf-8")))
724+ if change.changed_content or change.meta_modified():
725+ modifies.append(change)
726
727 # Renaming a directory implies all children must be renamed.
728 # Note: changes_from() doesn't handle this
729- if kind == 'directory' and tree_old.kind(oldpath) == 'directory':
730- for p, e in tree_old.iter_entries_by_dir(specific_files=[oldpath]):
731+ if kind == 'directory' and tree_old.kind(change.path[0]) == 'directory':
732+ for p, e in tree_old.iter_entries_by_dir(specific_files=[change.path[0]]):
733 if e.kind == 'directory' and self.plain_format:
734 continue
735- old_child_path = osutils.pathjoin(oldpath, p)
736- new_child_path = osutils.pathjoin(newpath, p)
737+ old_child_path = osutils.pathjoin(change.path[0], p)
738+ new_child_path = osutils.pathjoin(change.path[1], p)
739 must_be_renamed[old_child_path] = new_child_path
740
741 # Add children not already renamed
742@@ -602,13 +600,13 @@
743 new_child_path.encode("utf-8")))
744
745 # Record remaining deletes
746- for path, id_, kind in deletes:
747- if path not in deleted_paths:
748+ for change in deletes:
749+ if change.path[0] not in deleted_paths:
750 continue
751- if kind == 'directory' and self.plain_format:
752+ if change.kind[0] == 'directory' and self.plain_format:
753 continue
754 #path = self._adjust_path_for_renames(path, renamed, revision_id)
755- file_cmds.append(commands.FileDeleteCommand(path.encode("utf-8")))
756+ file_cmds.append(commands.FileDeleteCommand(change.path[0].encode("utf-8")))
757 return file_cmds, modifies, renamed
758
759 def _adjust_path_for_renames(self, path, renamed, revision_id):
760
761=== modified file 'breezy/plugins/fastimport/tests/test_generic_processor.py'
762--- breezy/plugins/fastimport/tests/test_generic_processor.py 2018-11-11 04:08:32 +0000
763+++ breezy/plugins/fastimport/tests/test_generic_processor.py 2019-09-21 16:12:34 +0000
764@@ -132,7 +132,7 @@
765 if expected_renamed is not None:
766 self.assertEquals(len(renamed), len(expected_renamed),
767 "%s is renamed, expected %s" % (renamed, expected_renamed))
768- renamed_files = [(item[0], item[1]) for item in renamed]
769+ renamed_files = [(item.path[0], item.path[1]) for item in renamed]
770 for expected_renamed_entry in expected_renamed:
771 expected_renamed_entry = (
772 expected_renamed_entry[0].decode('utf-8'),
773@@ -143,7 +143,7 @@
774 if expected_added is not None:
775 self.assertEquals(len(added), len(expected_added),
776 "%s is added" % str(added))
777- added_files = [(item[0],) for item in added]
778+ added_files = [(item.path[1],) for item in added]
779 for expected_added_entry in expected_added:
780 expected_added_entry = (
781 expected_added_entry[0].decode('utf-8'), )
782@@ -153,7 +153,7 @@
783 if expected_removed is not None:
784 self.assertEquals(len(removed), len(expected_removed),
785 "%s is removed" % str(removed))
786- removed_files = [(item[0],) for item in removed]
787+ removed_files = [(item.path[0],) for item in removed]
788 for expected_removed_entry in expected_removed:
789 expected_removed_entry = (
790 expected_removed_entry[0].decode('utf-8'), )
791@@ -163,7 +163,7 @@
792 if expected_modified is not None:
793 self.assertEquals(len(modified), len(expected_modified),
794 "%s is modified" % str(modified))
795- modified_files = [(item[0],) for item in modified]
796+ modified_files = [(item.path[1],) for item in modified]
797 for expected_modified_entry in expected_modified:
798 expected_modified_entry = (
799 expected_modified_entry[0].decode('utf-8'), )
800@@ -174,7 +174,7 @@
801 self.assertEquals(len(kind_changed), len(expected_kind_changed),
802 "%s is kind-changed, expected %s" % (kind_changed,
803 expected_kind_changed))
804- kind_changed_files = [(item[0], item[2], item[3])
805+ kind_changed_files = [(item.path[1], item.kind[0], item.kind[1])
806 for item in kind_changed]
807 for expected_kind_changed_entry in expected_kind_changed:
808 expected_kind_changed_entry = (
809
810=== modified file 'breezy/plugins/upload/cmds.py'
811--- breezy/plugins/upload/cmds.py 2019-06-29 19:54:32 +0000
812+++ breezy/plugins/upload/cmds.py 2019-09-21 16:12:34 +0000
813@@ -364,89 +364,87 @@
814 # --create-prefix option ?)
815 changes = self.tree.changes_from(from_tree)
816 with self.tree.lock_read():
817- for (path, id, kind) in changes.removed:
818- if self.is_ignored(path):
819+ for change in changes.removed:
820+ if self.is_ignored(change.path[0]):
821 if not self.quiet:
822- self.outf.write('Ignoring %s\n' % path)
823+ self.outf.write('Ignoring %s\n' % change.path[0])
824 continue
825- if kind == 'file':
826- self.delete_remote_file(path)
827- elif kind == 'directory':
828- self.delete_remote_dir_maybe(path)
829- elif kind == 'symlink':
830- self.delete_remote_file(path)
831+ if change.kind[0] == 'file':
832+ self.delete_remote_file(change.path[0])
833+ elif change.kind[0] == 'directory':
834+ self.delete_remote_dir_maybe(change.path[0])
835+ elif change.kind[0] == 'symlink':
836+ self.delete_remote_file(change.path[0])
837 else:
838 raise NotImplementedError
839
840- for (old_path, new_path, id, kind,
841- content_change, exec_change) in changes.renamed:
842- if self.is_ignored(old_path) and self.is_ignored(new_path):
843+ for change in changes.renamed:
844+ if self.is_ignored(change.path[0]) and self.is_ignored(change.path[1]):
845 if not self.quiet:
846- self.outf.write('Ignoring %s\n' % old_path)
847- self.outf.write('Ignoring %s\n' % new_path)
848+ self.outf.write('Ignoring %s\n' % change.path[0])
849+ self.outf.write('Ignoring %s\n' % change.path[1])
850 continue
851- if content_change:
852- # We update the old_path content because renames and
853+ if change.changed_content:
854+ # We update the change.path[0] content because renames and
855 # deletions are differed.
856- self.upload_file(old_path, new_path)
857- self.rename_remote(old_path, new_path)
858+ self.upload_file(change.path[0], change.path[1])
859+ self.rename_remote(change.path[0], change.path[1])
860 self.finish_renames()
861 self.finish_deletions()
862
863- for (path, id, old_kind, new_kind) in changes.kind_changed:
864- if self.is_ignored(path):
865- if not self.quiet:
866- self.outf.write('Ignoring %s\n' % path)
867- continue
868- if old_kind in ('file', 'symlink'):
869- self.delete_remote_file(path)
870- elif old_kind == 'directory':
871- self.delete_remote_dir(path)
872- else:
873- raise NotImplementedError
874-
875- if new_kind == 'file':
876- self.upload_file(path, path)
877- elif new_kind == 'symlink':
878- target = self.tree.get_symlink_target(path)
879- self.upload_symlink(path, target)
880- elif new_kind == 'directory':
881- self.make_remote_dir(path)
882- else:
883- raise NotImplementedError
884-
885- for (path, id, kind) in changes.added:
886- if self.is_ignored(path):
887- if not self.quiet:
888- self.outf.write('Ignoring %s\n' % path)
889- continue
890- if kind == 'file':
891- self.upload_file(path, path)
892- elif kind == 'directory':
893- self.make_remote_dir(path)
894- elif kind == 'symlink':
895- target = self.tree.get_symlink_target(path)
896+ for change in changes.kind_changed:
897+ if self.is_ignored(change.path[1]):
898+ if not self.quiet:
899+ self.outf.write('Ignoring %s\n' % change.path[1])
900+ continue
901+ if change.kind[0] in ('file', 'symlink'):
902+ self.delete_remote_file(change.path[0])
903+ elif change.kind[0] == 'directory':
904+ self.delete_remote_dir(change.path[0])
905+ else:
906+ raise NotImplementedError
907+
908+ if change.kind[1] == 'file':
909+ self.upload_file(change.path[1], change.path[1])
910+ elif change.kind[1] == 'symlink':
911+ target = self.tree.get_symlink_target(change.path[1])
912+ self.upload_symlink(change.path[1], target)
913+ elif change.kind[1] == 'directory':
914+ self.make_remote_dir(change.path[1])
915+ else:
916+ raise NotImplementedError
917+
918+ for change in changes.added:
919+ if self.is_ignored(change.path[1]):
920+ if not self.quiet:
921+ self.outf.write('Ignoring %s\n' % change.path[1])
922+ continue
923+ if change.kind[1] == 'file':
924+ self.upload_file(change.path[1], change.path[1])
925+ elif change.kind[1] == 'directory':
926+ self.make_remote_dir(change.path[1])
927+ elif change.kind[1] == 'symlink':
928+ target = self.tree.get_symlink_target(change.path[1])
929 try:
930- self.upload_symlink(path, target)
931+ self.upload_symlink(change.path[1], target)
932 except errors.TransportNotPossible:
933 if not self.quiet:
934 self.outf.write('Not uploading symlink %s -> %s\n'
935- % (path, target))
936+ % (change.path[1], target))
937 else:
938 raise NotImplementedError
939
940 # XXX: Add a test for exec_change
941- for (path, id, kind,
942- content_change, exec_change) in changes.modified:
943- if self.is_ignored(path):
944+ for change in changes.modified:
945+ if self.is_ignored(change.path[1]):
946 if not self.quiet:
947- self.outf.write('Ignoring %s\n' % path)
948+ self.outf.write('Ignoring %s\n' % change.path[1])
949 continue
950- if kind == 'file':
951- self.upload_file(path, path)
952- elif kind == 'symlink':
953- target = self.tree.get_symlink_target(path)
954- self.upload_symlink(path, target)
955+ if change.kind[1] == 'file':
956+ self.upload_file(change.path[1], change.path[1])
957+ elif change.kind[1] == 'symlink':
958+ target = self.tree.get_symlink_target(change.path[1])
959+ self.upload_symlink(change.path[1], target)
960 else:
961 raise NotImplementedError
962
963
964=== modified file 'breezy/status.py'
965--- breezy/status.py 2018-12-06 13:38:49 +0000
966+++ breezy/status.py 2019-09-21 16:12:34 +0000
967@@ -76,8 +76,8 @@
968 want_unversioned=want_unversioned)
969 # filter out unknown files. We may want a tree method for
970 # this
971- delta.unversioned = [unversioned for unversioned in
972- delta.unversioned if not new.is_ignored(unversioned[0])]
973+ delta.unversioned = [change for change in delta.unversioned
974+ if not new.is_ignored(change.path[1])]
975 show_long_callback(to_file, delta,
976 show_ids=show_ids,
977 show_unchanged=want_unchanged,
978
979=== modified file 'breezy/tests/blackbox/test_status.py'
980--- breezy/tests/blackbox/test_status.py 2019-06-29 19:54:32 +0000
981+++ breezy/tests/blackbox/test_status.py 2019-09-21 16:12:34 +0000
982@@ -716,7 +716,7 @@
983 self.assertStatusContains(
984 'kind changed:\n file \\(file => directory\\)')
985 tree.rename_one('file', 'directory')
986- self.assertStatusContains('renamed:\n file/ => directory/\n'
987+ self.assertStatusContains('renamed:\n file => directory/\n'
988 'modified:\n directory/\n')
989 rmdir('directory')
990 self.assertStatusContains('removed:\n file\n')
991
992=== modified file 'breezy/tests/blackbox/test_versioning.py'
993--- breezy/tests/blackbox/test_versioning.py 2018-11-11 04:08:32 +0000
994+++ breezy/tests/blackbox/test_versioning.py 2019-09-21 16:12:34 +0000
995@@ -57,7 +57,7 @@
996 self.log('delta.added = %r' % delta.added)
997
998 self.assertEqual(len(delta.added), 1)
999- self.assertEqual(delta.added[0][0], 'foo')
1000+ self.assertEqual(delta.added[0].path[1], 'foo')
1001 self.assertFalse(delta.modified)
1002
1003 def test_mkdir_in_subdir(self):
1004@@ -78,8 +78,8 @@
1005 self.log('delta.added = %r' % delta.added)
1006
1007 self.assertEqual(len(delta.added), 2)
1008- self.assertEqual(delta.added[0][0], 'dir')
1009- self.assertEqual(delta.added[1][0], pathjoin('dir', 'subdir'))
1010+ self.assertEqual(delta.added[0].path[1], 'dir')
1011+ self.assertEqual(delta.added[1].path[1], pathjoin('dir', 'subdir'))
1012 self.assertFalse(delta.modified)
1013
1014 def test_mkdir_w_nested_trees(self):
1015@@ -100,17 +100,17 @@
1016
1017 delta = wt.changes_from(wt.basis_tree())
1018 self.assertEqual(len(delta.added), 1)
1019- self.assertEqual(delta.added[0][0], 'dir')
1020+ self.assertEqual(delta.added[0].path[1], 'dir')
1021 self.assertFalse(delta.modified)
1022
1023 delta = wt_a.changes_from(wt_a.basis_tree())
1024 self.assertEqual(len(delta.added), 1)
1025- self.assertEqual(delta.added[0][0], 'dir')
1026+ self.assertEqual(delta.added[0].path[1], 'dir')
1027 self.assertFalse(delta.modified)
1028
1029 delta = wt_b.changes_from(wt_b.basis_tree())
1030 self.assertEqual(len(delta.added), 1)
1031- self.assertEqual(delta.added[0][0], 'dir')
1032+ self.assertEqual(delta.added[0].path[1], 'dir')
1033 self.assertFalse(delta.modified)
1034
1035 def test_mkdir_quiet(self):
1036
1037=== modified file 'breezy/tests/per_branch/test_commit.py'
1038--- breezy/tests/per_branch/test_commit.py 2018-11-11 04:08:32 +0000
1039+++ breezy/tests/per_branch/test_commit.py 2019-09-21 16:12:34 +0000
1040@@ -110,82 +110,84 @@
1041
1042 def test_post_commit_not_to_origin(self):
1043 tree = self.make_branch_and_memory_tree('branch')
1044- tree.lock_write()
1045- tree.add('')
1046- revid = tree.commit('first revision')
1047- branch.Branch.hooks.install_named_hook(
1048- 'post_commit', self.capture_post_commit_hook, None)
1049- revid2 = tree.commit('second revision')
1050- # having committed from up the branch, we should get the
1051- # before and after revnos and revids correctly.
1052- self.assertEqual([
1053- ('post_commit', None, tree.branch.base, 1, revid, 2, revid2,
1054- None, True)
1055- ],
1056- self.hook_calls)
1057- tree.unlock()
1058+ with tree.lock_write():
1059+ tree.add('')
1060+ revid = tree.commit('first revision')
1061+ branch.Branch.hooks.install_named_hook(
1062+ 'post_commit', self.capture_post_commit_hook, None)
1063+ revid2 = tree.commit('second revision')
1064+ # having committed from up the branch, we should get the
1065+ # before and after revnos and revids correctly.
1066+ self.assertEqual([
1067+ ('post_commit', None, tree.branch.base, 1, revid, 2, revid2,
1068+ None, True)
1069+ ],
1070+ self.hook_calls)
1071+
1072+ def get_rootfull_delta(self, repository, revid):
1073+ tree = repository.revision_tree(revid)
1074+ with repository.lock_read():
1075+ parent_revid = repository.get_parent_map([revid])[revid][0]
1076+ basis_tree = repository.revision_tree(parent_revid)
1077+ tree = repository.revision_tree(revid)
1078+ return tree.changes_from(basis_tree, include_root=True)
1079
1080 def test_pre_commit_passes(self):
1081- empty_delta = delta.TreeDelta()
1082- root_delta = delta.TreeDelta()
1083 tree = self.make_branch_and_memory_tree('branch')
1084- tree.lock_write()
1085- tree.add('')
1086- root_delta.added = [('', tree.path2id(''), 'directory')]
1087- branch.Branch.hooks.install_named_hook(
1088- "pre_commit", self.capture_pre_commit_hook, None)
1089- revid1 = tree.commit('first revision')
1090- revid2 = tree.commit('second revision')
1091- self.assertEqual([
1092- ('pre_commit', 0, revision.NULL_REVISION, 1, revid1, root_delta),
1093- ('pre_commit', 1, revid1, 2, revid2, empty_delta)
1094- ],
1095- self.hook_calls)
1096- tree.unlock()
1097+ with tree.lock_write():
1098+ tree.add('')
1099+ branch.Branch.hooks.install_named_hook(
1100+ "pre_commit", self.capture_pre_commit_hook, None)
1101+ revid1 = tree.commit('first revision')
1102+ revid2 = tree.commit('second revision')
1103+ root_delta = self.get_rootfull_delta(tree.branch.repository, revid1)
1104+ empty_delta = tree.branch.repository.get_revision_delta(revid2)
1105+ self.assertEqual([
1106+ ('pre_commit', 0, revision.NULL_REVISION, 1, revid1, root_delta),
1107+ ('pre_commit', 1, revid1, 2, revid2, empty_delta)
1108+ ],
1109+ self.hook_calls)
1110
1111 def test_pre_commit_fails(self):
1112- empty_delta = delta.TreeDelta()
1113- root_delta = delta.TreeDelta()
1114 tree = self.make_branch_and_memory_tree('branch')
1115- tree.lock_write()
1116- tree.add('')
1117- root_delta.added = [('', tree.path2id(''), 'directory')]
1118-
1119- class PreCommitException(Exception):
1120-
1121- def __init__(self, revid):
1122- self.revid = revid
1123-
1124- def hook_func(local, master,
1125- old_revno, old_revid, new_revno, new_revid,
1126- tree_delta, future_tree):
1127- raise PreCommitException(new_revid)
1128- branch.Branch.hooks.install_named_hook(
1129- "pre_commit", self.capture_pre_commit_hook, None)
1130- branch.Branch.hooks.install_named_hook("pre_commit", hook_func, None)
1131- revids = [None, None, None]
1132- # this commit will raise an exception
1133- # so the commit is rolled back and revno unchanged
1134- err = self.assertRaises(PreCommitException, tree.commit, 'message')
1135- # we have to record the revid to use in assertEqual later
1136- revids[0] = err.revid
1137- # unregister all pre_commit hooks
1138- branch.Branch.hooks["pre_commit"] = []
1139- # and re-register the capture hook
1140- branch.Branch.hooks.install_named_hook(
1141- "pre_commit", self.capture_pre_commit_hook, None)
1142- # now these commits should go through
1143- for i in range(1, 3):
1144- revids[i] = tree.commit('message')
1145- self.assertEqual([
1146- ('pre_commit', 0, revision.NULL_REVISION,
1147- 1, revids[0], root_delta),
1148- ('pre_commit', 0, revision.NULL_REVISION,
1149- 1, revids[1], root_delta),
1150- ('pre_commit', 1, revids[1], 2, revids[2], empty_delta)
1151- ],
1152- self.hook_calls)
1153- tree.unlock()
1154+ with tree.lock_write():
1155+ tree.add('')
1156+
1157+ class PreCommitException(Exception):
1158+
1159+ def __init__(self, revid):
1160+ self.revid = revid
1161+
1162+ def hook_func(local, master,
1163+ old_revno, old_revid, new_revno, new_revid,
1164+ tree_delta, future_tree):
1165+ raise PreCommitException(new_revid)
1166+ branch.Branch.hooks.install_named_hook(
1167+ "pre_commit", self.capture_pre_commit_hook, None)
1168+ branch.Branch.hooks.install_named_hook("pre_commit", hook_func, None)
1169+ revids = [None, None, None]
1170+ # this commit will raise an exception
1171+ # so the commit is rolled back and revno unchanged
1172+ err = self.assertRaises(PreCommitException, tree.commit, 'message')
1173+ # we have to record the revid to use in assertEqual later
1174+ revids[0] = err.revid
1175+ # unregister all pre_commit hooks
1176+ branch.Branch.hooks["pre_commit"] = []
1177+ # and re-register the capture hook
1178+ branch.Branch.hooks.install_named_hook(
1179+ "pre_commit", self.capture_pre_commit_hook, None)
1180+ # now these commits should go through
1181+ for i in range(1, 3):
1182+ revids[i] = tree.commit('message')
1183+ self.assertEqual([
1184+ ('pre_commit', 0, revision.NULL_REVISION,
1185+ 1, revids[0], self.get_rootfull_delta(tree.branch.repository, revids[0])),
1186+ ('pre_commit', 0, revision.NULL_REVISION,
1187+ 1, revids[1], self.get_rootfull_delta(tree.branch.repository, revids[1])),
1188+ ('pre_commit', 1, revids[1], 2, revids[2],
1189+ self.get_rootfull_delta(tree.branch.repository, revids[2]))
1190+ ],
1191+ self.hook_calls)
1192
1193 def test_pre_commit_delta(self):
1194 # This tests the TreeDelta object passed to pre_commit hook.
1195@@ -219,22 +221,5 @@
1196 "pre_commit", self.capture_pre_commit_hook, None)
1197 revid2 = tree.commit('second revision')
1198
1199- expected_delta = delta.TreeDelta()
1200- if tree.has_versioned_directories():
1201- expected_delta.added.append(
1202- ('added_dir', added_dir_id, 'directory'))
1203- if tree.supports_rename_tracking():
1204- expected_delta.removed = [('to_be_unversioned',
1205- to_be_unversioned_id, 'file')]
1206- expected_delta.renamed = [('dir/subfile', 'dir/subfile_renamed',
1207- dir_subfile_id, 'file', False, False)]
1208- else:
1209- expected_delta.added.append(('dir/subfile_renamed',
1210- tree.path2id('dir/subfile_renamed'), 'file'))
1211- expected_delta.removed = [
1212- ('dir/subfile', dir_subfile_id, 'file'),
1213- ('to_be_unversioned', to_be_unversioned_id, 'file')]
1214- expected_delta.modified = [('rootfile', rootfile_id, 'file', True,
1215- False)]
1216 self.assertEqual([('pre_commit', 1, revid1, 2, revid2,
1217- expected_delta)], self.hook_calls)
1218+ self.get_rootfull_delta(tree.branch.repository, revid2))], self.hook_calls)
1219
1220=== modified file 'breezy/tests/per_intertree/test_compare.py'
1221--- breezy/tests/per_intertree/test_compare.py 2019-06-29 13:16:26 +0000
1222+++ breezy/tests/per_intertree/test_compare.py 2019-09-21 16:12:34 +0000
1223@@ -92,10 +92,9 @@
1224 tree2 = self.get_tree_no_parents_abc_content(tree2)
1225 tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
1226 d = self.intertree_class(tree1, tree2).compare()
1227- self.assertEqual([('a', b'a-id', 'file'),
1228- ('b', b'b-id', 'directory'),
1229- ('b/c', b'c-id', 'file'),
1230- ], d.added)
1231+ self.assertEqual(
1232+ [('a', 'file'), ('b', 'directory'), ('b/c', 'file')],
1233+ [(c.path[1], c.kind[1]) for c in d.added])
1234 self.assertEqual([], d.modified)
1235 self.assertEqual([], d.removed)
1236 self.assertEqual([], d.renamed)
1237@@ -138,10 +137,10 @@
1238 d = self.intertree_class(tree1, tree2).compare()
1239 self.assertEqual([], d.added)
1240 self.assertEqual([], d.modified)
1241- self.assertEqual([('a', tree1.path2id('a'), 'file'),
1242- ('b', tree1.path2id('b'), 'directory'),
1243- ('b/c', tree1.path2id('b/c'), 'file'),
1244- ], d.removed)
1245+ self.assertEqual([('a', 'file'),
1246+ ('b', 'directory'),
1247+ ('b/c', 'file'),
1248+ ], [(c.path[0], c.kind[0]) for c in d.removed])
1249 self.assertEqual([], d.renamed)
1250 self.assertEqual([], d.unchanged)
1251
1252@@ -155,7 +154,9 @@
1253 d = self.intertree_class(tree1, tree2).compare()
1254 self.assertEqual([], d.added)
1255 self.assertEqual(
1256- [('a', tree1.path2id('a'), 'file', True, False)], d.modified)
1257+ [('a', 'file', True, False)],
1258+ [(c.path[1], c.kind[1], c.changed_content, c.meta_modified())
1259+ for c in d.modified])
1260 self.assertEqual([], d.removed)
1261 self.assertEqual([], d.renamed)
1262 self.assertEqual([], d.unchanged)
1263@@ -170,7 +171,9 @@
1264 d = self.intertree_class(tree1, tree2).compare()
1265 self.assertEqual([], d.added)
1266 self.assertEqual(
1267- [('b/c', tree1.path2id('b/c'), 'file', False, True)], d.modified)
1268+ [('b/c', 'file', False, True)],
1269+ [(c.path[1], c.kind[1], c.changed_content, c.meta_modified())
1270+ for c in d.modified])
1271 self.assertEqual([], d.removed)
1272 self.assertEqual([], d.renamed)
1273 self.assertEqual([], d.unchanged)
1274@@ -187,7 +190,9 @@
1275 self.assertEqual([], d.modified)
1276 self.assertEqual([], d.removed)
1277 self.assertEqual(
1278- [('a', 'd', tree1.path2id('a'), 'file', False, False)], d.renamed)
1279+ [('a', 'd', 'file', False, False)],
1280+ [(c.path[0], c.path[1], c.kind[1], c.changed_content, c.meta_modified())
1281+ for c in d.renamed])
1282 self.assertEqual([], d.unchanged)
1283
1284 def test_file_rename_and_modification(self):
1285@@ -202,7 +207,9 @@
1286 self.assertEqual([], d.modified)
1287 self.assertEqual([], d.removed)
1288 self.assertEqual(
1289- [('a', 'd', tree1.path2id('a'), 'file', True, False)], d.renamed)
1290+ [('a', 'd', 'file', True, False)],
1291+ [(c.path[0], c.path[1], c.kind[1], c.changed_content, c.meta_modified())
1292+ for c in d.renamed])
1293 self.assertEqual([], d.unchanged)
1294
1295 def test_file_rename_and_meta_modification(self):
1296@@ -217,7 +224,9 @@
1297 self.assertEqual([], d.modified)
1298 self.assertEqual([], d.removed)
1299 self.assertEqual(
1300- [('b/c', 'e', tree1.path2id('b/c'), 'file', False, True)], d.renamed)
1301+ [('b/c', 'e', 'file', False, True)],
1302+ [(c.path[0], c.path[1], c.kind[1], c.changed_content, c.meta_modified())
1303+ for c in d.renamed])
1304 self.assertEqual([], d.unchanged)
1305
1306 def test_empty_to_abc_content_a_only(self):
1307@@ -228,7 +237,9 @@
1308 tree2 = self.get_tree_no_parents_abc_content(tree2)
1309 tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
1310 d = self.intertree_class(tree1, tree2).compare(specific_files=['a'])
1311- self.assertEqual([('a', tree2.path2id('a'), 'file')], d.added)
1312+ self.assertEqual(
1313+ [('a', 'file')],
1314+ [(c.path[1], c.kind[1]) for c in d.added])
1315 self.assertEqual([], d.modified)
1316 self.assertEqual([], d.removed)
1317 self.assertEqual([], d.renamed)
1318@@ -243,10 +254,10 @@
1319 d = self.intertree_class(tree1, tree2).compare(
1320 specific_files=['a', 'b/c'])
1321 self.assertEqual(
1322- [('a', tree2.path2id('a'), 'file'),
1323- (u'b', tree2.path2id('b'), 'directory'),
1324- ('b/c', tree2.path2id('b/c'), 'file')],
1325- d.added)
1326+ [('a', 'file'),
1327+ (u'b', 'directory'),
1328+ ('b/c', 'file')],
1329+ [(c.path[1], c.kind[1]) for c in d.added])
1330 self.assertEqual([], d.modified)
1331 self.assertEqual([], d.removed)
1332 self.assertEqual([], d.renamed)
1333@@ -261,7 +272,8 @@
1334 d = self.intertree_class(tree1, tree2).compare(
1335 specific_files=['b/c'])
1336 self.assertEqual(
1337- [(u'b', b'b-id', 'directory'), ('b/c', b'c-id', 'file')], d.added)
1338+ [(u'b', 'directory'), ('b/c', 'file')],
1339+ [(c.path[1], c.kind[1]) for c in d.added])
1340 self.assertEqual([], d.modified)
1341 self.assertEqual([], d.removed)
1342 self.assertEqual([], d.renamed)
1343@@ -276,8 +288,8 @@
1344 tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
1345 d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
1346 self.assertEqual(
1347- [('b', b'b-id', 'directory'), ('b/c', b'c-id', 'file')],
1348- d.added)
1349+ [('b', 'directory'), ('b/c', 'file')],
1350+ [(c.path[1], c.kind[1]) for c in d.added])
1351 self.assertEqual([], d.modified)
1352 self.assertEqual([], d.removed)
1353 self.assertEqual([], d.renamed)
1354@@ -294,10 +306,12 @@
1355 self.assertEqual([], d.added)
1356 self.assertEqual([], d.modified)
1357 self.assertEqual([], d.removed)
1358- self.assertEqual([('a', 'd', b'a-id', 'file', True, False)], d.renamed)
1359- self.assertEqual(
1360- [(u'b', b'b-id', 'directory'), (u'b/c', b'c-id', 'file')],
1361- d.unchanged)
1362+ self.assertEqual(
1363+ [('a', 'd', 'file', True, False)],
1364+ [(c.path[0], c.path[1], c.kind[1], c.changed_content, c.meta_modified()) for c in d.renamed])
1365+ self.assertEqual(
1366+ [(u'b', 'directory'), (u'b/c', 'file')],
1367+ [(c.path[0], c.kind[0]) for c in d.unchanged])
1368
1369 def test_extra_trees_finds_ids(self):
1370 """Ask for a delta between two trees with a path present in a third."""
1371@@ -326,7 +340,9 @@
1372 d = self.intertree_class(tree1, tree2).compare(
1373 specific_files=['e'], extra_trees=[tree3])
1374 self.assertEqual([], d.added)
1375- self.assertEqual([('b/c', b'c-id', 'file', False, True)], d.modified)
1376+ self.assertEqual(
1377+ [('b/c', 'file', False, True)],
1378+ [(c.path[1], c.kind[1], c.changed_content, c.meta_modified()) for c in d.modified])
1379 self.assertEqual([], d.removed)
1380 self.assertEqual([], d.renamed)
1381 self.assertEqual([], d.unchanged)
1382@@ -358,8 +374,10 @@
1383 tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
1384 d = self.intertree_class(tree1, tree2).compare()
1385 self.assertEqual([], d.added)
1386- self.assertEqual([(u'a', b'a-id', 'file', True, False),
1387- (u'c', b'c-id', 'file', True, False)], d.modified)
1388+ self.assertEqual([(u'a', 'file', True, False),
1389+ (u'c', 'file', True, False)],
1390+ [(c.path[1], c.kind[1], c.changed_content, c.meta_modified())
1391+ for c in d.modified])
1392 self.assertEqual([], d.removed)
1393 self.assertEqual([], d.renamed)
1394 self.assertEqual([], d.unchanged)
1395@@ -383,11 +401,13 @@
1396 self.assertEqual([], d.removed)
1397 self.assertEqual([], d.renamed)
1398 self.assertEqual([], d.unchanged)
1399- expected_unversioned = [(u'dir', None, 'directory'),
1400- (u'file', None, 'file')]
1401+ expected_unversioned = [(u'dir', 'directory'),
1402+ (u'file', 'file')]
1403 if links_supported:
1404- expected_unversioned.append((u'link', None, 'symlink'))
1405- self.assertEqual(expected_unversioned, d.unversioned)
1406+ expected_unversioned.append((u'link', 'symlink'))
1407+ self.assertEqual(
1408+ expected_unversioned,
1409+ [(c.path[1], c.kind[1]) for c in d.unversioned])
1410
1411
1412 class TestIterChanges(TestCaseWithTwoTrees):
1413@@ -567,7 +587,7 @@
1414 except StopIteration:
1415 raise KeyError(file_id)
1416
1417- def content_changed(self, tree, file_id):
1418+ def changed_content(self, tree, file_id):
1419 path, entry = self.get_path_entry(tree, file_id)
1420 return TreeChange(
1421 file_id, (path, path), True, (True, True),
1422@@ -602,11 +622,11 @@
1423 (entry.name, None), (entry.kind, None),
1424 (entry.executable, None))
1425
1426- def renamed(self, from_tree, to_tree, file_id, content_changed):
1427+ def renamed(self, from_tree, to_tree, file_id, changed_content):
1428 from_path, from_entry = self.get_path_entry(from_tree, file_id)
1429 to_path, to_entry = self.get_path_entry(to_tree, file_id)
1430 return TreeChange(
1431- file_id, (from_path, to_path), content_changed, (True, True),
1432+ file_id, (from_path, to_path), changed_content, (True, True),
1433 (from_entry.parent_id, to_entry.parent_id),
1434 (from_entry.name, to_entry.name),
1435 (from_entry.kind, to_entry.kind),
1436@@ -1237,8 +1257,8 @@
1437 # We should ignore the fact that 'b' exists in tree-2
1438 # because the want_unversioned parameter was not given.
1439 expected = self.sorted([
1440- self.content_changed(tree2, b'a-id'),
1441- self.content_changed(tree2, b'c-id'),
1442+ self.changed_content(tree2, b'a-id'),
1443+ self.changed_content(tree2, b'c-id'),
1444 ])
1445 self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1446 self.check_has_changes(True, tree1, tree2)
1447@@ -1447,7 +1467,7 @@
1448 expected = [
1449 self.unchanged(tree1, tree1.path2id('')),
1450 self.added(tree2, b'added'),
1451- self.content_changed(tree2, b'changed'),
1452+ self.changed_content(tree2, b'changed'),
1453 self.kind_changed(tree1, tree2, b'fromdir'),
1454 self.kind_changed(tree1, tree2, b'fromfile'),
1455 self.deleted(tree1, b'removed'),
1456@@ -1468,7 +1488,7 @@
1457 root_id = tree1.path2id('')
1458 expected = [
1459 self.added(tree2, b'added'),
1460- self.content_changed(tree2, b'changed'),
1461+ self.changed_content(tree2, b'changed'),
1462 self.kind_changed(tree1, tree2, b'fromdir'),
1463 self.kind_changed(tree1, tree2, b'fromfile'),
1464 self.deleted(tree1, b'removed'),
1465@@ -1492,7 +1512,7 @@
1466
1467 def test_trees_with_special_names(self):
1468 tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
1469- expected = self.sorted(self.content_changed(tree2, f_id) for f_id in path_ids
1470+ expected = self.sorted(self.changed_content(tree2, f_id) for f_id in path_ids
1471 if f_id.endswith(b'_f-id'))
1472 self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
1473 self.check_has_changes(True, tree1, tree2)
1474@@ -1511,8 +1531,8 @@
1475 tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1476 # We should notice that 'b' and all its children are deleted
1477 expected = [
1478- self.content_changed(tree2, b'a-id'),
1479- self.content_changed(tree2, b'g-id'),
1480+ self.changed_content(tree2, b'a-id'),
1481+ self.changed_content(tree2, b'g-id'),
1482 self.deleted(tree1, b'b-id'),
1483 self.deleted(tree1, b'c-id'),
1484 self.deleted(tree1, b'd-id'),
1485@@ -1603,9 +1623,9 @@
1486
1487 tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
1488
1489- self.assertEqual([self.content_changed(tree1, mod_id)],
1490+ self.assertEqual([self.changed_content(tree1, mod_id)],
1491 self.do_iter_changes(tree1, tree2))
1492- self.assertEqual([self.content_changed(tree1, mod_id)],
1493+ self.assertEqual([self.changed_content(tree1, mod_id)],
1494 self.do_iter_changes(tree1, tree2,
1495 specific_files=[u'\u03b1']))
1496 self.check_has_changes(True, tree1, tree2)
1497
1498=== modified file 'breezy/tests/per_repository/test_repository.py'
1499--- breezy/tests/per_repository/test_repository.py 2019-08-11 13:25:22 +0000
1500+++ breezy/tests/per_repository/test_repository.py 2019-09-21 16:12:34 +0000
1501@@ -313,19 +313,17 @@
1502 tree_a = self.make_branch_and_tree('a')
1503 self.build_tree(['a/foo'])
1504 tree_a.add('foo')
1505- file1_id = tree_a.path2id('foo')
1506 rev1 = tree_a.commit('rev1')
1507 self.build_tree(['a/vla'])
1508 tree_a.add('vla')
1509- file2_id = tree_a.path2id('vla')
1510 rev2 = tree_a.commit('rev2')
1511
1512 delta = tree_a.branch.repository.get_revision_delta(rev1)
1513 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1514- self.assertEqual([('foo', file1_id, 'file')], delta.added)
1515+ self.assertEqual([('foo', 'file')], [(c.path[1], c.kind[1]) for c in delta.added])
1516 delta = tree_a.branch.repository.get_revision_delta(rev2)
1517 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1518- self.assertEqual([('vla', file2_id, 'file')], delta.added)
1519+ self.assertEqual([('vla', 'file')], [(c.path[1], c.kind[1]) for c in delta.added])
1520
1521 def test_clone_bzrdir_repository_revision(self):
1522 # make a repository with some revisions,
1523@@ -1022,9 +1020,9 @@
1524 self.tree_a.path2id('baz')]))[0]
1525 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1526 self.assertEqual([
1527- ('baz', self.tree_a.path2id('baz'), 'file'),
1528- ('foo', self.tree_a.path2id('foo'), 'file'),
1529- ], delta.added)
1530+ ('baz', 'file'),
1531+ ('foo', 'file'),
1532+ ], [(c.path[1], c.kind[1]) for c in delta.added])
1533
1534 def test_directory(self):
1535 # Test a directory
1536@@ -1033,10 +1031,10 @@
1537 specific_fileids=[self.bar_id]))[0]
1538 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1539 self.assertEqual([
1540- ('bar', self.tree_a.path2id('bar'), 'directory'),
1541- ('bar/b1', self.tree_a.path2id('bar/b1'), 'file'),
1542- ('bar/b2', self.tree_a.path2id('bar/b2'), 'file'),
1543- ], delta.added)
1544+ ('bar', 'directory'),
1545+ ('bar/b1', 'file'),
1546+ ('bar/b2', 'file'),
1547+ ], [(c.path[1], c.kind[1]) for c in delta.added])
1548
1549 def test_unrelated(self):
1550 # Try another revision
1551@@ -1053,20 +1051,19 @@
1552 specific_fileids=[self.tree_a.path2id('bar/b2')]))[0]
1553 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1554 self.assertEqual([
1555- ('bar', self.tree_a.path2id('bar'), 'directory'),
1556- ('bar/b2', self.tree_a.path2id('bar/b2'), 'file'),
1557- ], delta.added)
1558+ ('bar', 'directory'),
1559+ ('bar/b2', 'file'),
1560+ ], [(c.path[1], c.kind[1]) for c in delta.added])
1561
1562 def test_file_in_unchanged_directory(self):
1563 delta = list(self.repository.get_deltas_for_revisions(
1564 [self.repository.get_revision(self.rev2)],
1565 specific_fileids=[self.tree_a.path2id('bar/b3')]))[0]
1566 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1567- if delta.added == [
1568- ('bar', self.tree_a.path2id('bar'), 'directory'),
1569- ('bar/b3', self.tree_a.path2id('bar/b3'), 'file')]:
1570+ if [(c.path[1], c.kind[1]) for c in delta.added] == [
1571+ ('bar', 'directory'), ('bar/b3', 'file')]:
1572 self.knownFailure("bzr incorrectly reports 'bar' as added - "
1573 "bug 878217")
1574 self.assertEqual([
1575- ('bar/b3', self.tree_a.path2id('bar/b3'), 'file'),
1576- ], delta.added)
1577+ ('bar/b3', 'file'),
1578+ ], [(c.path[1], c.kind[1]) for c in delta.added])
1579
1580=== modified file 'breezy/tests/per_repository_vf/test_fileid_involved.py'
1581--- breezy/tests/per_repository_vf/test_fileid_involved.py 2019-06-29 13:16:26 +0000
1582+++ breezy/tests/per_repository_vf/test_fileid_involved.py 2019-09-21 16:12:34 +0000
1583@@ -136,11 +136,9 @@
1584 new_tree = self.branch.repository.revision_tree(new_rev)
1585 delta = new_tree.changes_from(old_tree)
1586
1587- l2 = [id for path, id, kind in delta.added] + \
1588- [id for oldpath, newpath, id, kind, text_modified,
1589- meta_modified in delta.renamed] + \
1590- [id for path, id, kind, text_modified, meta_modified in
1591- delta.modified]
1592+ l2 = [change.file_id for change in delta.added] + \
1593+ [change.file_id for change in delta.renamed] + \
1594+ [change.file_id for change in delta.modified]
1595 return set(l2)
1596
1597
1598
1599=== modified file 'breezy/tests/test_bundle.py'
1600--- breezy/tests/test_bundle.py 2019-06-30 10:50:40 +0000
1601+++ breezy/tests/test_bundle.py 2019-09-21 16:12:34 +0000
1602@@ -511,9 +511,7 @@
1603 for ancestor in ancestors:
1604 old = self.b1.repository.revision_tree(ancestor)
1605 new = tree.branch.repository.revision_tree(ancestor)
1606- old.lock_read()
1607- new.lock_read()
1608- try:
1609+ with old.lock_read(), new.lock_read():
1610 # Check that there aren't any inventory level changes
1611 delta = new.changes_from(old)
1612 self.assertFalse(delta.has_changed(),
1613@@ -528,9 +526,6 @@
1614 continue
1615 self.assertEqual(
1616 old_file.read(), new.get_file(path).read())
1617- finally:
1618- new.unlock()
1619- old.unlock()
1620 if not _mod_revision.is_null(rev_id):
1621 tree.branch.generate_revision_history(rev_id)
1622 tree.update()
1623
1624=== modified file 'breezy/tests/test_delta.py'
1625--- breezy/tests/test_delta.py 2019-06-23 14:08:06 +0000
1626+++ breezy/tests/test_delta.py 2019-09-21 16:12:34 +0000
1627@@ -21,6 +21,7 @@
1628 revision as _mod_revision,
1629 tests,
1630 )
1631+from ..tree import TreeChange
1632 from ..sixish import (
1633 PY3,
1634 StringIO,
1635@@ -31,10 +32,10 @@
1636 def __init__(self):
1637 self.calls = []
1638
1639- def report(self, file_id, path, versioned, renamed, modified, exe_change,
1640+ def report(self, path, versioned, renamed, modified, exe_change,
1641 kind):
1642- self.calls.append((file_id, path, versioned, renamed, modified,
1643- exe_change, kind))
1644+ self.calls.append(
1645+ (path, versioned, renamed, modified, exe_change, kind))
1646
1647
1648 class TestReportChanges(tests.TestCase):
1649@@ -66,7 +67,7 @@
1650 result.append(format % args)
1651 reporter = _mod_delta._ChangeReporter(result_line,
1652 unversioned_filter=unversioned_filter, view_info=view_info)
1653- reporter.report(file_id, (old_path, path), versioned_change, renamed,
1654+ reporter.report((old_path, path), versioned_change, renamed,
1655 modified, exe_change, kind)
1656 if expected_lines is not None:
1657 self.assertEqualDiff('\n'.join(expected_lines), '\n'.join(result))
1658@@ -160,16 +161,17 @@
1659 modified='unchanged',
1660 exe_change=False):
1661 reporter = InstrumentedReporter()
1662- _mod_delta.report_changes([(file_id, paths, content_change, versioned,
1663- parent_id, name, kind, executable)], reporter)
1664+ _mod_delta.report_changes([
1665+ TreeChange(
1666+ file_id, paths, content_change, versioned, parent_id,
1667+ name, kind, executable)], reporter)
1668 output = reporter.calls[0]
1669- self.assertEqual(file_id, output[0])
1670- self.assertEqual(paths, output[1])
1671- self.assertEqual(versioned_change, output[2])
1672- self.assertEqual(renamed, output[3])
1673- self.assertEqual(modified, output[4])
1674- self.assertEqual(exe_change, output[5])
1675- self.assertEqual(kind, output[6])
1676+ self.assertEqual(paths, output[0])
1677+ self.assertEqual(versioned_change, output[1])
1678+ self.assertEqual(renamed, output[2])
1679+ self.assertEqual(modified, output[3])
1680+ self.assertEqual(exe_change, output[4])
1681+ self.assertEqual(kind, output[5])
1682
1683 def test_report_changes(self):
1684 """Test change detection of report_changes"""
1685@@ -243,34 +245,33 @@
1686 os.unlink('filename')
1687 self.build_tree(['filename/'])
1688 delta = tree.changes_from(tree.basis_tree())
1689- self.assertEqual([('filename', b'file-id', 'file', 'directory')],
1690- delta.kind_changed)
1691+ self.assertEqual([('filename', 'file', 'directory')],
1692+ [(c.path[1], c.kind[0], c.kind[1]) for c in delta.kind_changed])
1693 self.assertEqual([], delta.added)
1694 self.assertEqual([], delta.removed)
1695 self.assertEqual([], delta.renamed)
1696 self.assertEqual([], delta.modified)
1697 self.assertEqual([], delta.unchanged)
1698 self.assertTrue(delta.has_changed())
1699- self.assertTrue(delta.touches_file_id(b'file-id'))
1700 self.assertEqual('kind changed:\n filename (file => directory)\n',
1701 self.show_string(delta))
1702 other_delta = _mod_delta.TreeDelta()
1703 self.assertNotEqual(other_delta, delta)
1704- other_delta.kind_changed = [('filename', b'file-id', 'file',
1705- 'symlink')]
1706+ other_delta.kind_changed = [
1707+ TreeChange(
1708+ b'file-id',
1709+ ('filename', 'filename'), True, (True, True),
1710+ (tree.path2id(''), tree.path2id('')),
1711+ ('filename', 'filename'),
1712+ ('file', 'symlink'), (False, False))]
1713 self.assertNotEqual(other_delta, delta)
1714- other_delta.kind_changed = [('filename', b'file-id', 'file',
1715- 'directory')]
1716+ other_delta.kind_changed = [
1717+ TreeChange(
1718+ b'file-id',
1719+ ('filename', 'filename'), True, (True, True),
1720+ (tree.path2id(''), tree.path2id('')), ('filename', 'filename'),
1721+ ('file', 'directory'), (False, False))]
1722 self.assertEqual(other_delta, delta)
1723- if PY3:
1724- self.assertEqualDiff("TreeDelta(added=[], removed=[], renamed=[],"
1725- " kind_changed=[('filename', b'file-id', 'file', 'directory')],"
1726- " modified=[], unchanged=[], unversioned=[])", repr(delta))
1727- else:
1728- self.assertEqualDiff("TreeDelta(added=[], removed=[], renamed=[],"
1729- " kind_changed=[(u'filename', 'file-id', 'file', 'directory')],"
1730- " modified=[], unchanged=[], unversioned=[])", repr(delta))
1731-
1732 self.assertEqual('K filename (file => directory) file-id\n',
1733 self.show_string(delta, show_ids=True,
1734 short_status=True))
1735@@ -280,10 +281,12 @@
1736 self.assertEqual([], delta.kind_changed)
1737 # This loses the fact that kind changed, remembering it as a
1738 # modification
1739- self.assertEqual([('filename', 'dirname', b'file-id', 'directory',
1740- True, False)], delta.renamed)
1741+ self.assertEqual([TreeChange(
1742+ b'file-id', ('filename', 'dirname'), True,
1743+ (True, True), (tree.path2id(''), tree.path2id('')),
1744+ ('filename', 'dirname'), ('file', 'directory'), (False, False))],
1745+ delta.renamed)
1746 self.assertTrue(delta.has_changed())
1747- self.assertTrue(delta.touches_file_id(b'file-id'))
1748
1749
1750 class TestDeltaShow(tests.TestCaseWithTransport):
1751
1752=== modified file 'breezy/tests/test_log.py'
1753--- breezy/tests/test_log.py 2018-11-17 17:17:02 +0000
1754+++ breezy/tests/test_log.py 2019-09-21 16:12:34 +0000
1755@@ -158,7 +158,7 @@
1756 # By default we expect an empty list
1757 expected = kw.get(n, [])
1758 # strip out only the path components
1759- got = [x[0] for x in getattr(delta, n)]
1760+ got = [x.path[1] or x.path[0] for x in getattr(delta, n)]
1761 self.assertEqual(expected, got)
1762
1763 def assertInvalidRevisonNumber(self, br, start, end):
1764
1765=== modified file 'breezy/tests/test_missing.py'
1766--- breezy/tests/test_missing.py 2018-11-12 01:41:38 +0000
1767+++ breezy/tests/test_missing.py 2019-09-21 16:12:34 +0000
1768@@ -103,7 +103,7 @@
1769
1770 delta0 = r0.delta
1771 self.assertNotEqual(None, delta0)
1772- self.assertEqual([('b', b'b-id', 'file')], delta0.added)
1773+ self.assertEqual([('b', 'file')], [(c.path[1], c.kind[1]) for c in delta0.added])
1774 self.assertEqual([], delta0.removed)
1775 self.assertEqual([], delta0.renamed)
1776 self.assertEqual([], delta0.modified)
1777@@ -111,7 +111,7 @@
1778 delta1 = r1.delta
1779 self.assertNotEqual(None, delta1)
1780 self.assertEqual([], delta1.added)
1781- self.assertEqual([('a', b'a-id', 'file')], delta1.removed)
1782+ self.assertEqual([('a', 'file')], [(c.path[0], c.kind[0]) for c in delta1.removed])
1783 self.assertEqual([], delta1.renamed)
1784 self.assertEqual([], delta1.modified)
1785
1786@@ -121,14 +121,17 @@
1787 self.assertEqual([], delta2.removed)
1788 self.assertEqual([], delta2.renamed)
1789 self.assertEqual(
1790- [('b', b'b-id', 'file', True, False)], delta2.modified)
1791+ [('b', 'file', True, False)],
1792+ [(c.path[1], c.kind[1], c.changed_content, c.meta_modified()) for c in delta2.modified])
1793
1794 delta3 = r3.delta
1795 self.assertNotEqual(None, delta3)
1796 self.assertEqual([], delta3.added)
1797 self.assertEqual([], delta3.removed)
1798- self.assertEqual([('b', 'c', b'b-id', 'file', False, False)],
1799- delta3.renamed)
1800+ self.assertEqual(
1801+ [('b', 'c', 'file', False, False)],
1802+ [(c.path[0], c.path[1], c.kind[1], c.changed_content, c.meta_modified())
1803+ for c in delta3.renamed])
1804 self.assertEqual([], delta3.modified)
1805
1806
1807
1808=== modified file 'breezy/tests/test_tree.py'
1809--- breezy/tests/test_tree.py 2019-05-12 09:30:18 +0000
1810+++ breezy/tests/test_tree.py 2019-09-21 16:12:34 +0000
1811@@ -141,7 +141,7 @@
1812 self.assertEqual(len(delta.added), 0)
1813 delta = wt.changes_from(wt.basis_tree(), include_root=True)
1814 self.assertEqual(len(delta.added), 1)
1815- self.assertEqual(delta.added[0][0], '')
1816+ self.assertEqual(delta.added[0].path[1], '')
1817
1818 def test_changes_from_with_require_versioned(self):
1819 """Ensure the require_versioned option does what's expected."""
1820
1821=== modified file 'breezy/tree.py'
1822--- breezy/tree.py 2019-07-25 23:22:30 +0000
1823+++ breezy/tree.py 2019-09-21 16:12:34 +0000
1824@@ -147,6 +147,9 @@
1825 self.kind = kind
1826 self.executable = executable
1827
1828+ def __repr__(self):
1829+ return "%s%r" % (self.__class__.__name__, tuple(self))
1830+
1831 def __len__(self):
1832 return len(self.__slots__)
1833
1834@@ -169,6 +172,11 @@
1835 return tuple(self).__getitem__(i)
1836 return getattr(self, self.__slots__[i])
1837
1838+ def meta_modified(self):
1839+ if self.versioned == (True, True):
1840+ return (self.executable[0] != self.executable[1])
1841+ return False
1842+
1843 def is_reparented(self):
1844 return self.parent_id[0] != self.parent_id[1]
1845
1846
1847=== modified file 'breezy/version_info_formats/__init__.py'
1848--- breezy/version_info_formats/__init__.py 2018-11-11 04:08:32 +0000
1849+++ breezy/version_info_formats/__init__.py 2019-09-21 16:12:34 +0000
1850@@ -113,35 +113,33 @@
1851 return
1852
1853 delta = self._working_tree.changes_from(basis_tree,
1854- include_root=True)
1855+ include_root=True,
1856+ want_unversioned=True)
1857
1858 # Using a 2-pass algorithm for renames. This is because you might have
1859 # renamed something out of the way, and then created a new file
1860 # in which case we would rather see the new marker
1861 # Or you might have removed the target, and then renamed
1862 # in which case we would rather see the renamed marker
1863- for (old_path, new_path, file_id,
1864- kind, text_mod, meta_mod) in delta.renamed:
1865- self._clean = False
1866- self._file_revisions[old_path] = u'renamed to %s' % (new_path,)
1867- for path, file_id, kind in delta.removed:
1868- self._clean = False
1869- self._file_revisions[path] = 'removed'
1870- for path, file_id, kind in delta.added:
1871- self._clean = False
1872- self._file_revisions[path] = 'new'
1873- for (old_path, new_path, file_id,
1874- kind, text_mod, meta_mod) in delta.renamed:
1875- self._clean = False
1876- self._file_revisions[new_path] = u'renamed from %s' % (
1877- old_path,)
1878- for path, file_id, kind, text_mod, meta_mod in delta.modified:
1879- self._clean = False
1880- self._file_revisions[path] = 'modified'
1881-
1882- for path in self._working_tree.unknowns():
1883- self._clean = False
1884- self._file_revisions[path] = 'unversioned'
1885+ for change in delta.renamed:
1886+ self._clean = False
1887+ self._file_revisions[change.path[0]] = u'renamed to %s' % (change.path[1],)
1888+ for change in delta.removed:
1889+ self._clean = False
1890+ self._file_revisions[change.path[0]] = 'removed'
1891+ for change in delta.added:
1892+ self._clean = False
1893+ self._file_revisions[change.path[1]] = 'new'
1894+ for change in delta.renamed:
1895+ self._clean = False
1896+ self._file_revisions[change.path[1]] = u'renamed from %s' % (
1897+ change.path[0],)
1898+ for change in delta.modified:
1899+ self._clean = False
1900+ self._file_revisions[change.path[1]] = 'modified'
1901+ for change in delta.unversioned:
1902+ self._clean = False
1903+ self._file_revisions[change.path[1]] = 'unversioned'
1904 finally:
1905 basis_tree.unlock()
1906 if self._working_tree is not None:

Subscribers

People subscribed via source and target branches