Rev 2990: New Repository API find_text_key_references for use by reconcile and check. in http://people.ubuntu.com/~robertc/baz2.0/reconcile

Robert Collins robertc at robertcollins.net
Wed Nov 14 04:24:35 GMT 2007


At http://people.ubuntu.com/~robertc/baz2.0/reconcile

------------------------------------------------------------
revno: 2990
revision-id:robertc at robertcollins.net-20071114042424-ww2cu4nqfo5fv6c4
parent: robertc at robertcollins.net-20071114022530-prb0wv25n7os0ee1
committer: Robert Collins <robertc at robertcollins.net>
branch nick: find_text_key_references
timestamp: Wed 2007-11-14 15:24:24 +1100
message:
  New Repository API find_text_key_references for use by reconcile and check.
added:
  bzrlib/tests/repository_implementations/test_find_text_key_references.py test_find_text_key_r-20071114033605-v73bakal8x77qlfi-1
modified:
  bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
  bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
  bzrlib/tests/repository_implementations/__init__.py __init__.py-20060131092037-9564957a7d4a841b
  bzrlib/tests/repository_implementations/test_check_reconcile.py test_broken.py-20070928125406-62236394w0jpbpd6-2
=== added file 'bzrlib/tests/repository_implementations/test_find_text_key_references.py'
--- a/bzrlib/tests/repository_implementations/test_find_text_key_references.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/repository_implementations/test_find_text_key_references.py	2007-11-14 04:24:24 +0000
@@ -0,0 +1,30 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+"""Test the find_text_key_references API."""
+
+
+from bzrlib.tests.repository_implementations import TestCaseWithRepository
+
+
+class TestFindTextKeyReferences(TestCaseWithRepository):
+
+    def test_empty(self):
+        repo = self.make_repository('.')
+        repo.lock_read()
+        self.addCleanup(repo.unlock)
+        self.assertEqual({}, repo.find_text_key_references())

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2007-11-04 20:35:32 +0000
+++ b/bzrlib/remote.py	2007-11-14 04:24:24 +0000
@@ -305,6 +305,20 @@
             #self._real_repository = self.bzrdir._real_bzrdir.open_repository()
             self._set_real_repository(self.bzrdir._real_bzrdir.open_repository())
 
+    def find_text_key_references(self):
+        """Find the text key references within the repository.
+
+        :return: a dictionary mapping (file_id, revision_id) tuples to altered file-ids to an iterable of
+        revision_ids. Each altered file-ids has the exact revision_ids that
+        altered it listed explicitly.
+        :return: A dictionary mapping text keys ((fileid, revision_id) tuples)
+            to whether they were referred to by the inventory of the
+            revision_id that they contain. The inventory texts from all present
+            revision ids are assessed to generate this report.
+        """
+        self._ensure_real()
+        return self._real_repository.find_text_key_references()
+
     def get_revision_graph(self, revision_id=None):
         """See Repository.get_revision_graph()."""
         if revision_id is None:

=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py	2007-11-14 02:25:30 +0000
+++ b/bzrlib/repository.py	2007-11-14 04:24:24 +0000
@@ -1055,6 +1055,27 @@
                                                          signature,
                                                          self.get_transaction())
 
+    def find_text_key_references(self):
+        """Find the text key references within the repository.
+
+        :return: a dictionary mapping (file_id, revision_id) tuples to altered file-ids to an iterable of
+        revision_ids. Each altered file-ids has the exact revision_ids that
+        altered it listed explicitly.
+        :return: A dictionary mapping text keys ((fileid, revision_id) tuples)
+            to whether they were referred to by the inventory of the
+            revision_id that they contain. The inventory texts from all present
+            revision ids are assessed to generate this report.
+        """
+        revision_ids = self.all_revision_ids()
+        w = self.get_inventory_weave()
+        pb = ui.ui_factory.nested_progress_bar()
+        try:
+            return self._find_text_key_references_from_xml_inventory_lines(
+                w.iter_lines_added_or_present_in_versions(revision_ids, pb=pb))
+        finally:
+            pb.finished()
+
+
     def _find_text_key_references_from_xml_inventory_lines(self,
         line_iterator):
         """Core routine for extracting references to texts from inventories.
@@ -1068,6 +1089,10 @@
             not part of the line_iterator's output then False will be given -
             even though it may actually refer to that key.
         """
+        assert self._serializer.support_altered_by_hack, \
+            ("_find_text_key_references_from_xml_inventory_lines only "
+             "supported for branches which store inventory as unnested xml, "
+             "not on %r" % self)
         result = {}
 
         # this code needs to read every new line in every inventory for the
