Merge lp:~jelmer/brz/get-delta-revisions-files into lp:brz/3.1

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/get-delta-revisions-files
Merge into: lp:brz/3.1
Diff against target: 285 lines (+160/-19)
7 files modified
breezy/bzr/remote.py (+8/-6)
breezy/bzr/tests/per_repository_vf/test_repository.py (+13/-2)
breezy/git/tree.py (+8/-6)
breezy/log.py (+1/-1)
breezy/plugins/stats/cmds.py (+2/-2)
breezy/repository.py (+38/-0)
breezy/tests/per_repository/test_repository.py (+90/-2)
To merge this branch: bzr merge lp:~jelmer/brz/get-delta-revisions-files
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve
Review via email: mp+386469@code.launchpad.net

Commit message

Add Repository.get_revision_deltas.

Description of the change

Add Repository.get_revision_deltas.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'breezy/bzr/remote.py'
--- breezy/bzr/remote.py 2020-03-22 19:12:43 +0000
+++ breezy/bzr/remote.py 2020-06-28 18:07:07 +0000
@@ -2590,12 +2590,14 @@
2590 # file-id based, so filtering before or afterwards is2590 # file-id based, so filtering before or afterwards is
2591 # currently easier.2591 # currently easier.
2592 if specific_fileids is None:2592 if specific_fileids is None:
2593 trees = dict((t.get_revision_id(), t) for2593 trees = {
2594 t in self.revision_trees(required_trees))2594 t.get_revision_id(): t
2595 for t in self.revision_trees(required_trees)}
2595 else:2596 else:
2596 trees = dict((t.get_revision_id(), t) for2597 trees = {
2597 t in self._filtered_revision_trees(required_trees,2598 t.get_revision_id(): t
2598 specific_fileids))2599 for t in self._filtered_revision_trees(
2600 required_trees, specific_fileids)}
25992601
2600 # Calculate the deltas2602 # Calculate the deltas
2601 for revision in revisions:2603 for revision in revisions:
@@ -2608,7 +2610,7 @@
2608 def get_revision_delta(self, revision_id):2610 def get_revision_delta(self, revision_id):
2609 with self.lock_read():2611 with self.lock_read():
2610 r = self.get_revision(revision_id)2612 r = self.get_revision(revision_id)
2611 return list(self.get_deltas_for_revisions([r]))[0]2613 return list(self.get_revision_deltas([r]))[0]
26122614
2613 def revision_trees(self, revision_ids):2615 def revision_trees(self, revision_ids):
2614 with self.lock_read():2616 with self.lock_read():
26152617
=== modified file 'breezy/bzr/tests/per_repository_vf/test_repository.py'
--- breezy/bzr/tests/per_repository_vf/test_repository.py 2020-06-10 02:56:53 +0000
+++ breezy/bzr/tests/per_repository_vf/test_repository.py 2020-06-28 18:07:07 +0000
@@ -364,8 +364,19 @@
364 revisions = [repository.get_revision(r) for r in364 revisions = [repository.get_revision(r) for r in
365 [b'rev1', b'rev2', b'rev3', b'rev4']]365 [b'rev1', b'rev2', b'rev3', b'rev4']]
366 deltas1 = list(repository.get_deltas_for_revisions(revisions))366 deltas1 = list(repository.get_deltas_for_revisions(revisions))
367 deltas2 = [repository.get_revision_delta(r.revision_id) for r in367 deltas2 = [repository.get_revision_delta(r.revision_id)
368 revisions]368 for r in revisions]
369 self.assertEqual(deltas1, deltas2)
370
371 def test_get_revision_deltas(self):
372 repository = self.controldir.open_repository()
373 repository.lock_read()
374 self.addCleanup(repository.unlock)
375 revisions = [repository.get_revision(r) for r in
376 [b'rev1', b'rev2', b'rev3', b'rev4']]
377 deltas1 = list(repository.get_revision_deltas(revisions))
378 deltas2 = [repository.get_revision_delta(r.revision_id)
379 for r in revisions]
369 self.assertEqual(deltas1, deltas2)380 self.assertEqual(deltas1, deltas2)
370381
371 def test_all_revision_ids(self):382 def test_all_revision_ids(self):
372383
=== modified file 'breezy/git/tree.py'
--- breezy/git/tree.py 2020-06-27 14:48:19 +0000
+++ breezy/git/tree.py 2020-06-28 18:07:07 +0000
@@ -1029,10 +1029,11 @@
1029 ret = {}1029 ret = {}
1030 changes = self._iter_git_changes(specific_files=paths)[0]1030 changes = self._iter_git_changes(specific_files=paths)[0]
1031 for (change_type, old, new) in changes:1031 for (change_type, old, new) in changes:
1032 oldpath = old[0]1032 if old[0] is None:
1033 newpath = new[0]1033 continue
1034 oldpath = decode_git_path(old[0])
1034 if oldpath in paths:1035 if oldpath in paths:
1035 ret[oldpath] = newpath1036 ret[oldpath] = decode_git_path(new[0]) if new[0] else None
1036 for path in paths:1037 for path in paths:
1037 if path not in ret:1038 if path not in ret:
1038 if self.source.has_filename(path):1039 if self.source.has_filename(path):
@@ -1049,10 +1050,11 @@
1049 ret = {}1050 ret = {}
1050 changes = self._iter_git_changes(specific_files=paths)[0]1051 changes = self._iter_git_changes(specific_files=paths)[0]
1051 for (change_type, old, new) in changes:1052 for (change_type, old, new) in changes:
1052 oldpath = old[0]1053 if new[0] is None:
1053 newpath = new[0]1054 continue
1055 newpath = decode_git_path(new[0])
1054 if newpath in paths:1056 if newpath in paths:
1055 ret[newpath] = oldpath1057 ret[newpath] = decode_git_path(old[0]) if old[0] else None
1056 for path in paths:1058 for path in paths:
1057 if path not in ret:1059 if path not in ret:
1058 if self.target.has_filename(path):1060 if self.target.has_filename(path):
10591061
=== modified file 'breezy/log.py'
--- breezy/log.py 2020-06-21 02:15:25 +0000
+++ breezy/log.py 2020-06-28 18:07:07 +0000
@@ -982,7 +982,7 @@
982 revisions = [rev[1] for rev in revs]982 revisions = [rev[1] for rev in revs]
983 new_revs = []983 new_revs = []
984 if delta_type == 'full' and not check_fileids:984 if delta_type == 'full' and not check_fileids:
985 deltas = repository.get_deltas_for_revisions(revisions)985 deltas = repository.get_revision_deltas(revisions)
986 for rev, delta in zip(revs, deltas):986 for rev, delta in zip(revs, deltas):
987 new_revs.append((rev[0], rev[1], delta))987 new_revs.append((rev[0], rev[1], delta))
988 else:988 else:
989989
=== modified file 'breezy/plugins/stats/cmds.py'
--- breezy/plugins/stats/cmds.py 2019-12-23 00:34:25 +0000
+++ breezy/plugins/stats/cmds.py 2020-06-28 18:07:07 +0000
@@ -315,7 +315,7 @@
315 with ui.ui_factory.nested_progress_bar() as pb:315 with ui.ui_factory.nested_progress_bar() as pb:
316 with repository.lock_read():316 with repository.lock_read():
317 i = 0317 i = 0
318 for delta in repository.get_deltas_for_revisions(revs):318 for delta in repository.get_revision_deltas(revs):
319 pb.update("classifying commits", i, len(revs))319 pb.update("classifying commits", i, len(revs))
320 for c in classify_delta(delta):320 for c in classify_delta(delta):
321 if c not in ret:321 if c not in ret:
@@ -364,7 +364,7 @@
364 if ps is not None and r != NULL_REVISION]364 if ps is not None and r != NULL_REVISION]
365 revs = repository.get_revisions(ancestry)365 revs = repository.get_revisions(ancestry)
366 with ui.ui_factory.nested_progress_bar() as pb:366 with ui.ui_factory.nested_progress_bar() as pb:
367 iterator = zip(revs, repository.get_deltas_for_revisions(revs))367 iterator = zip(revs, repository.get_revision_deltas(revs))
368 for i, (rev, delta) in enumerate(iterator):368 for i, (rev, delta) in enumerate(iterator):
369 pb.update("analysing revisions", i, len(revs))369 pb.update("analysing revisions", i, len(revs))
370 # Don't count merges370 # Don't count merges
371371
=== modified file 'breezy/repository.py'
--- breezy/repository.py 2020-01-20 00:03:54 +0000
+++ breezy/repository.py 2020-06-28 18:07:07 +0000
@@ -913,6 +913,44 @@
913 r = self.get_revision(revision_id)913 r = self.get_revision(revision_id)
914 return list(self.get_deltas_for_revisions([r]))[0]914 return list(self.get_deltas_for_revisions([r]))[0]
915915
916 def get_revision_deltas(self, revisions, specific_files=None):
917 """Produce a generator of revision deltas.
918
919 Note that the input is a sequence of REVISIONS, not revision ids.
920 Trees will be held in memory until the generator exits.
921 Each delta is relative to the revision's lefthand predecessor.
922
923 specific_files should exist in the first revision.
924
925 :param specific_files: if not None, the result is filtered
926 so that only those files, their parents and their
927 children are included.
928 """
929 from .tree import InterTree
930 # Get the revision-ids of interest
931 required_trees = set()
932 for revision in revisions:
933 required_trees.add(revision.revision_id)
934 required_trees.update(revision.parent_ids[:1])
935
936 trees = {
937 t.get_revision_id(): t
938 for t in self.revision_trees(required_trees)}
939
940 # Calculate the deltas
941 for revision in revisions:
942 if not revision.parent_ids:
943 old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
944 else:
945 old_tree = trees[revision.parent_ids[0]]
946 intertree = InterTree.get(old_tree, trees[revision.revision_id])
947 yield intertree.compare(specific_files=specific_files)
948 if specific_files is not None:
949 specific_files = [
950 p for p in intertree.find_source_paths(
951 specific_files).values()
952 if p is not None]
953
916 def store_revision_signature(self, gpg_strategy, plaintext, revision_id):954 def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
917 raise NotImplementedError(self.store_revision_signature)955 raise NotImplementedError(self.store_revision_signature)
918956
919957
=== modified file 'breezy/tests/per_repository/test_repository.py'
--- breezy/tests/per_repository/test_repository.py 2019-09-21 16:12:01 +0000
+++ breezy/tests/per_repository/test_repository.py 2020-06-28 18:07:07 +0000
@@ -997,10 +997,10 @@
997 self.assertEqual(repo.control_url, repo.control_transport.base)997 self.assertEqual(repo.control_url, repo.control_transport.base)
998998
999999
1000class TestDeltaRevisionFiltered(per_repository.TestCaseWithRepository):1000class TestDeltaRevisionFileIdFiltered(per_repository.TestCaseWithRepository):
10011001
1002 def setUp(self):1002 def setUp(self):
1003 super(TestDeltaRevisionFiltered, self).setUp()1003 super(TestDeltaRevisionFileIdFiltered, self).setUp()
1004 self.tree_a = self.make_branch_and_tree('a')1004 self.tree_a = self.make_branch_and_tree('a')
1005 self.build_tree(['a/foo', 'a/bar/', 'a/bar/b1', 'a/bar/b2', 'a/baz'])1005 self.build_tree(['a/foo', 'a/bar/', 'a/bar/b1', 'a/bar/b2', 'a/baz'])
1006 self.tree_a.add(['foo', 'bar', 'bar/b1', 'bar/b2', 'baz'])1006 self.tree_a.add(['foo', 'bar', 'bar/b1', 'bar/b2', 'baz'])
@@ -1067,3 +1067,91 @@
1067 self.assertEqual([1067 self.assertEqual([
1068 ('bar/b3', 'file'),1068 ('bar/b3', 'file'),
1069 ], [(c.path[1], c.kind[1]) for c in delta.added])1069 ], [(c.path[1], c.kind[1]) for c in delta.added])
1070
1071
1072class TestDeltaRevisionFilesFiltered(per_repository.TestCaseWithRepository):
1073
1074 def setUp(self):
1075 super(TestDeltaRevisionFilesFiltered, self).setUp()
1076 self.tree_a = self.make_branch_and_tree('a')
1077 self.build_tree(
1078 ['a/foo', 'a/bar/', 'a/bar/b1', 'a/bar/b2', 'a/baz', 'a/oldname'])
1079 self.tree_a.add(['foo', 'bar', 'bar/b1', 'bar/b2', 'baz', 'oldname'])
1080 self.rev1 = self.tree_a.commit('rev1')
1081 self.build_tree(['a/bar/b3'])
1082 self.tree_a.add('bar/b3')
1083 self.tree_a.rename_one('oldname', 'newname')
1084 self.rev2 = self.tree_a.commit('rev2')
1085 self.repository = self.tree_a.branch.repository
1086 self.addCleanup(self.repository.lock_read().unlock)
1087
1088 def test_multiple_files(self):
1089 # Test multiple files
1090 delta = list(self.repository.get_revision_deltas(
1091 [self.repository.get_revision(self.rev1)], specific_files=[
1092 'foo', 'baz']))[0]
1093 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1094 self.assertEqual([
1095 ('baz', 'file'),
1096 ('foo', 'file'),
1097 ], [(c.path[1], c.kind[1]) for c in delta.added])
1098
1099 def test_directory(self):
1100 # Test a directory
1101 delta = list(self.repository.get_revision_deltas(
1102 [self.repository.get_revision(self.rev1)],
1103 specific_files=['bar']))[0]
1104 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1105 self.assertEqual([
1106 ('bar', 'directory'),
1107 ('bar/b1', 'file'),
1108 ('bar/b2', 'file'),
1109 ], [(c.path[1], c.kind[1]) for c in delta.added])
1110
1111 def test_unrelated(self):
1112 # Try another revision
1113 delta = list(self.repository.get_revision_deltas(
1114 [self.repository.get_revision(self.rev2)],
1115 specific_files=['foo']))[0]
1116 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1117 self.assertEqual([], delta.added)
1118
1119 def test_renamed(self):
1120 # Try another revision
1121 self.assertTrue(
1122 self.repository.revision_tree(self.rev2).has_filename('newname'))
1123 self.assertTrue(
1124 self.repository.revision_tree(self.rev1).has_filename('oldname'))
1125 revs = [
1126 self.repository.get_revision(self.rev2),
1127 self.repository.get_revision(self.rev1)]
1128 delta2, delta1 = list(self.repository.get_revision_deltas(
1129 revs, specific_files=['newname']))
1130 self.assertIsInstance(delta1, _mod_delta.TreeDelta)
1131 self.assertEqual([('oldname', 'newname')], [c.path for c in delta2.renamed])
1132 self.assertIsInstance(delta2, _mod_delta.TreeDelta)
1133 self.assertEqual(['oldname'], [c.path[1] for c in delta1.added])
1134
1135 def test_file_in_directory(self):
1136 # Test a file in a directory, both of which were added
1137 delta = list(self.repository.get_revision_deltas(
1138 [self.repository.get_revision(self.rev1)],
1139 specific_files=['bar/b2']))[0]
1140 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1141 self.assertEqual([
1142 ('bar', 'directory'),
1143 ('bar/b2', 'file'),
1144 ], [(c.path[1], c.kind[1]) for c in delta.added])
1145
1146 def test_file_in_unchanged_directory(self):
1147 delta = list(self.repository.get_revision_deltas(
1148 [self.repository.get_revision(self.rev2)],
1149 specific_files=['bar/b3']))[0]
1150 self.assertIsInstance(delta, _mod_delta.TreeDelta)
1151 if [(c.path[1], c.kind[1]) for c in delta.added] == [
1152 ('bar', 'directory'), ('bar/b3', 'file')]:
1153 self.knownFailure("bzr incorrectly reports 'bar' as added - "
1154 "bug 878217")
1155 self.assertEqual([
1156 ('bar/b3', 'file'),
1157 ], [(c.path[1], c.kind[1]) for c in delta.added])

Subscribers

People subscribed via source and target branches