Rev 4716: Merge the 2.0.x stable series into bzr.dev. in http://bzr.arbash-meinel.com/branches/bzr/jam-integration
John Arbash Meinel
john at arbash-meinel.com
Fri Sep 25 22:24:54 BST 2009
At http://bzr.arbash-meinel.com/branches/bzr/jam-integration
------------------------------------------------------------
revno: 4716 [merge]
revision-id: john at arbash-meinel.com-20090925212421-2xhep7gf3e4717op
parent: pqm at pqm.ubuntu.com-20090924094523-nsz6mp3qwor3xpp3
parent: pqm at pqm.ubuntu.com-20090925210528-kxssbjs9to8ob22a
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: jam-integration
timestamp: Fri 2009-09-25 16:24:21 -0500
message:
Merge the 2.0.x stable series into bzr.dev.
This includes the 2.0.0 release and the update for CHKInventory.filter()
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/inventory.py inventory.py-20050309040759-6648b84ca2005b37
bzrlib/tests/per_inventory/__init__.py __init__.py-20070821044532-olbadbokgv3qv1yd-1
bzrlib/tests/per_inventory/basics.py basics.py-20070903044446-kdjwbiu1p1zi9phs-1
bzrlib/tests/test_inv.py testinv.py-20050722220913-1dc326138d1a5892
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS 2009-09-24 09:45:23 +0000
+++ b/NEWS 2009-09-25 21:24:21 +0000
@@ -183,13 +183,38 @@
Bug Fixes
*********
+* Improve the time for ``bzr log DIR`` for 2a format repositories.
+ We had been using the same code path as for <2a formats, which required
+ iterating over all objects in all revisions.
+ (John Arbash Meinel, #374730)
+
* Make sure that we unlock the tree if we fail to create a TreeTransform
object when doing a merge, and there is limbo, or pending-deletions
directory. (Gary van der Merwe, #427773)
-bzr 2.0.0 (Not Released Yet)
-############################
+bzr 2.0.0
+#########
+
+:2.0.0: 2009-09-22
+:Codename: Instant Karma
+
+This release of Bazaar makes the 2a (previously 'brisbane-core') format
+the default when new branches or repositories are created. This format is
+substantially smaller and faster for many operations. Most of the work in
+this release focuses on bug fixes and stabilization, covering both 2a and
+previous formats. (See the Upgrade Guide for information on migrating
+existing projects.)
+
+This release also improves the documentation content and presentation,
+including adding Windows HtmlHelp manuals.
+
+The Bazaar team decided that 2.0 will be a long-term supported release,
+with bugfix-only 2.0.x releases based on it, continuing for at least six
+months or until the following stable release.
+
+Changes from 2.0.0rc2 to final
+******************************
* Officially branded as 2.0.0 rather than 2.0 to clarify between things
that "want to happen on the 2.0.x stable series" versus things that want
@@ -297,14 +322,6 @@
:Codename: no worries
:2.0.0rc1: 2009-08-26
-This release of Bazaar makes 2a 'brisbane-core' format the
-default. Most of the work in this release now focuses on bug
-fixes and stabilization, covering both 2a and previous formats.
-
-The Bazaar team decided that 2.0 will be a long-term supported
-release, with bugfix-only releases based on it, continuing for at
-least six months or until the following stable release.
-
Compatibility Breaks
********************
=== modified file 'bzrlib/inventory.py'
--- a/bzrlib/inventory.py 2009-08-30 23:51:10 +0000
+++ b/bzrlib/inventory.py 2009-09-25 21:24:21 +0000
@@ -1197,6 +1197,14 @@
raise errors.InconsistentDelta("<deleted>", parent_id,
"The file id was deleted but its children were not deleted.")
+ def create_by_apply_delta(self, inventory_delta, new_revision_id,
+ propagate_caches=False):
+ """See CHKInventory.create_by_apply_delta()"""
+ new_inv = self.copy()
+ new_inv.apply_delta(inventory_delta)
+ new_inv.revision_id = new_revision_id
+ return new_inv
+
def _set_root(self, ie):
self.root = ie
self._byid = {self.root.file_id: self.root}
@@ -1546,6 +1554,123 @@
else:
raise ValueError("unknown kind %r" % entry.kind)
+ def _expand_fileids_to_parents_and_children(self, file_ids):
+ """Give a more wholistic view starting with the given file_ids.
+
+ For any file_id which maps to a directory, we will include all children
+ of that directory. We will also include all directories which are
+ parents of the given file_ids, but we will not include their children.
+
+ eg:
+ / # TREE_ROOT
+ foo/ # foo-id
+ baz # baz-id
+ frob/ # frob-id
+ fringle # fringle-id
+ bar/ # bar-id
+ bing # bing-id
+
+ if given [foo-id] we will include
+ TREE_ROOT as interesting parents
+ and
+ foo-id, baz-id, frob-id, fringle-id
+ As interesting ids.
+ """
+ interesting = set()
+ # TODO: Pre-pass over the list of fileids to see if anything is already
+ # deserialized in self._fileid_to_entry_cache
+
+ directories_to_expand = set()
+ children_of_parent_id = {}
+ # It is okay if some of the fileids are missing
+ for entry in self._getitems(file_ids):
+ if entry.kind == 'directory':
+ directories_to_expand.add(entry.file_id)
+ interesting.add(entry.parent_id)
+ children_of_parent_id.setdefault(entry.parent_id, []
+ ).append(entry.file_id)
+
+ # Now, interesting has all of the direct parents, but not the
+ # parents of those parents. It also may have some duplicates with
+ # specific_fileids
+ remaining_parents = interesting.difference(file_ids)
+ # When we hit the TREE_ROOT, we'll get an interesting parent of None,
+ # but we don't actually want to recurse into that
+ interesting.add(None) # this will auto-filter it in the loop
+ remaining_parents.discard(None)
+ while remaining_parents:
+ if None in remaining_parents:
+ import pdb; pdb.set_trace()
+ next_parents = set()
+ for entry in self._getitems(remaining_parents):
+ next_parents.add(entry.parent_id)
+ children_of_parent_id.setdefault(entry.parent_id, []
+ ).append(entry.file_id)
+ # Remove any search tips we've already processed
+ remaining_parents = next_parents.difference(interesting)
+ interesting.update(remaining_parents)
+ # We should probably also .difference(directories_to_expand)
+ interesting.update(file_ids)
+ interesting.discard(None)
+ while directories_to_expand:
+ # Expand directories by looking in the
+ # parent_id_basename_to_file_id map
+ keys = [(f,) for f in directories_to_expand]
+ directories_to_expand = set()
+ items = self.parent_id_basename_to_file_id.iteritems(keys)
+ next_file_ids = set([item[1] for item in items])
+ next_file_ids = next_file_ids.difference(interesting)
+ interesting.update(next_file_ids)
+ for entry in self._getitems(next_file_ids):
+ if entry.kind == 'directory':
+ directories_to_expand.add(entry.file_id)
+ children_of_parent_id.setdefault(entry.parent_id, []
+ ).append(entry.file_id)
+ return interesting, children_of_parent_id
+
+ def filter(self, specific_fileids):
+ """Get an inventory view filtered against a set of file-ids.
+
+ Children of directories and parents are included.
+
+ The result may or may not reference the underlying inventory
+ so it should be treated as immutable.
+ """
+ (interesting,
+ parent_to_children) = self._expand_fileids_to_parents_and_children(
+ specific_fileids)
+ # There is some overlap here, but we assume that all interesting items
+ # are in the _fileid_to_entry_cache because we had to read them to
+ # determine if they were a dir we wanted to recurse, or just a file
+ # This should give us all the entries we'll want to add, so start
+ # adding
+ other = Inventory(self.root_id)
+ other.root.revision = self.root.revision
+ other.revision_id = self.revision_id
+ if not interesting or not parent_to_children:
+ # empty filter, or filtering entrys that don't exist
+ # (if even 1 existed, then we would have populated
+ # parent_to_children with at least the tree root.)
+ return other
+ cache = self._fileid_to_entry_cache
+ try:
+ remaining_children = collections.deque(parent_to_children[self.root_id])
+ except:
+ import pdb; pdb.set_trace()
+ raise
+ while remaining_children:
+ file_id = remaining_children.popleft()
+ ie = cache[file_id]
+ if ie.kind == 'directory':
+ ie = ie.copy() # We create a copy to depopulate the .children attribute
+ # TODO: depending on the uses of 'other' we should probably alwyas
+ # '.copy()' to prevent someone from mutating other and
+ # invaliding our internal cache
+ other.add(ie)
+ if file_id in parent_to_children:
+ remaining_children.extend(parent_to_children[file_id])
+ return other
+
@staticmethod
def _bytes_to_utf8name_key(bytes):
"""Get the file_id, revision_id key out of bytes."""
@@ -1885,6 +2010,27 @@
# really we're passing an inventory, not a tree...
raise errors.NoSuchId(self, file_id)
+ def _getitems(self, file_ids):
+ """Similar to __getitem__, but lets you query for multiple.
+
+ The returned order is undefined. And currently if an item doesn't
+ exist, it isn't included in the output.
+ """
+ result = []
+ remaining = []
+ for file_id in file_ids:
+ entry = self._fileid_to_entry_cache.get(file_id, None)
+ if entry is None:
+ remaining.append(file_id)
+ else:
+ result.append(entry)
+ file_keys = [(f,) for f in remaining]
+ for file_key, value in self.id_to_entry.iteritems(file_keys):
+ entry = self._bytes_to_entry(value)
+ result.append(entry)
+ self._fileid_to_entry_cache[entry.file_id] = entry
+ return result
+
def has_id(self, file_id):
# Perhaps have an explicit 'contains' method on CHKMap ?
if self._fileid_to_entry_cache.get(file_id, None) is not None:
=== modified file 'bzrlib/tests/per_inventory/__init__.py'
--- a/bzrlib/tests/per_inventory/__init__.py 2009-07-10 07:14:02 +0000
+++ b/bzrlib/tests/per_inventory/__init__.py 2009-09-24 18:51:41 +0000
@@ -16,15 +16,52 @@
"""Tests for different inventory implementations"""
-from bzrlib.tests import multiply_tests
+from bzrlib import (
+ groupcompress,
+ tests,
+ )
def load_tests(basic_tests, module, loader):
"""Generate suite containing all parameterized tests"""
modules_to_test = [
'bzrlib.tests.per_inventory.basics',
]
- from bzrlib.inventory import Inventory
- scenarios = [('Inventory', {'inventory_class':Inventory})]
+ from bzrlib.inventory import Inventory, CHKInventory
+
+ def inv_to_chk_inv(test, inv):
+ """CHKInventory needs a backing VF, so we create one."""
+ factory = groupcompress.make_pack_factory(True, True, 1)
+ trans = test.get_transport('chk-inv')
+ trans.ensure_base()
+ vf = factory(trans)
+ # We intentionally use a non-standard maximum_size, so that we are more
+ # likely to trigger splits, and get increased test coverage.
+ chk_inv = CHKInventory.from_inventory(vf, inv,
+ maximum_size=100,
+ search_key_name='hash-255-way')
+ return chk_inv
+ scenarios = [('Inventory', {'_inventory_class': Inventory,
+ '_inv_to_test_inv': lambda test, inv: inv
+ }),
+ ('CHKInventory', {'_inventory_class': CHKInventory,
+ '_inv_to_test_inv': inv_to_chk_inv,
+ })]
# add the tests for the sub modules
- return multiply_tests(loader.loadTestsFromModuleNames(modules_to_test),
+ return tests.multiply_tests(
+ loader.loadTestsFromModuleNames(modules_to_test),
scenarios, basic_tests)
+
+
+class TestCaseWithInventory(tests.TestCaseWithMemoryTransport):
+
+ _inventory_class = None # set by load_tests
+ _inv_to_test_inv = None # set by load_tests
+
+ def make_test_inventory(self):
+ """Return an instance of the Inventory class under test."""
+ return self._inventory_class()
+
+ def inv_to_test_inv(self, inv):
+ """Convert a regular Inventory object into an inventory under test."""
+ return self._inv_to_test_inv(self, inv)
+
=== modified file 'bzrlib/tests/per_inventory/basics.py'
--- a/bzrlib/tests/per_inventory/basics.py 2009-07-17 00:49:02 +0000
+++ b/bzrlib/tests/per_inventory/basics.py 2009-09-24 20:09:36 +0000
@@ -21,6 +21,8 @@
from bzrlib import (
errors,
+ inventory,
+ osutils,
)
from bzrlib.inventory import (
@@ -28,22 +30,36 @@
InventoryEntry,
InventoryFile,
InventoryLink,
- ROOT_ID,
TreeReference,
)
-from bzrlib.tests import (
- TestCase,
- )
-
-
-class TestInventory(TestCase):
-
- def make_inventory(self, root_id):
- return self.inventory_class(root_id=root_id)
+from bzrlib.tests.per_inventory import TestCaseWithInventory
+
+
+
+class TestInventory(TestCaseWithInventory):
+
+ def make_init_inventory(self):
+ inv = inventory.Inventory('tree-root')
+ inv.revision = 'initial-rev'
+ inv.root.revision = 'initial-rev'
+ return self.inv_to_test_inv(inv)
+
+ def make_file(self, file_id, name, parent_id, content='content\n',
+ revision='new-test-rev'):
+ ie = InventoryFile(file_id, name, parent_id)
+ ie.text_sha1 = osutils.sha_string(content)
+ ie.text_size = len(content)
+ ie.revision = revision
+ return ie
+
+ def make_link(self, file_id, name, parent_id, target='link-target\n'):
+ ie = InventoryLink(file_id, name, parent_id)
+ ie.symlink_target = target
+ return ie
def prepare_inv_with_nested_dirs(self):
- inv = self.make_inventory('tree-root')
+ inv = inventory.Inventory('tree-root')
for args in [('src', 'directory', 'src-id'),
('doc', 'directory', 'doc-id'),
('src/hello.c', 'file', 'hello-id'),
@@ -53,172 +69,98 @@
('src/zz.c', 'file', 'zzc-id'),
('src/sub/a', 'file', 'a-id'),
('Makefile', 'file', 'makefile-id')]:
- inv.add_path(*args)
- return inv
-
-
-class TestInventoryUpdates(TestInventory):
-
- def test_creation_from_root_id(self):
- # iff a root id is passed to the constructor, a root directory is made
- inv = self.make_inventory(root_id='tree-root')
- self.assertNotEqual(None, inv.root)
- self.assertEqual('tree-root', inv.root.file_id)
-
- def test_add_path_of_root(self):
- # if no root id is given at creation time, there is no root directory
- inv = self.make_inventory(root_id=None)
- self.assertIs(None, inv.root)
- # add a root entry by adding its path
- ie = inv.add_path("", "directory", "my-root")
- self.assertEqual("my-root", ie.file_id)
- self.assertIs(ie, inv.root)
-
- def test_add_path(self):
- inv = self.make_inventory(root_id='tree_root')
- ie = inv.add_path('hello', 'file', 'hello-id')
- self.assertEqual('hello-id', ie.file_id)
- self.assertEqual('file', ie.kind)
-
- def test_copy(self):
- """Make sure copy() works and creates a deep copy."""
- inv = self.make_inventory(root_id='some-tree-root')
- ie = inv.add_path('hello', 'file', 'hello-id')
- inv2 = inv.copy()
- inv.root.file_id = 'some-new-root'
- ie.name = 'file2'
- self.assertEqual('some-tree-root', inv2.root.file_id)
- self.assertEqual('hello', inv2['hello-id'].name)
-
- def test_copy_empty(self):
- """Make sure an empty inventory can be copied."""
- inv = self.make_inventory(root_id=None)
- inv2 = inv.copy()
- self.assertIs(None, inv2.root)
-
- def test_copy_copies_root_revision(self):
- """Make sure the revision of the root gets copied."""
- inv = self.make_inventory(root_id='someroot')
- inv.root.revision = 'therev'
- inv2 = inv.copy()
- self.assertEquals('someroot', inv2.root.file_id)
- self.assertEquals('therev', inv2.root.revision)
-
- def test_create_tree_reference(self):
- inv = self.make_inventory('tree-root-123')
- inv.add(TreeReference('nested-id', 'nested', parent_id='tree-root-123',
- revision='rev', reference_revision='rev2'))
-
- def test_error_encoding(self):
- inv = self.make_inventory('tree-root')
- inv.add(InventoryFile('a-id', u'\u1234', 'tree-root'))
- e = self.assertRaises(errors.InconsistentDelta, inv.add,
- InventoryFile('b-id', u'\u1234', 'tree-root'))
- self.assertContainsRe(str(e), r'\\u1234')
-
- def test_add_recursive(self):
- parent = InventoryDirectory('src-id', 'src', 'tree-root')
- child = InventoryFile('hello-id', 'hello.c', 'src-id')
- parent.children[child.file_id] = child
- inv = self.make_inventory('tree-root')
- inv.add(parent)
- self.assertEqual('src/hello.c', inv.id2path('hello-id'))
-
-
-class TestInventoryApplyDelta(TestInventory):
+ ie = inv.add_path(*args)
+ if args[1] == 'file':
+ ie.text_sha1 = osutils.sha_string('content\n')
+ ie.text_size = len('content\n')
+ return self.inv_to_test_inv(inv)
+
+
+class TestInventoryCreateByApplyDelta(TestInventory):
"""A subset of the inventory delta application tests.
See test_inv which has comprehensive delta application tests for
- inventories, dirstate, and repository based inventories, unlike the tests
- here which only test in-memory implementations that can support a plain
- 'apply_delta'.
+ inventories, dirstate, and repository based inventories.
"""
-
- def test_apply_delta_add(self):
- inv = self.make_inventory('tree-root')
- inv.apply_delta([
- (None, "a", "a-id", InventoryFile('a-id', 'a', 'tree-root')),
- ])
- self.assertEqual('a', inv.id2path('a-id'))
-
- def test_apply_delta_delete(self):
- inv = self.make_inventory('tree-root')
- inv.apply_delta([
- (None, "a", "a-id", InventoryFile('a-id', 'a', 'tree-root')),
- ])
- self.assertEqual('a', inv.id2path('a-id'))
- a_ie = inv['a-id']
- inv.apply_delta([("a", None, "a-id", None)])
+ def test_add(self):
+ inv = self.make_init_inventory()
+ inv = inv.create_by_apply_delta([
+ (None, "a", "a-id", self.make_file('a-id', 'a', 'tree-root')),
+ ], 'new-test-rev')
+ self.assertEqual('a', inv.id2path('a-id'))
+
+ def test_delete(self):
+ inv = self.make_init_inventory()
+ inv = inv.create_by_apply_delta([
+ (None, "a", "a-id", self.make_file('a-id', 'a', 'tree-root')),
+ ], 'new-rev-1')
+ self.assertEqual('a', inv.id2path('a-id'))
+ inv = inv.create_by_apply_delta([
+ ("a", None, "a-id", None),
+ ], 'new-rev-2')
self.assertRaises(errors.NoSuchId, inv.id2path, 'a-id')
- def test_apply_delta_rename(self):
- inv = self.make_inventory('tree-root')
- inv.apply_delta([
- (None, "a", "a-id", InventoryFile('a-id', 'a', 'tree-root')),
- ])
+ def test_rename(self):
+ inv = self.make_init_inventory()
+ inv = inv.create_by_apply_delta([
+ (None, "a", "a-id", self.make_file('a-id', 'a', 'tree-root')),
+ ], 'new-rev-1')
self.assertEqual('a', inv.id2path('a-id'))
a_ie = inv['a-id']
- b_ie = InventoryFile(a_ie.file_id, "b", a_ie.parent_id)
- inv.apply_delta([("a", "b", "a-id", b_ie)])
+ b_ie = self.make_file(a_ie.file_id, "b", a_ie.parent_id)
+ inv = inv.create_by_apply_delta([("a", "b", "a-id", b_ie)], 'new-rev-2')
self.assertEqual("b", inv.id2path('a-id'))
- def test_apply_delta_illegal(self):
+ def test_illegal(self):
# A file-id cannot appear in a delta more than once
- inv = self.make_inventory('tree-root')
- self.assertRaises(errors.InconsistentDelta, inv.apply_delta, [
- ("a", "a", "id-1", InventoryFile('id-1', 'a', 'tree-root')),
- ("a", "b", "id-1", InventoryFile('id-1', 'b', 'tree-root')),
- ])
+ inv = self.make_init_inventory()
+ self.assertRaises(errors.InconsistentDelta, inv.create_by_apply_delta, [
+ (None, "a", "id-1", self.make_file('id-1', 'a', 'tree-root')),
+ (None, "b", "id-1", self.make_file('id-1', 'b', 'tree-root')),
+ ], 'new-rev-1')
class TestInventoryReads(TestInventory):
def test_is_root(self):
"""Ensure our root-checking code is accurate."""
- inv = self.make_inventory('TREE_ROOT')
- self.assertTrue(inv.is_root('TREE_ROOT'))
+ inv = self.make_init_inventory()
+ self.assertTrue(inv.is_root('tree-root'))
self.assertFalse(inv.is_root('booga'))
- inv.root.file_id = 'booga'
+ ie = inv['tree-root'].copy()
+ ie.file_id = 'booga'
+ inv = inv.create_by_apply_delta([("", None, "tree-root", None),
+ (None, "", "booga", ie)], 'new-rev-2')
self.assertFalse(inv.is_root('TREE_ROOT'))
self.assertTrue(inv.is_root('booga'))
- # works properly even if no root is set
- inv.root = None
- self.assertFalse(inv.is_root('TREE_ROOT'))
- self.assertFalse(inv.is_root('booga'))
def test_ids(self):
"""Test detection of files within selected directories."""
- inv = self.make_inventory(ROOT_ID)
+ inv = inventory.Inventory('TREE_ROOT')
for args in [('src', 'directory', 'src-id'),
('doc', 'directory', 'doc-id'),
('src/hello.c', 'file'),
('src/bye.c', 'file', 'bye-id'),
('Makefile', 'file')]:
- inv.add_path(*args)
+ ie = inv.add_path(*args)
+ if args[1] == 'file':
+ ie.text_sha1 = osutils.sha_string('content\n')
+ ie.text_size = len('content\n')
+ inv = self.inv_to_test_inv(inv)
self.assertEqual(inv.path2id('src'), 'src-id')
self.assertEqual(inv.path2id('src/bye.c'), 'bye-id')
- self.assert_('src-id' in inv)
+ self.assertTrue('src-id' in inv)
def test_non_directory_children(self):
"""Test path2id when a parent directory has no children"""
- inv = self.make_inventory('tree_root')
- inv.add(InventoryFile('file-id','file',
- parent_id='tree_root'))
- inv.add(InventoryLink('link-id','link',
- parent_id='tree_root'))
+ inv = inventory.Inventory('tree-root')
+ inv.add(self.make_file('file-id','file', 'tree-root'))
+ inv.add(self.make_link('link-id','link', 'tree-root'))
self.assertIs(None, inv.path2id('file/subfile'))
self.assertIs(None, inv.path2id('link/subfile'))
def test_iter_entries(self):
- inv = self.make_inventory('tree-root')
- for args in [('src', 'directory', 'src-id'),
- ('doc', 'directory', 'doc-id'),
- ('src/hello.c', 'file', 'hello-id'),
- ('src/bye.c', 'file', 'bye-id'),
- ('src/sub', 'directory', 'sub-id'),
- ('src/sub/a', 'file', 'a-id'),
- ('Makefile', 'file', 'makefile-id')]:
- inv.add_path(*args)
+ inv = self.prepare_inv_with_nested_dirs()
# Test all entries
self.assertEqual([
@@ -230,6 +172,8 @@
('src/hello.c', 'hello-id'),
('src/sub', 'sub-id'),
('src/sub/a', 'a-id'),
+ ('src/zz.c', 'zzc-id'),
+ ('zz', 'zz-id'),
], [(path, ie.file_id) for path, ie in inv.iter_entries()])
# Test a subdirectory
@@ -238,6 +182,7 @@
('hello.c', 'hello-id'),
('sub', 'sub-id'),
('sub/a', 'a-id'),
+ ('zz.c', 'zzc-id'),
], [(path, ie.file_id) for path, ie in inv.iter_entries(
from_dir='src-id')])
@@ -247,6 +192,7 @@
('Makefile', 'makefile-id'),
('doc', 'doc-id'),
('src', 'src-id'),
+ ('zz', 'zz-id'),
], [(path, ie.file_id) for path, ie in inv.iter_entries(
recursive=False)])
@@ -255,24 +201,23 @@
('bye.c', 'bye-id'),
('hello.c', 'hello-id'),
('sub', 'sub-id'),
+ ('zz.c', 'zzc-id'),
], [(path, ie.file_id) for path, ie in inv.iter_entries(
from_dir='src-id', recursive=False)])
def test_iter_just_entries(self):
- inv = self.make_inventory('tree-root')
- for args in [('src', 'directory', 'src-id'),
- ('doc', 'directory', 'doc-id'),
- ('src/hello.c', 'file', 'hello-id'),
- ('src/bye.c', 'file', 'bye-id'),
- ('Makefile', 'file', 'makefile-id')]:
- inv.add_path(*args)
+ inv = self.prepare_inv_with_nested_dirs()
self.assertEqual([
+ 'a-id',
'bye-id',
'doc-id',
'hello-id',
'makefile-id',
'src-id',
+ 'sub-id',
'tree-root',
+ 'zz-id',
+ 'zzc-id',
], sorted([ie.file_id for ie in inv.iter_just_entries()]))
def test_iter_entries_by_dir(self):
@@ -387,3 +332,10 @@
('src/sub/a', 'a-id'),
('src/zz.c', 'zzc-id'),
], [(path, ie.file_id) for path, ie in new_inv.iter_entries()])
+
+ def test_inv_filter_entry_not_present(self):
+ inv = self.prepare_inv_with_nested_dirs()
+ new_inv = inv.filter(['not-present-id'])
+ self.assertEqual([
+ ('', 'tree-root'),
+ ], [(path, ie.file_id) for path, ie in new_inv.iter_entries()])
=== modified file 'bzrlib/tests/test_inv.py'
--- a/bzrlib/tests/test_inv.py 2009-09-09 01:28:34 +0000
+++ b/bzrlib/tests/test_inv.py 2009-09-24 19:26:45 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005, 2006, 2007 Canonical Ltd
+# Copyright (C) 2005, 2006, 2007, 2008, 2009 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
@@ -17,12 +17,14 @@
from bzrlib import (
chk_map,
+ groupcompress,
bzrdir,
errors,
inventory,
osutils,
repository,
revision,
+ tests,
)
from bzrlib.inventory import (CHKInventory, Inventory, ROOT_ID, InventoryFile,
InventoryDirectory, InventoryEntry, TreeReference)
@@ -257,6 +259,76 @@
return repo.get_inventory('result')
+class TestInventoryUpdates(TestCase):
+
+ def test_creation_from_root_id(self):
+ # iff a root id is passed to the constructor, a root directory is made
+ inv = inventory.Inventory(root_id='tree-root')
+ self.assertNotEqual(None, inv.root)
+ self.assertEqual('tree-root', inv.root.file_id)
+
+ def test_add_path_of_root(self):
+ # if no root id is given at creation time, there is no root directory
+ inv = inventory.Inventory(root_id=None)
+ self.assertIs(None, inv.root)
+ # add a root entry by adding its path
+ ie = inv.add_path("", "directory", "my-root")
+ ie.revision = 'test-rev'
+ self.assertEqual("my-root", ie.file_id)
+ self.assertIs(ie, inv.root)
+
+ def test_add_path(self):
+ inv = inventory.Inventory(root_id='tree_root')
+ ie = inv.add_path('hello', 'file', 'hello-id')
+ self.assertEqual('hello-id', ie.file_id)
+ self.assertEqual('file', ie.kind)
+
+ def test_copy(self):
+ """Make sure copy() works and creates a deep copy."""
+ inv = inventory.Inventory(root_id='some-tree-root')
+ ie = inv.add_path('hello', 'file', 'hello-id')
+ inv2 = inv.copy()
+ inv.root.file_id = 'some-new-root'
+ ie.name = 'file2'
+ self.assertEqual('some-tree-root', inv2.root.file_id)
+ self.assertEqual('hello', inv2['hello-id'].name)
+
+ def test_copy_empty(self):
+ """Make sure an empty inventory can be copied."""
+ inv = inventory.Inventory(root_id=None)
+ inv2 = inv.copy()
+ self.assertIs(None, inv2.root)
+
+ def test_copy_copies_root_revision(self):
+ """Make sure the revision of the root gets copied."""
+ inv = inventory.Inventory(root_id='someroot')
+ inv.root.revision = 'therev'
+ inv2 = inv.copy()
+ self.assertEquals('someroot', inv2.root.file_id)
+ self.assertEquals('therev', inv2.root.revision)
+
+ def test_create_tree_reference(self):
+ inv = inventory.Inventory('tree-root-123')
+ inv.add(TreeReference('nested-id', 'nested', parent_id='tree-root-123',
+ revision='rev', reference_revision='rev2'))
+
+ def test_error_encoding(self):
+ inv = inventory.Inventory('tree-root')
+ inv.add(InventoryFile('a-id', u'\u1234', 'tree-root'))
+ e = self.assertRaises(errors.InconsistentDelta, inv.add,
+ InventoryFile('b-id', u'\u1234', 'tree-root'))
+ self.assertContainsRe(str(e), r'\\u1234')
+
+ def test_add_recursive(self):
+ parent = InventoryDirectory('src-id', 'src', 'tree-root')
+ child = InventoryFile('hello-id', 'hello.c', 'src-id')
+ parent.children[child.file_id] = child
+ inv = inventory.Inventory('tree-root')
+ inv.add(parent)
+ self.assertEqual('src/hello.c', inv.id2path('hello-id'))
+
+
+
class TestDeltaApplication(TestCaseWithTransport):
def get_empty_inventory(self, reference_inv=None):
@@ -503,6 +575,22 @@
inv, delta)
+class TestInventory(TestCase):
+
+ def test_is_root(self):
+ """Ensure our root-checking code is accurate."""
+ inv = inventory.Inventory('TREE_ROOT')
+ self.assertTrue(inv.is_root('TREE_ROOT'))
+ self.assertFalse(inv.is_root('booga'))
+ inv.root.file_id = 'booga'
+ self.assertFalse(inv.is_root('TREE_ROOT'))
+ self.assertTrue(inv.is_root('booga'))
+ # works properly even if no root is set
+ inv.root = None
+ self.assertFalse(inv.is_root('TREE_ROOT'))
+ self.assertFalse(inv.is_root('booga'))
+
+
class TestInventoryEntry(TestCase):
def test_file_kind_character(self):
@@ -650,17 +738,12 @@
self.assertEqual(expected_change, change)
-class TestCHKInventory(TestCaseWithTransport):
+class TestCHKInventory(tests.TestCaseWithMemoryTransport):
def get_chk_bytes(self):
- # The easiest way to get a CHK store is a development6 repository and
- # then work with the chk_bytes attribute directly.
- repo = self.make_repository(".", format="development6-rich-root")
- repo.lock_write()
- self.addCleanup(repo.unlock)
- repo.start_write_group()
- self.addCleanup(repo.abort_write_group)
- return repo.chk_bytes
+ factory = groupcompress.make_pack_factory(True, True, 1)
+ trans = self.get_transport('')
+ return factory(trans)
def read_bytes(self, chk_bytes, key):
stream = chk_bytes.get_record_stream([key], 'unordered', True)
@@ -1131,3 +1214,135 @@
self.assertIsInstance(ie2.name, unicode)
self.assertEqual(('tree\xce\xa9name', 'tree-root-id', 'tree-rev-id'),
inv._bytes_to_utf8name_key(bytes))
+
+
+class TestCHKInventoryExpand(tests.TestCaseWithMemoryTransport):
+
+ def get_chk_bytes(self):
+ factory = groupcompress.make_pack_factory(True, True, 1)
+ trans = self.get_transport('')
+ return factory(trans)
+
+ def make_dir(self, inv, name, parent_id):
+ inv.add(inv.make_entry('directory', name, parent_id, name + '-id'))
+
+ def make_file(self, inv, name, parent_id, content='content\n'):
+ ie = inv.make_entry('file', name, parent_id, name + '-id')
+ ie.text_sha1 = osutils.sha_string(content)
+ ie.text_size = len(content)
+ inv.add(ie)
+
+ def make_simple_inventory(self):
+ inv = Inventory('TREE_ROOT')
+ inv.revision_id = "revid"
+ inv.root.revision = "rootrev"
+ # / TREE_ROOT
+ # dir1/ dir1-id
+ # sub-file1 sub-file1-id
+ # sub-file2 sub-file2-id
+ # sub-dir1/ sub-dir1-id
+ # subsub-file1 subsub-file1-id
+ # dir2/ dir2-id
+ # sub2-file1 sub2-file1-id
+ # top top-id
+ self.make_dir(inv, 'dir1', 'TREE_ROOT')
+ self.make_dir(inv, 'dir2', 'TREE_ROOT')
+ self.make_dir(inv, 'sub-dir1', 'dir1-id')
+ self.make_file(inv, 'top', 'TREE_ROOT')
+ self.make_file(inv, 'sub-file1', 'dir1-id')
+ self.make_file(inv, 'sub-file2', 'dir1-id')
+ self.make_file(inv, 'subsub-file1', 'sub-dir1-id')
+ self.make_file(inv, 'sub2-file1', 'dir2-id')
+ chk_bytes = self.get_chk_bytes()
+ # use a small maximum_size to force internal paging structures
+ chk_inv = CHKInventory.from_inventory(chk_bytes, inv,
+ maximum_size=100,
+ search_key_name='hash-255-way')
+ bytes = ''.join(chk_inv.to_lines())
+ return CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
+
+ def assert_Getitems(self, expected_fileids, inv, file_ids):
+ self.assertEqual(sorted(expected_fileids),
+ sorted([ie.file_id for ie in inv._getitems(file_ids)]))
+
+ def assertExpand(self, all_ids, inv, file_ids):
+ (val_all_ids,
+ val_children) = inv._expand_fileids_to_parents_and_children(file_ids)
+ self.assertEqual(set(all_ids), val_all_ids)
+ entries = inv._getitems(val_all_ids)
+ expected_children = {}
+ for entry in entries:
+ s = expected_children.setdefault(entry.parent_id, [])
+ s.append(entry.file_id)
+ val_children = dict((k, sorted(v)) for k, v
+ in val_children.iteritems())
+ expected_children = dict((k, sorted(v)) for k, v
+ in expected_children.iteritems())
+ self.assertEqual(expected_children, val_children)
+
+ def test_make_simple_inventory(self):
+ inv = self.make_simple_inventory()
+ layout = []
+ for path, entry in inv.iter_entries_by_dir():
+ layout.append((path, entry.file_id))
+ self.assertEqual([
+ ('', 'TREE_ROOT'),
+ ('dir1', 'dir1-id'),
+ ('dir2', 'dir2-id'),
+ ('top', 'top-id'),
+ ('dir1/sub-dir1', 'sub-dir1-id'),
+ ('dir1/sub-file1', 'sub-file1-id'),
+ ('dir1/sub-file2', 'sub-file2-id'),
+ ('dir1/sub-dir1/subsub-file1', 'subsub-file1-id'),
+ ('dir2/sub2-file1', 'sub2-file1-id'),
+ ], layout)
+
+ def test__getitems(self):
+ inv = self.make_simple_inventory()
+ # Reading from disk
+ self.assert_Getitems(['dir1-id'], inv, ['dir1-id'])
+ self.assertTrue('dir1-id' in inv._fileid_to_entry_cache)
+ self.assertFalse('sub-file2-id' in inv._fileid_to_entry_cache)
+ # From cache
+ self.assert_Getitems(['dir1-id'], inv, ['dir1-id'])
+ # Mixed
+ self.assert_Getitems(['dir1-id', 'sub-file2-id'], inv,
+ ['dir1-id', 'sub-file2-id'])
+ self.assertTrue('dir1-id' in inv._fileid_to_entry_cache)
+ self.assertTrue('sub-file2-id' in inv._fileid_to_entry_cache)
+
+ def test_single_file(self):
+ inv = self.make_simple_inventory()
+ self.assertExpand(['TREE_ROOT', 'top-id'], inv, ['top-id'])
+
+ def test_get_all_parents(self):
+ inv = self.make_simple_inventory()
+ self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
+ 'subsub-file1-id',
+ ], inv, ['subsub-file1-id'])
+
+ def test_get_children(self):
+ inv = self.make_simple_inventory()
+ self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
+ 'sub-file1-id', 'sub-file2-id', 'subsub-file1-id',
+ ], inv, ['dir1-id'])
+
+ def test_from_root(self):
+ inv = self.make_simple_inventory()
+ self.assertExpand(['TREE_ROOT', 'dir1-id', 'dir2-id', 'sub-dir1-id',
+ 'sub-file1-id', 'sub-file2-id', 'sub2-file1-id',
+ 'subsub-file1-id', 'top-id'], inv, ['TREE_ROOT'])
+
+ def test_top_level_file(self):
+ inv = self.make_simple_inventory()
+ self.assertExpand(['TREE_ROOT', 'top-id'], inv, ['top-id'])
+
+ def test_subsub_file(self):
+ inv = self.make_simple_inventory()
+ self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
+ 'subsub-file1-id'], inv, ['subsub-file1-id'])
+
+ def test_sub_and_root(self):
+ inv = self.make_simple_inventory()
+ self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id', 'top-id',
+ 'subsub-file1-id'], inv, ['top-id', 'subsub-file1-id'])
More information about the bazaar-commits
mailing list