@@ -1164,9 +1189,6 @@
         revision_ids. Each altered file-ids has the exact revision_ids that
         altered it listed explicitly.
         """
-        assert self._serializer.support_altered_by_hack, \
-            ("fileids_altered_by_revision_ids only supported for branches " 
-             "which store inventory as unnested xml, not on %r" % self)
         selected_revision_ids = set(revision_ids)
         w = self.get_inventory_weave()
         pb = ui.ui_factory.nested_progress_bar()

=== modified file 'bzrlib/tests/repository_implementations/__init__.py'
--- a/bzrlib/tests/repository_implementations/__init__.py	2007-11-03 14:26:37 +0000
+++ b/bzrlib/tests/repository_implementations/__init__.py	2007-11-14 04:24:24 +0000
@@ -168,6 +168,14 @@
         inv = self.make_one_file_inventory(
             repo, 'rev1a', [], root_revision='rev1a')
         self.add_revision(repo, 'rev1a', inv, [])
+        self.versioned_root = repo.supports_rich_root()
+
+    def repository_text_key_references(self):
+        result = {}
+        if self.versioned_root:
+            result.update({('TREE_ROOT', 'rev1a'): True})
+        result.update({('a-file-id', 'rev1a'): True})
+        return result
 
 
 class FileParentIsNotInRevisionAncestryScenario(BrokenRepoScenario):
@@ -217,6 +225,16 @@
         inv = self.make_one_file_inventory(
             repo, 'rev2', ['rev1a', 'rev1b'])
         self.add_revision(repo, 'rev2', inv, ['rev1a'])
+        self.versioned_root = repo.supports_rich_root()
+
+    def repository_text_key_references(self):
+        result = {}
+        if self.versioned_root:
+            result.update({('TREE_ROOT', 'rev1a'): True,
+                           ('TREE_ROOT', 'rev2'): True})
+        result.update({('a-file-id', 'rev1a'): True,
+                       ('a-file-id', 'rev2'): True})
+        return result
 
 
 class FileParentHasInaccessibleInventoryScenario(BrokenRepoScenario):
@@ -267,6 +285,16 @@
         # a-file cannot have rev1c as its ancestor.
         inv = self.make_one_file_inventory(repo, 'rev3', ['rev1c'])
         self.add_revision(repo, 'rev3', inv, ['rev1c', 'rev1a'])
+        self.versioned_root = repo.supports_rich_root()
+
+    def repository_text_key_references(self):
+        result = {}
+        if self.versioned_root:
+            result.update({('TREE_ROOT', 'rev2'): True,
+                           ('TREE_ROOT', 'rev3'): True})
+        result.update({('a-file-id', 'rev2'): True,
+                       ('a-file-id', 'rev3'): True})
+        return result
 
 
 class FileParentsNotReferencedByAnyInventoryScenario(BrokenRepoScenario):
@@ -386,6 +414,24 @@
         # parents for the per file graph.
         inv = self.make_one_file_inventory(repo, 'rev5', ['rev2', 'rev2c'])
         self.add_revision(repo, 'rev5', inv, ['rev2', 'rev2c'])
+        self.versioned_root = repo.supports_rich_root()
+
+    def repository_text_key_references(self):
+        result = {}
+        if self.versioned_root:
+            result.update({('TREE_ROOT', 'rev1a'): True,
+                           ('TREE_ROOT', 'rev2'): True,
+                           ('TREE_ROOT', 'rev2b'): True,
+                           ('TREE_ROOT', 'rev2c'): True,
+                           ('TREE_ROOT', 'rev3'): True,
+                           ('TREE_ROOT', 'rev4'): True,
+                           ('TREE_ROOT', 'rev5'): True})
+        result.update({('a-file-id', 'rev1a'): True,
+                       ('a-file-id', 'rev2c'): True,
+                       ('a-file-id', 'rev3'): True,
+                       ('a-file-id', 'rev4'): True,
+                       ('a-file-id', 'rev5'): True})
+        return result
 
 
 class UnreferencedFileParentsFromNoOpMergeScenario(BrokenRepoScenario):
@@ -454,6 +500,21 @@
         # rev4: a modification of a-file on top of rev3.
         inv = self.make_one_file_inventory(repo, 'rev4', ['rev2'])
         self.add_revision(repo, 'rev4', inv, ['rev3'])
+        self.versioned_root = repo.supports_rich_root()
+
+    def repository_text_key_references(self):
+        result = {}
+        if self.versioned_root:
+            result.update({('TREE_ROOT', 'rev1a'): True,
+                           ('TREE_ROOT', 'rev1b'): True,
+                           ('TREE_ROOT', 'rev2'): True,
+                           ('TREE_ROOT', 'rev3'): True,
+                           ('TREE_ROOT', 'rev4'): True})
+        result.update({('a-file-id', 'rev1a'): True,
+                       ('a-file-id', 'rev1b'): True,
+                       ('a-file-id', 'rev2'): False,
+                       ('a-file-id', 'rev4'): True})
+        return result
 
 
 class TooManyParentsScenario(BrokenRepoScenario):
@@ -503,7 +564,19 @@
         inv = self.make_one_file_inventory(
             repo, 'broken-revision', ('good-parent', 'bad-parent'))
         self.add_revision(repo, 'broken-revision', inv, ('good-parent',))
+        self.versioned_root = repo.supports_rich_root()
 
+    def repository_text_key_references(self):
+        result = {}
+        if self.versioned_root:
+            result.update({('TREE_ROOT', 'bad-parent'): True,
+                           ('TREE_ROOT', 'broken-revision'): True,
+                           ('TREE_ROOT', 'good-parent'): True})
+        result.update({('a-file-id', 'bad-parent'): True,
+                       ('a-file-id', 'broken-revision'): True,
+                       ('a-file-id', 'good-parent'): True})
+        return result
+             
 
 class ClaimedFileParentDidNotModifyFileScenario(BrokenRepoScenario):
     """A scenario where the file parent is the same as the revision parent, but
