Rev 2945: (Andrew Bennetts) Reconcile will force file versions with unreferenced parents to be stored as fulltexts (fixes bug 155730). in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Fri Oct 26 08:48:09 BST 2007
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 2945
revision-id: pqm at pqm.ubuntu.com-20071026074806-v0hw6v1dbm6hu9oj
parent: pqm at pqm.ubuntu.com-20071025232834-wcuoh6azwgez5b80
parent: andrew.bennetts at canonical.com-20071026065843-zof5jrpbfic8cmxl
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2007-10-26 08:48:06 +0100
message:
(Andrew Bennetts) Reconcile will force file versions with unreferenced parents to be stored as fulltexts (fixes bug 155730).
modified:
bzrlib/check.py check.py-20050309040759-f3a679400c06bcc1
bzrlib/reconcile.py reweave_inventory.py-20051108164726-1e5e0934febac06e
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
------------------------------------------------------------
revno: 2927.2.14
merged: andrew.bennetts at canonical.com-20071026065843-zof5jrpbfic8cmxl
parent: andrew.bennetts at canonical.com-20071026064809-4f9fi8h5we7ob7wg
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Fri 2007-10-26 16:58:43 +1000
message:
Tweaks suggested by review.
------------------------------------------------------------
revno: 2927.2.13
merged: andrew.bennetts at canonical.com-20071026064809-4f9fi8h5we7ob7wg
parent: andrew.bennetts at canonical.com-20071026064728-d3vy41n03fb2j8ni
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Fri 2007-10-26 16:48:09 +1000
message:
Display number of file versions not referenced by their corresponding inventory (i.e. dangling versions) in bzr check output.
------------------------------------------------------------
revno: 2927.2.12
merged: andrew.bennetts at canonical.com-20071026064728-d3vy41n03fb2j8ni
parent: andrew.bennetts at canonical.com-20071026010910-5ibwby7sfga11llr
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Fri 2007-10-26 16:47:28 +1000
message:
Add a mutter as a hack give some basic progress indication in .bzr.log for the prepopulation step.
------------------------------------------------------------
revno: 2927.2.11
merged: andrew.bennetts at canonical.com-20071026010910-5ibwby7sfga11llr
parent: andrew.bennetts at canonical.com-20071025001405-aroz1xo9327ndwnn
parent: pqm at pqm.ubuntu.com-20071025232834-wcuoh6azwgez5b80
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Fri 2007-10-26 11:09:10 +1000
message:
Merge from bzr.dev.
------------------------------------------------------------
revno: 2927.2.10
merged: andrew.bennetts at canonical.com-20071025001405-aroz1xo9327ndwnn
parent: andrew.bennetts at canonical.com-20071024110815-t89wamuahli15fe4
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Thu 2007-10-25 10:14:05 +1000
message:
More docstrings, elaborate a comment with an XXX, and remove a little bit of cruft.
------------------------------------------------------------
revno: 2927.2.9
merged: andrew.bennetts at canonical.com-20071024110815-t89wamuahli15fe4
parent: andrew.bennetts at canonical.com-20071024110355-x7ikgyc6xrwexko9
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Wed 2007-10-24 21:08:15 +1000
message:
Adjust expected 'check' output in test scenarios. All test_check_reconcile now passes.
------------------------------------------------------------
revno: 2927.2.8
merged: andrew.bennetts at canonical.com-20071024110355-x7ikgyc6xrwexko9
parent: andrew.bennetts at canonical.com-20071024105639-8uskiounrird2i43
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Wed 2007-10-24 21:03:55 +1000
message:
Remove totally unreferenced file versions. All reconcile tests passing.
------------------------------------------------------------
revno: 2927.2.7
merged: andrew.bennetts at canonical.com-20071024105639-8uskiounrird2i43
parent: andrew.bennetts at canonical.com-20071024105224-ro2zlfg1iqvgs9rc
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Wed 2007-10-24 20:56:39 +1000
message:
Condense assertion message.
------------------------------------------------------------
revno: 2927.2.6
merged: andrew.bennetts at canonical.com-20071024105224-ro2zlfg1iqvgs9rc
parent: andrew.bennetts at canonical.com-20071024104558-o2rij4yn86abdqh5
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Wed 2007-10-24 20:52:24 +1000
message:
Make some more check tests pass.
------------------------------------------------------------
revno: 2927.2.5
merged: andrew.bennetts at canonical.com-20071024104558-o2rij4yn86abdqh5
parent: andrew.bennetts at canonical.com-20071024104255-c3shrqmiynjqm9n8
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Wed 2007-10-24 20:45:58 +1000
message:
Remove corrected_inventories, add proper description of corrected_fulltexts.
------------------------------------------------------------
revno: 2927.2.4
merged: andrew.bennetts at canonical.com-20071024104255-c3shrqmiynjqm9n8
parent: andrew.bennetts at canonical.com-20071024081257-w4gd9pl4dp1h8xtt
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Wed 2007-10-24 20:42:55 +1000
message:
Don't create a 'rev3' file version in the test.
------------------------------------------------------------
revno: 2927.2.3
merged: andrew.bennetts at canonical.com-20071024081257-w4gd9pl4dp1h8xtt
parent: andrew.bennetts at canonical.com-20071023075622-ikpj0dyoku3y6jsf
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Wed 2007-10-24 18:12:57 +1000
message:
Add fulltexts to avoid bug 155730.
------------------------------------------------------------
revno: 2927.2.2
merged: andrew.bennetts at canonical.com-20071023075622-ikpj0dyoku3y6jsf
parent: andrew.bennetts at canonical.com-20071023004829-l76zvyp8sglxtgpa
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Tue 2007-10-23 17:56:22 +1000
message:
Only try to check versions that actually exist in the versioned file, and do a little more muttering.
------------------------------------------------------------
revno: 2927.2.1
merged: andrew.bennetts at canonical.com-20071023004829-l76zvyp8sglxtgpa
parent: pqm at pqm.ubuntu.com-20071022212520-al7xlieh3d7ng370
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: reconcile-remove-unreferenced-file-versions-bug-155730
timestamp: Tue 2007-10-23 10:48:29 +1000
message:
Tidy a scenario's all_versions slightly.
=== modified file 'bzrlib/check.py'
--- a/bzrlib/check.py 2007-10-17 09:39:41 +0000
+++ b/bzrlib/check.py 2007-10-26 06:48:09 +0000
@@ -60,6 +60,7 @@
self.repository)
self.unreferenced_ancestors = set()
self.inconsistent_parents = []
+ self.dangling_versions = set()
def check(self):
self.repository.lock_read()
@@ -156,6 +157,9 @@
' %s has wrong parents in index: '
'%r should be %r',
revision_id, index_parents, actual_parents)
+ if self.dangling_versions:
+ note('%6d file versions are not referenced by their inventory',
+ len(self.dangling_versions))
def check_one_rev(self, rev_id):
"""Check one revision.
@@ -214,14 +218,18 @@
weave_checker = self.repository.get_versioned_file_checker(
self.planned_revisions, self.revision_versions)
result = weave_checker.check_file_version_parents(w, weave_id)
-
- for revision_id, (weave_parents,correct_parents) in result.items():
+ bad_parents, dangling_versions = result
+ bad_parents = bad_parents.items()
+ for revision_id, (weave_parents,correct_parents) in bad_parents:
self.inconsistent_parents.append(
(revision_id, weave_id, weave_parents, correct_parents))
+ if weave_parents is None:
+ weave_parents = []
unreferenced_parents = set(weave_parents)-set(correct_parents)
for unreferenced_parent in unreferenced_parents:
self.unreferenced_ancestors.add(
(weave_id, unreferenced_parent))
+ self.dangling_versions.update(dangling_versions)
self.checked_weaves[weave_id] = True
def _check_revision_tree(self, rev_id):
=== modified file 'bzrlib/reconcile.py'
--- a/bzrlib/reconcile.py 2007-10-24 05:33:57 +0000
+++ b/bzrlib/reconcile.py 2007-10-26 06:58:43 +0000
@@ -376,21 +376,53 @@
transaction = self.repo.get_transaction()
revision_versions = repository._RevisionTextVersionCache(self.repo)
versions = self.revisions.versions()
+ mutter('Prepopulating revision text cache with %d revisions',
+ len(versions))
revision_versions.prepopulate_revs(versions)
+ used_file_versions = revision_versions.used_file_versions()
for num, file_id in enumerate(self.repo.weave_store):
self.pb.update('Fixing text parents', num,
len(self.repo.weave_store))
vf = self.repo.weave_store.get_weave(file_id, transaction)
vf_checker = self.repo.get_versioned_file_checker(
- versions, revision_versions)
- versions_with_bad_parents = vf_checker.check_file_version_parents(
- vf, file_id)
- if len(versions_with_bad_parents) == 0:
+ vf.versions(), revision_versions)
+ versions_with_bad_parents, dangling_file_versions = \
+ vf_checker.check_file_version_parents(vf, file_id)
+ if (len(versions_with_bad_parents) == 0 and
+ len(dangling_file_versions) == 0):
continue
- self._fix_text_parent(file_id, vf, versions_with_bad_parents)
+ full_text_versions = set()
+ unused_versions = set()
+ for dangling_version in dangling_file_versions:
+ version = dangling_version[1]
+ if dangling_version in used_file_versions:
+ # This version *is* used by some revision, even though it
+ # isn't used by its own revision! We make sure any
+ # revision referencing it is stored as a fulltext
+ # This avoids bug 155730: it means that clients looking at
+ # inventories to determine the versions to fetch will not
+ # miss a required version. (So clients can assume that if
+ # they have a complete revision graph, and fetch all file
+ # versions named by those revisions inventories, then they
+ # will not have any missing parents for 'delta' knit
+ # records.)
+ # XXX: A better, but more difficult and slower fix would be
+ # to rewrite the inventories referencing this version.
+ full_text_versions.add(version)
+ else:
+ # This version is totally unreferenced. It should be
+ # removed.
+ unused_versions.add(version)
+ self._fix_text_parent(file_id, vf, versions_with_bad_parents,
+ full_text_versions, unused_versions)
- def _fix_text_parent(self, file_id, vf, versions_with_bad_parents):
+ def _fix_text_parent(self, file_id, vf, versions_with_bad_parents,
+ full_text_versions, unused_versions):
"""Fix bad versionedfile entries in a single versioned file."""
+ mutter('fixing text parent: %r (%d versions)', file_id,
+ len(versions_with_bad_parents))
+ mutter('(%d need to be full texts, %d are unused)',
+ len(full_text_versions), len(unused_versions))
new_vf = self.repo.weave_store.get_empty('temp:%s' % file_id,
self.transaction)
new_parents = {}
@@ -401,8 +433,16 @@
parents = vf.get_parents(version)
new_parents[version] = parents
for version in TopoSorter(new_parents.items()).iter_topo_order():
- new_vf.add_lines(version, new_parents[version],
- vf.get_lines(version))
+ if version in unused_versions:
+ continue
+ lines = vf.get_lines(version)
+ parents = new_parents[version]
+ if parents and (parents[0] in full_text_versions):
+ # Force this record to be a fulltext, not a delta.
+ new_vf._add(version, lines, parents, False,
+ None, None, None, False)
+ else:
+ new_vf.add_lines(version, parents, lines)
self.repo.weave_store.copy(new_vf, file_id, self.transaction)
self.repo.weave_store.delete('temp:%s' % file_id, self.transaction)
=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py 2007-10-25 06:17:57 +0000
+++ b/bzrlib/repository.py 2007-10-26 06:58:43 +0000
@@ -2658,6 +2658,7 @@
# XXX: this loop is very similar to
# bzrlib.fetch.Inter1and2Helper.iter_rev_trees.
while revs:
+ mutter('%d revisions left to prepopulate', len(revs))
for tree in self.repository.revision_trees(revs[:100]):
if tree.inventory.revision_id is None:
tree.inventory.revision_id = tree.get_revision_id()
@@ -2672,6 +2673,19 @@
self.revision_parents[revision_id] = parents
return parents
+ def used_file_versions(self):
+ """Return a set of (revision_id, file_id) pairs for each file version
+ referenced by any inventory cached by this _RevisionTextVersionCache.
+
+ If the entire repository has been cached, this can be used to find all
+ file versions that are actually referenced by inventories. Thus any
+ other file version is completely unused and can be removed safely.
+ """
+ result = set()
+ for inventory_summary in self.revision_versions.itervalues():
+ result.update(inventory_summary.items())
+ return result
+
class VersionedFileChecker(object):
@@ -2681,6 +2695,9 @@
self.repository = repository
def calculate_file_version_parents(self, revision_id, file_id):
+ """Calculate the correct parents for a file version according to
+ the inventories.
+ """
text_revision = self.revision_versions.get_text_version(
file_id, revision_id)
if text_revision is None:
@@ -2703,7 +2720,20 @@
return tuple(new_parents)
def check_file_version_parents(self, weave, file_id):
- result = {}
+ """Check the parents stored in a versioned file are correct.
+
+ It also detects file versions that are not referenced by their
+ corresponding revision's inventory.
+
+ :returns: A tuple of (wrong_parents, dangling_file_versions).
+ wrong_parents is a dict mapping {revision_id: (stored_parents,
+ correct_parents)} for each revision_id where the stored parents
+ are not correct. dangling_file_versions is a set of (file_id,
+ revision_id) tuples for versions that are present in this versioned
+ file, but not used by the corresponding inventory.
+ """
+ wrong_parents = {}
+ dangling_file_versions = set()
for num, revision_id in enumerate(self.planned_revisions):
correct_parents = self.calculate_file_version_parents(
revision_id, file_id)
@@ -2711,7 +2741,14 @@
continue
text_revision = self.revision_versions.get_text_version(
file_id, revision_id)
- knit_parents = tuple(weave.get_parents(text_revision))
+ try:
+ knit_parents = tuple(weave.get_parents(revision_id))
+ except errors.RevisionNotPresent:
+ knit_parents = None
+ if text_revision != revision_id:
+ # This file version is not referenced by its corresponding
+ # inventory!
+ dangling_file_versions.add((file_id, revision_id))
if correct_parents != knit_parents:
- result[revision_id] = (knit_parents, correct_parents)
- return result
+ wrong_parents[revision_id] = (knit_parents, correct_parents)
+ return wrong_parents, dangling_file_versions
=== modified file 'bzrlib/tests/repository_implementations/__init__.py'
--- a/bzrlib/tests/repository_implementations/__init__.py 2007-10-17 09:39:41 +0000
+++ b/bzrlib/tests/repository_implementations/__init__.py 2007-10-26 06:58:43 +0000
@@ -108,9 +108,9 @@
A subclass needs to define the following methods:
:populate_repository: a method to use to populate a repository with
sample revisions, inventories and file versions.
- :all_versions: all the versions in repository. run_test verifies
- that the text of each of these versions of the file is unchanged
- by the reconcile.
+ :all_versions_after_reconcile: all the versions in repository after
+ reconcile. run_test verifies that the text of each of these
+ versions of the file is unchanged by the reconcile.
:populated_parents: a list of (parents list, revision). Each version
of the file is verified to have the given parents before running
the reconcile. i.e. this is used to assert that the repo from the
@@ -119,20 +119,30 @@
of the file is verified to have the given parents after the
reconcile. i.e. this is used to assert that reconcile made the
changes we expect it to make.
+
+ A subclass may define the following optional method as well:
+ :corrected_fulltexts: a list of file versions that should be stored as
+ fulltexts (not deltas) after reconcile. run_test will verify that
+ this occurs.
"""
def __init__(self, test_case):
self.test_case = test_case
def make_one_file_inventory(self, repo, revision, parents,
- inv_revision=None, root_revision=None):
+ inv_revision=None, root_revision=None,
+ file_contents=None, make_file_version=True):
return self.test_case.make_one_file_inventory(
repo, revision, parents, inv_revision=inv_revision,
- root_revision=root_revision)
+ root_revision=root_revision, file_contents=file_contents,
+ make_file_version=make_file_version)
def add_revision(self, repo, revision_id, inv, parent_ids):
return self.test_case.add_revision(repo, revision_id, inv, parent_ids)
+ def corrected_fulltexts(self):
+ return []
+
class UndamagedRepositoryScenario(BrokenRepoScenario):
"""A scenario where the repository has no damage.
@@ -140,7 +150,7 @@
It has a single revision, 'rev1a', with a single file.
"""
- def all_versions(self):
+ def all_versions_after_reconcile(self):
return ('rev1a', )
def populated_parents(self):
@@ -168,7 +178,7 @@
'rev2', preserving 'rev1a' as a parent.
"""
- def all_versions(self):
+ def all_versions_after_reconcile(self):
return ('rev1a', 'rev1b', 'rev2')
def populated_parents(self):
@@ -218,7 +228,7 @@
inaccessbile (i.e. remove 'rev1c' from the parents of a-file's rev3).
"""
- def all_versions(self):
+ def all_versions_after_reconcile(self):
return ('rev2', 'rev3')
def populated_parents(self):
@@ -271,17 +281,22 @@
inventory.
"""
- def all_versions(self):
- return ('rev1a', 'rev2', 'rev4', 'rev2b', 'rev4', 'rev2c', 'rev5')
+ def all_versions_after_reconcile(self):
+ return ('rev1a', 'rev2c', 'rev4', 'rev5')
def populated_parents(self):
- return (
+ return [
+ (('rev1a',), 'rev2'),
+ (('rev1a',), 'rev2b'),
(('rev2',), 'rev3'),
(('rev2',), 'rev4'),
- (('rev2', 'rev2c'), 'rev5'))
+ (('rev2', 'rev2c'), 'rev5')]
def corrected_parents(self):
return (
+ # rev2 and rev2b have been removed.
+ (None, 'rev2'),
+ (None, 'rev2b'),
# rev3's accessible parent inventories all have rev1a as the last
# modifier.
(('rev1a',), 'rev3'),
@@ -294,13 +309,18 @@
def check_regexes(self):
return [
- "3 inconsistent parents",
+ "5 inconsistent parents",
+ r"a-file-id version rev2 has parents \('rev1a',\) "
+ r"but should have \(\)",
+ r"a-file-id version rev2b has parents \('rev1a',\) "
+ r"but should have \(\)",
r"a-file-id version rev3 has parents \('rev2',\) "
r"but should have \('rev1a',\)",
r"a-file-id version rev5 has parents \('rev2', 'rev2c'\) "
r"but should have \('rev2c',\)",
r"a-file-id version rev4 has parents \('rev2',\) "
r"but should have \('rev1a',\)",
+ "2 file versions are not referenced by their inventory",
]
def populate_repository(self, repo):
@@ -310,7 +330,8 @@
self.add_revision(repo, 'rev1a', inv, [])
# make rev2, with a-file.
- # a-file is unmodified from rev1a.
+ # a-file is unmodified from rev1a, and an unreferenced rev2 file
+ # version is present in the repository.
self.make_one_file_inventory(
repo, 'rev2', ['rev1a'], inv_revision='rev1a')
self.add_revision(repo, 'rev2', inv, ['rev1a'])
@@ -361,6 +382,74 @@
self.add_revision(repo, 'rev5', inv, ['rev2', 'rev2c'])
+class UnreferencedFileParentsFromNoOpMergeScenario(BrokenRepoScenario):
+ """
+ rev1a and rev1b with identical contents
+ rev2 revision has parents of [rev1a, rev1b]
+ There is a a-file:rev2 file version, not referenced by the inventory.
+ """
+
+ def all_versions_after_reconcile(self):
+ return ('rev1a', 'rev1b', 'rev2', 'rev4')
+
+ def populated_parents(self):
+ return (
+ ((), 'rev1a'),
+ ((), 'rev1b'),
+ (('rev1a', 'rev1b'), 'rev2'),
+ (None, 'rev3'),
+ (('rev2',), 'rev4'),
+ )
+
+ def corrected_parents(self):
+ return (
+ ((), 'rev1a'),
+ ((), 'rev1b'),
+ ((), 'rev2'),
+ (None, 'rev3'),
+ (('rev2',), 'rev4'),
+ )
+
+ def corrected_fulltexts(self):
+ return ['rev4']
+
+ def check_regexes(self):
+ return []
+
+ def populate_repository(self, repo):
+ # make rev1a: A well-formed revision, containing 'a-file'
+ inv1a = self.make_one_file_inventory(
+ repo, 'rev1a', [], root_revision='rev1a')
+ self.add_revision(repo, 'rev1a', inv1a, [])
+
+ # make rev1b: A well-formed revision, containing 'a-file'
+ # rev1b of a-file has the exact same contents as rev1a.
+ file_contents = repo.revision_tree('rev1a').get_file_text('a-file-id')
+ inv = self.make_one_file_inventory(
+ repo, 'rev1b', [], root_revision='rev1b',
+ file_contents=file_contents)
+ self.add_revision(repo, 'rev1b', inv, [])
+
+ # make rev2, a merge of rev1a and rev1b, with a-file.
+ # a-file is unmodified from rev1a and rev1b, but a new version is
+ # wrongly present anyway.
+ inv = self.make_one_file_inventory(
+ repo, 'rev2', ['rev1a', 'rev1b'], inv_revision='rev1a',
+ file_contents=file_contents)
+ self.add_revision(repo, 'rev2', inv, ['rev1a', 'rev1b'])
+
+ # rev3: a-file unchanged from rev2, but wrongly referencing rev2 of the
+ # file in its inventory.
+ inv = self.make_one_file_inventory(
+ repo, 'rev3', ['rev2'], inv_revision='rev2',
+ file_contents=file_contents, make_file_version=False)
+ self.add_revision(repo, 'rev3', inv, ['rev2'])
+
+ # 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'])
+
+
class TooManyParentsScenario(BrokenRepoScenario):
"""A scenario where 'broken-revision' of 'a-file' claims to have parents
['good-parent', 'bad-parent']. However 'bad-parent' is in the ancestry of
@@ -368,7 +457,7 @@
['good-parent'].
"""
- def all_versions(self):
+ def all_versions_after_reconcile(self):
return ('bad-parent', 'good-parent', 'broken-revision')
def populated_parents(self):
@@ -414,8 +503,8 @@
'modified-something-else' is the parent file version.
"""
- def all_versions(self):
- return ('basis', 'modified-something-else', 'current')
+ def all_versions_after_reconcile(self):
+ return ('basis', 'current')
def populated_parents(self):
return (
@@ -426,14 +515,17 @@
def corrected_parents(self):
return (
((), 'basis'),
- (('basis',), 'modified-something-else'),
+ (None, 'modified-something-else'),
(('basis',), 'current'))
def check_regexes(self):
return (
- '1 inconsistent parents',
+ '2 inconsistent parents',
r"\* a-file-id version current has parents "
- r"\('modified-something-else',\) but should have \('basis',\)")
+ r"\('modified-something-else',\) but should have \('basis',\)",
+ r"\* a-file-id version modified-something-else has parents "
+ r"\('basis',\) but should have \(\)",
+ )
def populate_repository(self, repo):
inv = self.make_one_file_inventory(repo, 'basis', ())
@@ -466,7 +558,7 @@
iteration order is arbitrary, it is also consistent within a single test).
"""
- def all_versions(self):
+ def all_versions_after_reconcile(self):
return ['parent-1', 'parent-2', 'broken-revision-1-2',
'broken-revision-2-1']
@@ -520,6 +612,7 @@
TooManyParentsScenario,
ClaimedFileParentDidNotModifyFileScenario,
IncorrectlyOrderedParentsScenario,
+ UnreferencedFileParentsFromNoOpMergeScenario,
]
=== modified file 'bzrlib/tests/repository_implementations/test_check_reconcile.py'
--- a/bzrlib/tests/repository_implementations/test_check_reconcile.py 2007-10-17 09:39:41 +0000
+++ b/bzrlib/tests/repository_implementations/test_check_reconcile.py 2007-10-26 06:58:43 +0000
@@ -65,7 +65,8 @@
repo.add_revision(revision_id,revision, inv)
def make_one_file_inventory(self, repo, revision, parents,
- inv_revision=None, root_revision=None):
+ inv_revision=None, root_revision=None,
+ file_contents=None, make_file_version=True):
"""Make an inventory containing a version of a file with ID 'a-file'.
The file's ID will be 'a-file', and its filename will be 'a file name',
@@ -78,6 +79,9 @@
inventory entry. Otherwise, this defaults to revision.
:param root_revision: if not None, the inventory's root.revision will
be set to this.
+ :param file_contents: if not None, the contents of this file version.
+ Otherwise a unique default (based on revision ID) will be
+ generated.
"""
inv = Inventory(revision_id=revision)
if root_revision is not None:
@@ -89,12 +93,14 @@
else:
entry.revision = revision
entry.text_size = 0
- file_contents = '%sline\n' % entry.revision
+ if file_contents is None:
+ file_contents = '%sline\n' % entry.revision
entry.text_sha1 = sha.sha(file_contents).hexdigest()
inv.add(entry)
- vf = repo.weave_store.get_weave_or_empty(file_id,
- repo.get_transaction())
- vf.add_lines(revision, parents, [file_contents])
+ if make_file_version:
+ vf = repo.weave_store.get_weave_or_empty(file_id,
+ repo.get_transaction())
+ vf.add_lines(revision, parents, [file_contents])
return inv
def require_repo_suffers_text_parent_corruption(self, repo):
@@ -106,14 +112,22 @@
return tuple(repo.weave_store.get_weave('a-file-id',
repo.get_transaction()).get_parents(revision_id))
+ def assertFileVersionAbsent(self, repo, revision_id):
+ self.assertFalse(repo.weave_store.get_weave('a-file-id',
+ repo.get_transaction()).has_version(revision_id),
+ 'File version %s wrongly present.' % (revision_id,))
+
def assertParentsMatch(self, expected_parents_for_versions, repo,
when_description):
for expected_parents, version in expected_parents_for_versions:
- found_parents = self.file_parents(repo, version)
- self.assertEqual(expected_parents, found_parents,
- "Expected version %s of a-file-id to have parents %s %s "
- "reconcile, but it has %s instead."
- % (version, expected_parents, when_description, found_parents))
+ if expected_parents is None:
+ self.assertFileVersionAbsent(repo, version)
+ else:
+ found_parents = self.file_parents(repo, version)
+ self.assertEqual(expected_parents, found_parents,
+ "%s reconcile %s has parents %s, should have %s."
+ % (when_description, version, found_parents,
+ expected_parents))
def shas_for_versions_of_file(self, repo, versions):
"""Get the SHA-1 hashes of the versions of 'a-file' in the repository.
@@ -134,14 +148,22 @@
repo = self.make_populated_repository(scenario.populate_repository)
self.require_repo_suffers_text_parent_corruption(repo)
self.assertParentsMatch(scenario.populated_parents(), repo, 'before')
- vf_shas = self.shas_for_versions_of_file(repo, scenario.all_versions())
+ vf_shas = self.shas_for_versions_of_file(
+ repo, scenario.all_versions_after_reconcile())
result = repo.reconcile(thorough=True)
self.assertParentsMatch(scenario.corrected_parents(), repo, 'after')
# The contents of the versions in the versionedfile should be the same
# after the reconcile.
self.assertEqual(
vf_shas,
- self.shas_for_versions_of_file(repo, scenario.all_versions()))
+ self.shas_for_versions_of_file(
+ repo, scenario.all_versions_after_reconcile()))
+
+ for file_version in scenario.corrected_fulltexts():
+ vf = repo.weave_store.get_weave(
+ 'a-file-id', repo.get_transaction())
+ self.assertEqual('fulltext', vf._index.get_method(file_version),
+ '%r should be fulltext' % (file_version,))
def test_check_behaviour(self):
"""Populate a repository and check it, and verify the output."""
More information about the bazaar-commits
mailing list