Rev 2880: (robertc) Have CommitBuilder.record_entry_contents return inventory delta information. (Robert Collins). in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Wed Oct 3 08:01:17 BST 2007
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 2880
revision-id: pqm at pqm.ubuntu.com-20071003070115-95pox4ok1e47a7v0
parent: pqm at pqm.ubuntu.com-20071003050442-e0x9ofdfo0hwxnal
parent: robertc at robertcollins.net-20071003061506-2hbze42e1sokni8j
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2007-10-03 08:01:15 +0100
message:
(robertc) Have CommitBuilder.record_entry_contents return inventory delta information. (Robert Collins).
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/commit.py commit.py-20050511101309-79ec1a0168e0e825
bzrlib/errors.py errors.py-20050309040759-20512168c4e14fbd
bzrlib/repository.py rev_storage.py-20051111201905-119e9401e46257e3
bzrlib/tests/repository_implementations/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
------------------------------------------------------------
revno: 2871.1.4
merged: robertc at robertcollins.net-20071003061506-2hbze42e1sokni8j
parent: robertc at robertcollins.net-20070928070556-lxsw7332u3kdltwz
parent: pqm at pqm.ubuntu.com-20071003050442-e0x9ofdfo0hwxnal
committer: Robert Collins <robertc at robertcollins.net>
branch nick: commit-builder
timestamp: Wed 2007-10-03 16:15:06 +1000
message:
Merge bzr.dev.
------------------------------------------------------------
revno: 2871.1.3
merged: robertc at robertcollins.net-20070928070556-lxsw7332u3kdltwz
parent: robertc at robertcollins.net-20070928012059-sbuwqzv68dlbb9z9
committer: Robert Collins <robertc at robertcollins.net>
branch nick: commit-builder
timestamp: Fri 2007-09-28 17:05:56 +1000
message:
* The CommitBuilder method ``record_entry_contents`` now returns summary
information about the effect of the commit on the repository. This tuple
contains an inventory delta item if the entry changed from the basis, and a
boolean indicating whether a new file graph node was recorded.
(Robert Collins)
------------------------------------------------------------
revno: 2871.1.2
merged: robertc at robertcollins.net-20070928012059-sbuwqzv68dlbb9z9
parent: robertc at robertcollins.net-20070928005033-k2aj7takjzzfo3vn
committer: Robert Collins <robertc at robertcollins.net>
branch nick: commit-builder
timestamp: Fri 2007-09-28 11:20:59 +1000
message:
* ``CommitBuilder.record_entry_contents`` now requires the root entry of a
tree be supplied to it, previously failing to do so would trigger a
deprecation warning. (Robert Collins)
=== modified file 'NEWS'
--- a/NEWS 2007-10-03 05:04:42 +0000
+++ b/NEWS 2007-10-03 06:15:06 +0000
@@ -119,6 +119,10 @@
API BREAKS:
+ * ``CommitBuilder.record_entry_contents`` now requires the root entry of a
+ tree be supplied to it, previously failing to do so would trigger a
+ deprecation warning. (Robert Collins)
+
* ``KnitVersionedFile.add*`` will no longer cache added records even when
enable_cache() has been called - the caching feature is now exclusively for
reading existing data. (Robert Collins)
@@ -183,6 +187,12 @@
* Knit joining has been enhanced to support plain to annotated conversion
and annotated to plain conversion. (Ian Clatworthy)
+ * The CommitBuilder method ``record_entry_contents`` now returns summary
+ information about the effect of the commit on the repository. This tuple
+ contains an inventory delta item if the entry changed from the basis, and a
+ boolean indicating whether a new file graph node was recorded.
+ (Robert Collins)
+
TESTING:
* When running bzr commands within the test suite, internal exceptions are
=== modified file 'bzrlib/commit.py'
--- a/bzrlib/commit.py 2007-10-02 01:06:55 +0000
+++ b/bzrlib/commit.py 2007-10-03 06:15:06 +0000
@@ -665,8 +665,9 @@
# required after that changes.
if len(self.parents) > 1:
ie.revision = None
- if self.builder.record_entry_contents(ie, self.parent_invs, path,
- self.basis_tree, None):
+ delta, version_recorded = self.builder.record_entry_contents(
+ ie, self.parent_invs, path, self.basis_tree, None)
+ if version_recorded:
self.any_entries_changed = True
# note that deletes have occurred
@@ -784,8 +785,9 @@
else:
ie = existing_ie.copy()
ie.revision = None
- if self.builder.record_entry_contents(ie, self.parent_invs,
- path, self.work_tree, content_summary):
+ delta, version_recorded = self.builder.record_entry_contents(ie,
+ self.parent_invs, path, self.work_tree, content_summary)
+ if version_recorded:
self.any_entries_changed = True
if report_changes:
self._report_change(ie, path)
=== modified file 'bzrlib/errors.py'
--- a/bzrlib/errors.py 2007-10-02 06:13:56 +0000
+++ b/bzrlib/errors.py 2007-10-03 06:15:06 +0000
@@ -260,6 +260,12 @@
self.revision_id = revision_id
+class RootMissing(InternalBzrError):
+
+ _fmt = ("The root entry of a tree must be the first entry supplied to "
+ "record_entry_contents.")
+
+
class NoHelpTopic(BzrError):
_fmt = ("No help could be found for '%(topic)s'. "
=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py 2007-10-03 04:23:01 +0000
+++ b/bzrlib/repository.py 2007-10-03 06:15:06 +0000
@@ -194,18 +194,23 @@
commit.
:param tree: The tree that is being committed.
"""
- if ie.parent_id is not None:
- # if ie is not root, add a root automatically.
- symbol_versioning.warn('Root entry should be supplied to'
- ' record_entry_contents, as of bzr 0.10.',
- DeprecationWarning, stacklevel=2)
- self.record_entry_contents(tree.inventory.root.copy(), parent_invs,
- '', tree, tree.path_content_summary(''))
+ # In this revision format, root entries have no knit or weave When
+ # serializing out to disk and back in root.revision is always
+ # _new_revision_id
+ ie.revision = self._new_revision_id
+
+ def _get_delta(self, ie, basis_inv, path):
+ """Get a delta against the basis inventory for ie."""
+ if ie.file_id not in basis_inv:
+ # add
+ return (None, path, ie.file_id, ie)
+ elif ie != basis_inv[ie.file_id]:
+ # common but altered
+ # TODO: avoid tis id2path call.
+ return (basis_inv.id2path(ie.file_id), path, ie.file_id, ie)
else:
- # In this revision format, root entries have no knit or weave When
- # serializing out to disk and back in root.revision is always
- # _new_revision_id
- ie.revision = self._new_revision_id
+ # common, unaltered
+ return None
def record_entry_contents(self, ie, parent_invs, path, tree,
content_summary):
@@ -223,11 +228,16 @@
content - stat, length, exec, sha/link target. This is only
accessed when the entry has a revision of None - that is when it is
a candidate to commit.
- :return: True if a new version of the entry has been recorded.
- (Committing a merge where a file was only changed on the other side
- will not return True.)
+ :return: A tuple (change_delta, version_recorded). change_delta is
+ an inventory_delta change for this entry against the basis tree of
+ the commit, or None if no change occured against the basis tree.
+ version_recorded is True if a new version of the entry has been
+ recorded. For instance, committing a merge where a file was only
+ changed on the other side will return (delta, False).
"""
if self.new_inventory.root is None:
+ if ie.parent_id is not None:
+ raise errors.RootMissing()
self._check_root(ie, parent_invs, tree)
if ie.revision is None:
kind = content_summary[0]
@@ -245,11 +255,38 @@
assert ie.kind == kind
self.new_inventory.add(ie)
+ # TODO: slow, take it out of the inner loop.
+ try:
+ basis_inv = parent_invs[0]
+ except IndexError:
+ basis_inv = Inventory(root_id=None)
+
# ie.revision is always None if the InventoryEntry is considered
# for committing. We may record the previous parents revision if the
# content is actually unchanged against a sole head.
if ie.revision is not None:
- return ie.revision == self._new_revision_id and (path != '' or
+ if self._versioned_root or path != '':
+ # not considered for commit
+ delta = None
+ else:
+ # repositories that do not version the root set the root's
+ # revision to the new commit even when no change occurs, and
+ # this masks when a change may have occurred against the basis,
+ # so calculate if one happened.
+ if ie.file_id not in basis_inv:
+ # add
+ delta = (None, path, ie.file_id, ie)
+ else:
+ basis_id = basis_inv[ie.file_id]
+ if basis_id.name != '':
+ # not the root
+ delta = (basis_inv.id2path(ie.file_id), path,
+ ie.file_id, ie)
+ else:
+ # common, unaltered
+ delta = None
+ # not considered for commit, OR, for non-rich-root
+ return delta, ie.revision == self._new_revision_id and (path != '' or
self._versioned_root)
# XXX: Friction: parent_candidates should return a list not a dict
@@ -301,7 +338,7 @@
ie.text_size = parent_entry.text_size
ie.text_sha1 = parent_entry.text_sha1
ie.executable = parent_entry.executable
- return
+ return self._get_delta(ie, basis_inv, path), False
else:
# Either there is only a hash change(no hash cache entry,
# or same size content change), or there is no change on
@@ -326,13 +363,13 @@
ie.text_size = parent_entry.text_size
ie.text_sha1 = parent_entry.text_sha1
ie.executable = parent_entry.executable
- return
+ return self._get_delta(ie, basis_inv, path), False
elif kind == 'directory':
if not store:
# all data is meta here, nothing specific to directory, so
# carry over:
ie.revision = parent_entry.revision
- return
+ return self._get_delta(ie, basis_inv, path), False
lines = []
self._add_text_to_weave(ie.file_id, lines, heads, None)
elif kind == 'symlink':
@@ -346,7 +383,7 @@
# unchanged, carry over.
ie.revision = parent_entry.revision
ie.symlink_target = parent_entry.symlink_target
- return
+ return self._get_delta(ie, basis_inv, path), False
ie.symlink_target = current_link_target
lines = []
self._add_text_to_weave(ie.file_id, lines, heads, None)
@@ -358,14 +395,14 @@
# unchanged, carry over.
ie.reference_revision = parent_entry.reference_revision
ie.revision = parent_entry.revision
- return
+ return self._get_delta(ie, basis_inv, path), False
ie.reference_revision = content_summary[3]
lines = []
self._add_text_to_weave(ie.file_id, lines, heads, None)
else:
raise NotImplementedError('unknown kind')
ie.revision = self._new_revision_id
- return True
+ return self._get_delta(ie, basis_inv, path), True
def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
versionedfile = self.repository.weave_store.get_weave_or_empty(
@@ -401,8 +438,6 @@
commit.
:param tree: The tree that is being committed.
"""
- # ie must be root for this builder
- assert ie.parent_id is None
######################################################################
=== modified file 'bzrlib/tests/repository_implementations/test_commit_builder.py'
--- a/bzrlib/tests/repository_implementations/test_commit_builder.py 2007-09-27 21:11:38 +0000
+++ b/bzrlib/tests/repository_implementations/test_commit_builder.py 2007-10-03 06:15:06 +0000
@@ -16,6 +16,7 @@
"""Tests for repository commit builder."""
+from copy import copy
import errno
import os
import sys
@@ -121,23 +122,18 @@
self.assertEqual(revision_id,
tree.branch.repository.get_inventory(revision_id).revision_id)
- def test_commit_without_root(self):
- """This should cause a deprecation warning, not an assertion failure"""
+ def test_commit_without_root_errors(self):
tree = self.make_branch_and_tree(".")
tree.lock_write()
try:
- if tree.branch.repository.supports_rich_root():
- raise tests.TestSkipped('Format requires root')
self.build_tree(['foo'])
tree.add('foo', 'foo-id')
entry = tree.inventory['foo-id']
builder = tree.branch.get_commit_builder([])
- self.callDeprecated(['Root entry should be supplied to'
- ' record_entry_contents, as of bzr 0.10.'],
+ self.assertRaises(errors.RootMissing,
builder.record_entry_contents, entry, [], 'foo', tree,
tree.path_content_summary('foo'))
- builder.finish_inventory()
- rev_id = builder.commit('foo bar')
+ builder.abort()
finally:
tree.unlock()
@@ -152,9 +148,11 @@
try:
ie = inventory.make_entry('directory', '', None,
tree.inventory.root.file_id)
- self.assertFalse(builder.record_entry_contents(
+ delta, version_recorded = builder.record_entry_contents(
ie, [parent_tree.inventory], '', tree,
- tree.path_content_summary('')))
+ tree.path_content_summary(''))
+ self.assertFalse(version_recorded)
+ self.assertEqual(None, delta)
builder.abort()
except:
builder.abort()
@@ -229,7 +227,7 @@
def _add_commit_check_unchanged(self, tree, name):
tree.add([name], [name + 'id'])
rev1 = tree.commit('')
- rev2 = tree.commit('')
+ rev2 = self.mini_commit(tree, name, name, False, False)
tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
self.assertEqual(rev1, tree2.inventory[name + 'id'].revision)
@@ -323,15 +321,37 @@
tree.add([name], [name + 'id'])
rev1 = tree.commit('')
changer()
+ rev2 = self.mini_commit(tree, name, tree.id2path(name + 'id'))
+ tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
+ self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
+ self.assertEqual(rev2, tree2.inventory[name + 'id'].revision)
+ self.assertFileAncestry([rev1, rev2], tree, name)
+
+ def mini_commit(self, tree, name, new_name, records_version=True,
+ delta_against_basis=True):
+ """Perform a miniature commit looking for record entry results.
+
+ :param tree: The tree to commit.
+ :param name: The path in the basis tree of the tree being committed.
+ :param new_name: The path in the tree being committed.
+ :param records_version: True if the commit of new_name is expected to
+ record a new version.
+ :param delta_against_basis: True of the commit of new_name is expected
+ to have a delta against the basis.
+ """
tree.lock_write()
try:
# mini manual commit here so we can check the return of
# record_entry_contents.
- builder = tree.branch.get_commit_builder([tree.last_revision()])
+ parent_ids = tree.get_parent_ids()
+ builder = tree.branch.get_commit_builder(parent_ids)
parent_tree = tree.basis_tree()
parent_tree.lock_read()
self.addCleanup(parent_tree.unlock)
parent_invs = [parent_tree.inventory]
+ for parent_id in parent_ids[1:]:
+ parent_invs.append(tree.branch.repository.revision_tree(
+ parent_id).inventory)
# root
builder.record_entry_contents(
inventory.make_entry('directory', '', None,
@@ -345,13 +365,25 @@
return builder.record_entry_contents(ie, parent_invs, path,
tree, tree.path_content_summary(path))
- file_id = name + 'id'
+ file_id = tree.path2id(new_name)
parent_id = tree.inventory[file_id].parent_id
if parent_id != tree.inventory.root.file_id:
commit_id(parent_id)
# because a change of some sort is meant to have occurred,
# recording the entry must return True.
- self.assertTrue(commit_id(file_id))
+ delta, version_recorded = commit_id(file_id)
+ if records_version:
+ self.assertTrue(version_recorded)
+ else:
+ self.assertFalse(version_recorded)
+ new_entry = builder.new_inventory[file_id]
+ if delta_against_basis:
+ expected_delta = (name, new_name, file_id, new_entry)
+ else:
+ expected_delta = None
+ if expected_delta != delta:
+ import pdb;pdb.set_trace()
+ self.assertEqual(expected_delta, delta)
builder.finish_inventory()
rev2 = builder.commit('')
tree.set_parent_ids([rev2])
@@ -361,10 +393,7 @@
raise
else:
tree.unlock()
- tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
- self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
- self.assertEqual(rev2, tree2.inventory[name + 'id'].revision)
- self.assertFileAncestry([rev1, rev2], tree, name)
+ return rev2
def assertFileAncestry(self, ancestry, tree, name, alt_ancestry=None):
# all the changes that have occured should be in the ancestry
@@ -413,7 +442,7 @@
rev2 = self._rename_in_tree(tree1, name)
rev3 = self._rename_in_tree(tree2, name)
tree1.merge_from_branch(tree2.branch)
- rev4 = tree1.commit('')
+ rev4 = self.mini_commit(tree1, 'new_' + name, 'new_' + name)
tree3, = self._get_revtrees(tree1, [rev4])
self.assertEqual(rev4, tree3.inventory[name + 'id'].revision)
# TODO: change this to an assertFileGraph call to check the
@@ -445,7 +474,7 @@
# change on the other side to merge back
rev2 = self._rename_in_tree(tree2, name)
tree1.merge_from_branch(tree2.branch)
- rev3 = tree1.commit('')
+ rev3 = self.mini_commit(tree1, name, 'new_' + name, False)
tree3, = self._get_revtrees(tree1, [rev2])
self.assertEqual(rev2, tree3.inventory[name + 'id'].revision)
self.assertFileAncestry([rev1, rev2], tree1, name)
More information about the bazaar-commits
mailing list