@@ -562,7 +635,18 @@
         inv = self.make_one_file_inventory(
             repo, 'current', ('modified-something-else',))
         self.add_revision(repo, 'current', inv, ('modified-something-else',))
+        self.versioned_root = repo.supports_rich_root()
 
+    def repository_text_key_references(self):
+        result = {}
+        if self.versioned_root:
+            result.update({('TREE_ROOT', 'basis'): True,
+                           ('TREE_ROOT', 'current'): True,
+                           ('TREE_ROOT', 'modified-something-else'): True})
+        result.update({('a-file-id', 'basis'): True,
+                       ('a-file-id', 'current'): True})
+        return result
+            
 
 class IncorrectlyOrderedParentsScenario(BrokenRepoScenario):
     """A scenario where the set parents of a version of a file are correct, but
@@ -626,7 +710,21 @@
             repo, 'broken-revision-2-1', ['parent-1', 'parent-2'])
         self.add_revision(
             repo, 'broken-revision-2-1', inv, ['parent-2', 'parent-1'])
+        self.versioned_root = repo.supports_rich_root()
 
+    def repository_text_key_references(self):
+        result = {}
+        if self.versioned_root:
+            result.update({('TREE_ROOT', 'broken-revision-1-2'): True,
+                           ('TREE_ROOT', 'broken-revision-2-1'): True,
+                           ('TREE_ROOT', 'parent-1'): True,
+                           ('TREE_ROOT', 'parent-2'): True})
+        result.update({('a-file-id', 'broken-revision-1-2'): True,
+                       ('a-file-id', 'broken-revision-2-1'): True,
+                       ('a-file-id', 'parent-1'): True,
+                       ('a-file-id', 'parent-2'): True})
+        return result
+               
 
 all_broken_scenario_classes = [
     UndamagedRepositoryScenario,
@@ -671,6 +769,7 @@
         'test_commit_builder',
         'test_fetch',
         'test_fileid_involved',
+        'test_find_text_key_references',
         'test_has_same_location',
         'test_is_write_locked',
         'test_iter_reverse_revision_history',

=== modified file 'bzrlib/tests/repository_implementations/test_check_reconcile.py'
--- a/bzrlib/tests/repository_implementations/test_check_reconcile.py	2007-11-03 14:26:37 +0000
+++ b/bzrlib/tests/repository_implementations/test_check_reconcile.py	2007-11-14 04:24:24 +0000
@@ -134,6 +134,16 @@
                     % (when_description, version, found_parents,
                        expected_parents))
 
+    def prepare_test_repository(self):
+        """Prepare a repository to test with from the test scenario.
+
+        :return: A repository, and the scenario instance.
+        """
+        scenario = self.scenario_class(self)
+        repo = self.make_populated_repository(scenario.populate_repository)
+        self.require_repo_suffers_text_parent_corruption(repo)
+        return repo, scenario
+
     def shas_for_versions_of_file(self, repo, versions):
         """Get the SHA-1 hashes of the versions of 'a-file' in the repository.
         
@@ -149,9 +159,7 @@
         """Populate a repository and reconcile it, verifying the state before
         and after.
         """
-        scenario = self.scenario_class(self)
-        repo = self.make_populated_repository(scenario.populate_repository)
-        self.require_repo_suffers_text_parent_corruption(repo)
+        repo, scenario = self.prepare_test_repository()
         repo.lock_read()
         try:
             self.assertParentsMatch(scenario.populated_parents(), repo,
@@ -183,9 +191,7 @@
 
     def test_check_behaviour(self):
         """Populate a repository and check it, and verify the output."""
-        scenario = self.scenario_class(self)
-        repo = self.make_populated_repository(scenario.populate_repository)
-        self.require_repo_suffers_text_parent_corruption(repo)
+        repo, scenario = self.prepare_test_repository()
         check_result = repo.check()
         check_result.report_results(verbose=True)
         for pattern in scenario.check_regexes(repo):
@@ -193,3 +199,10 @@
                 self._get_log(keep_log_file=True),
                 pattern)
 
+    def test_find_text_key_references(self):
+        """Test that find_text_key_references finds erroneous references."""
+        repo, scenario = self.prepare_test_repository()
+        repo.lock_read()
+        self.addCleanup(repo.unlock)
+        self.assertEqual(scenario.repository_text_key_references(),
+            repo.find_text_key_references())



More information about the bazaar-commits mailing list