Rev 3173: JournalEntry -> inventory conversion. in http://people.ubuntu.com/~robertc/baz2.0/inventory.journalled

Robert Collins robertc at robertcollins.net
Fri Jan 4 02:10:07 GMT 2008


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

------------------------------------------------------------
revno: 3173
revision-id:robertc at robertcollins.net-20080104021002-71l0ihc8z2qx4eb1
parent: robertc at robertcollins.net-20080104000221-evx725bk1h5q7502
committer: Robert Collins <robertc at robertcollins.net>
branch nick: inventory.journalled
timestamp: Fri 2008-01-04 13:10:02 +1100
message:
  JournalEntry -> inventory conversion.
modified:
  bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
  bzrlib/journalled_inventory.py journalled_inventory-20080103020931-0ht5n40kwc0p7fy1-1
  bzrlib/tests/test_journalled_inv.py test_journalled_inv.-20080103012121-ny2w9slze5jgty8i-1
  doc/developers/inventory.txt   inventory.txt-20080103013957-opkrhxy6lmywmx4i-1
=== modified file 'bzrlib/inventory.py'
--- a/bzrlib/inventory.py	2007-12-18 18:25:12 +0000
+++ b/bzrlib/inventory.py	2008-01-04 02:10:02 +0000
@@ -1417,6 +1417,25 @@
     return factory(file_id, name, parent_id)
 
 
+def make_inv_delta(old, new):
+    """Make an inventory delta from two inventories."""
+    old_ids = set(old._byid.iterkeys())
+    new_ids = set(new._byid.iterkeys())
+    adds = new_ids - old_ids
+    deletes = old_ids - new_ids
+    common = old_ids.intersection(new_ids)
+    delta = []
+    for file_id in deletes:
+        delta.append((old.id2path(file_id), None, file_id, None))
+    for file_id in adds:
+        delta.append((None, new.id2path(file_id), file_id, new[file_id]))
+    for file_id in common:
+        if old[file_id] != new[file_id]:
+            delta.append((old.id2path(file_id), new.id2path(file_id),
+                file_id, new[file_id]))
+    return delta
+
+
 def ensure_normalized_name(name):
     """Normalize name.
 

=== modified file 'bzrlib/journalled_inventory.py'
--- a/bzrlib/journalled_inventory.py	2008-01-04 00:01:31 +0000
+++ b/bzrlib/journalled_inventory.py	2008-01-04 02:10:02 +0000
@@ -26,7 +26,10 @@
 __all__ = ['EntryAccess', 'InventoryJournal']
 
 from bzrlib import errors
+from bzrlib.osutils import basename
+from bzrlib import inventory
 from bzrlib.revision import NULL_REVISION
+from bzrlib.tsort import topo_sort
 
 
 def _directory_content(entry):
@@ -56,7 +59,7 @@
     target = entry.symlink_target
     if target is None:
         raise errors.BzrError('Missing target for %s' % entry.file_id)
-    return "link\x00%s\x00" % target
+    return "link\x00%s\x00" % target.encode('utf8')
 
 
 def _reference_content(entry):
@@ -70,6 +73,42 @@
     return "tree\x00%s\x00" % tree_revision
 
 
+def _dir_to_entry(content, name, parent_id, file_id, last_modified,
+    _type=inventory.InventoryDirectory):
+    """Convert a dir content record to an InventoryDirectory."""
+    result = _type(file_id, name, parent_id)
+    result.revision = last_modified
+    return result
+
+
+def _file_to_entry(content, name, parent_id, file_id, last_modified,
+    _type=inventory.InventoryFile):
+    """Convert a dir content record to an InventoryFile."""
+    result = _type(file_id, name, parent_id)
+    result.revision = last_modified
+    result.text_size = int(content[1])
+    result.text_sha1 = content[2]
+    return result
+
+
+def _link_to_entry(content, name, parent_id, file_id, last_modified,
+    _type=inventory.InventoryLink):
+    """Convert a link content record to an InventoryLink."""
+    result = _type(file_id, name, parent_id)
+    result.revision = last_modified
+    result.symlink_target = content[1].decode('utf8')
+    return result
+
+
+def _tree_to_entry(content, name, parent_id, file_id, last_modified,
+    _type=inventory.TreeReference):
+    """Convert a tree content record to a TreeReference."""
+    result = _type(file_id, name, parent_id)
+    result.revision = last_modified
+    result.reference_revision = content[1]
+    return result
+
+
 class _JournalEntry(object):
     """An individual entry in a journalled inventory."""
 
@@ -110,6 +149,61 @@
                 self.by_id[line[0]] = line[1]
         self.parent_revision = parent_entry.parent_revision
 
+    def to_inventory(self):
+        """Convert this JournalEntry to an inventory object.
+
+        :raises BzrError: If the parent is not NULL_REVISION then not enough
+            information will be present.
+        :return: An Inventory object.
+        """
+        if self.parent_revision != NULL_REVISION:
+            raise errors.BzrError("Journal not completely replayed.")
+        # build a topo order on parent ids.
+        parent_graph = [(None, [])]
+        for utf8_path, file_id, parent_id, last_modified, content in \
+            self.by_id.itervalues():
+            if content[0] == 'tree' and not self.tree_references:
+                raise errors.BzrError("tree reference (id %s) present in "
+                    "non-tree-reference supporting journal." % file_id)
+            if utf8_path == 'None':
+                # deleted id, nothing to see here.
+                continue
+            if utf8_path == '/' and not self.versioned_root:
+                # This is a double check as its done during parsing, but it
+                # seems worthwhile.
+                if file_id != 'TREE_ROOT':
+                    raise errors.BzrError(
+                        'file_id %s is not TREE_ROOT for /' % file_id)
+                if last_modified is not None:
+                    raise errors.BzrError(
+                        'Version present for / in %s' % file_id)
+                last_modified = None
+            else:
+                if last_modified[-1] == ':':
+                    raise errors.BzrError(
+                        'special revision id in journal (id %s)' % file_id)
+            parent_graph.append((file_id, [parent_id]))
+        order = topo_sort(parent_graph)
+        if order[0] != None:
+            raise errors.BzrError(
+                'inconsistent file id parent links (%r)' % order[0])
+        result = inventory.Inventory(None)
+        entry_factory = {
+            'dir': _dir_to_entry,
+            'file': _file_to_entry,
+            'link': _link_to_entry,
+            'tree': _tree_to_entry,
+        }
+        for file_id in order[1:]:
+            utf8_path, _1, parent_id, last_modified, content = \
+                self.by_id[file_id]
+            kind = content[0]
+            path = utf8_path[1:].decode('utf8')
+            name = basename(path)
+            result.add(entry_factory[content[0]](
+                    content, name, parent_id, file_id, last_modified))
+        return result
+
 
 class EntryAccess(object):
     """Provide access to named bytesequences of the journal entries."""
@@ -152,6 +246,9 @@
         to_line = self._delta_item_to_line
         for delta_item in delta_to_new:
             lines.append(to_line(delta_item))
+            if lines[-1].__class__ != str:
+                raise errors.BzrError(
+                    'to_line generated non-str output %r' % lines[-1])
         lines.sort()
         lines[0] = "format: %s\n" % InventoryJournal.FORMAT_1
         lines[1] = "parent: %s\n" % old_inventory_name
@@ -166,7 +263,7 @@
             newpath_utf8 = 'None'
             parent_id = ''
             last_modified = NULL_REVISION
-            content = 'deleted'
+            content = 'deleted\x00\x00'
         else:
             # TODO: Test real-world utf8 cache hit rate. It may be a win.
             newpath_utf8 = '/' + newpath.encode('utf8')
@@ -212,12 +309,11 @@
             parent_id = parent_id or None
             by_id[file_id] = (newpath_utf8, file_id, parent_id,
                 last_modified, tuple(content.split('\x00')))
-            if newpath_utf8 == '/':
-                if self._versioned_root and last_modified == 'null:':
-                    raise errors.BzrError('unversioned root found: %r' % line)
-                elif not self._versioned_root and (last_modified != 'null:' or 
-                    file_id != 'TREE_ROOT'):
+            if newpath_utf8 == '/' and not self._versioned_root and (
+                last_modified != 'null:' or file_id != 'TREE_ROOT'):
                     raise errors.BzrError("Versioned root found: %r" % line)
+            elif last_modified[-1] == ':':
+                    raise errors.BzrError('special revisionid found: %r' % line)
             if not self._tree_references and content.startswith('tree\x00'):
                 raise errors.BzrError("Tree reference found: %r" % line)
         if len(by_id) + 3 != len(lines):

=== modified file 'bzrlib/tests/test_journalled_inv.py'
--- a/bzrlib/tests/test_journalled_inv.py	2008-01-04 00:01:31 +0000
+++ b/bzrlib/tests/test_journalled_inv.py	2008-01-04 02:10:02 +0000
@@ -39,7 +39,7 @@
 root_only_lines = """format: bzr journalled inventory v1 (bzr 1.1)
 parent: null:
 version: entry-version
-/\x00an-id\x00\x00a at e\xe5ample.com--2004\x00dir\x00\x00
+/\x00an-id\x00\x00a at e\xc3\xa5ample.com--2004\x00dir\x00\x00
 """
 
 root_change_lines = """format: bzr journalled inventory v1 (bzr 1.1)
@@ -57,7 +57,7 @@
 reference_lines = """format: bzr journalled inventory v1 (bzr 1.1)
 parent: null:
 version: entry-version
-/\x00TREE_ROOT\x00\x00a at e\xe5ample.com--2004\x00dir\x00\x00
+/\x00TREE_ROOT\x00\x00a at e\xc3\xa5ample.com--2004\x00dir\x00\x00
 /foo\x00id\x00TREE_ROOT\x00changed\x00tree\x00subtree-version\x00
 """
 
@@ -71,28 +71,10 @@
 class TestSerializer(TestCase):
     """Test journalled inventory serialisation."""
 
-    def make_inv_delta(self, old, new):
-        """Make an inventory delta from two inventories."""
-        old_ids = set(old._byid.iterkeys())
-        new_ids = set(new._byid.iterkeys())
-        adds = new_ids - old_ids
-        deletes = old_ids - new_ids
-        common = old_ids.intersection(new_ids)
-        delta = []
-        for file_id in deletes:
-            delta.append((old.id2path(file_id), None, file_id, None))
-        for file_id in adds:
-            delta.append((None, new.id2path(file_id), file_id, new[file_id]))
-        for file_id in common:
-            if old[file_id] != new[file_id]:
-                delta.append((old.id2path(file_id), new.id2path(file_id),
-                    file_id, new[file_id]))
-        return delta
-
     def test_empty_delta_to_lines(self):
         old_inv = Inventory(None)
         new_inv = Inventory(None)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=True,
             tree_references=True)
         self.assertEqual(StringIO(empty_lines).readlines(),
@@ -102,9 +84,9 @@
         old_inv = Inventory(None)
         new_inv = Inventory(None)
         root = new_inv.make_entry('directory', '', None, 'an-id')
-        root.revision = 'a at e\xe5ample.com--2004'
+        root.revision = 'a at e\xc3\xa5ample.com--2004'
         new_inv.add(root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=True,
             tree_references=True)
         self.assertEqual(StringIO(root_only_lines).readlines(),
@@ -115,7 +97,7 @@
         new_inv = Inventory(None)
         root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
         new_inv.add(root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=False,
             tree_references=False)
         self.assertEqual(StringIO(root_only_unversioned).readlines(),
@@ -125,11 +107,11 @@
         old_inv = Inventory(None)
         new_inv = Inventory(None)
         root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
-        root.revision = 'a at e\xe5ample.com--2004'
+        root.revision = 'a at e\xc3\xa5ample.com--2004'
         new_inv.add(root)
         non_root = new_inv.make_entry('directory', 'foo', root.file_id, 'id')
         new_inv.add(non_root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=True,
             tree_references=True)
         self.assertRaises(errors.BzrError,
@@ -140,7 +122,7 @@
         new_inv = Inventory(None)
         root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
         new_inv.add(root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=True,
             tree_references=True)
         self.assertRaises(errors.BzrError,
@@ -150,9 +132,9 @@
         old_inv = Inventory(None)
         new_inv = Inventory(None)
         root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
-        root.revision = 'a at e\xe5ample.com--2004'
+        root.revision = 'a at e\xc3\xa5ample.com--2004'
         new_inv.add(root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=False,
             tree_references=True)
         self.assertRaises(errors.BzrError,
@@ -163,7 +145,7 @@
         new_inv = Inventory(None)
         root = new_inv.make_entry('directory', '', None, 'my-rich-root-id')
         new_inv.add(root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=False,
             tree_references=True)
         self.assertRaises(errors.BzrError,
@@ -179,7 +161,7 @@
         non_root.revision = 'changed'
         non_root.kind = 'strangelove'
         new_inv.add(non_root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=True,
             tree_references=True)
         # we expect keyerror because there is little value wrapping this.
@@ -191,14 +173,14 @@
         old_inv = Inventory(None)
         new_inv = Inventory(None)
         root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
-        root.revision = 'a at e\xe5ample.com--2004'
+        root.revision = 'a at e\xc3\xa5ample.com--2004'
         new_inv.add(root)
         non_root = new_inv.make_entry(
             'tree-reference', 'foo', root.file_id, 'id')
         non_root.revision = 'changed'
         non_root.reference_revision = 'subtree-version'
         new_inv.add(non_root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=True,
             tree_references=False)
         # we expect keyerror because there is little value wrapping this.
@@ -210,14 +192,14 @@
         old_inv = Inventory(None)
         new_inv = Inventory(None)
         root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
-        root.revision = 'a at e\xe5ample.com--2004'
+        root.revision = 'a at e\xc3\xa5ample.com--2004'
         new_inv.add(root)
         non_root = new_inv.make_entry(
             'tree-reference', 'foo', root.file_id, 'id')
         non_root.revision = 'changed'
         non_root.reference_revision = 'subtree-version'
         new_inv.add(non_root)
-        delta = self.make_inv_delta(old_inv, new_inv)
+        delta = inventory.make_inv_delta(old_inv, new_inv)
         journal = journalled_inventory.InventoryJournal(versioned_root=True,
             tree_references=True)
         self.assertEqual(StringIO(reference_lines).readlines(),
@@ -271,8 +253,8 @@
 """format: bzr journalled inventory v1 (bzr 1.1)
 parent: null:
 version: null:
-/\x00an-id\x00\x00a at e\xe5ample.com--2004\x00dir\x00\x00
-/\x00an-id\x00\x00a at e\xe5ample.com--2004\x00dir\x00\x00
+/\x00an-id\x00\x00a at e\xc3\xa5ample.com--2004\x00dir\x00\x00
+/\x00an-id\x00\x00a at e\xc3\xa5ample.com--2004\x00dir\x00\x00
 """
         self.assertRaises(errors.BzrError,
             journal.parse_text_bytes, double_root_lines)
@@ -282,20 +264,31 @@
             tree_references=True)
         journal_entry = journal.parse_text_bytes(root_only_lines)
         self.assertEqual({
-            'an-id':('/', 'an-id', None, 'a at e\xe5ample.com--2004',
+            'an-id':('/', 'an-id', None, 'a at e\xc3\xa5ample.com--2004',
                      ('dir', '', '')),
             },
             journal_entry.by_id)
         self.assertEqual(NULL_REVISION, journal_entry.parent_revision)
         self.assertEqual('entry-version', journal_entry.version)
 
+    def test_parse_special_revid_not_valid_last_mod(self):
+        journal = journalled_inventory.InventoryJournal(versioned_root=False,
+            tree_references=True)
+        root_only_lines = """format: bzr journalled inventory v1 (bzr 1.1)
+parent: null:
+version: null:
+/\x00TREE_ROOT\x00\x00null:\x00dir\x00\x00
+"""
+        self.assertRaises(errors.BzrError,
+            journal.parse_text_bytes, root_only_lines)
+
     def test_parse_versioned_root_versioned_disabled(self):
         journal = journalled_inventory.InventoryJournal(versioned_root=False,
             tree_references=True)
         root_only_lines = """format: bzr journalled inventory v1 (bzr 1.1)
 parent: null:
 version: null:
-/\x00TREE_ROOT\x00\x00a at e\xe5ample.com--2004\x00dir\x00\x00
+/\x00TREE_ROOT\x00\x00a at e\xc3\xa5ample.com--2004\x00dir\x00\x00
 """
         self.assertRaises(errors.BzrError,
             journal.parse_text_bytes, root_only_lines)
@@ -335,7 +328,6 @@
         a_root = journal.parse_text_bytes(root_only_lines)
         null = journal.parse_text_bytes(empty_lines)
         root = journal.parse_text_bytes(root_only_lines)
-        print root.parent_revision
         root.combine_with(null)
         self.assertJournalEntriesEqual(a_root, root)
 
@@ -364,12 +356,109 @@
         change_tree = journal.parse_text_bytes(change_tree_lines)
         change_tree.combine_with(root)
         self.assertEqual({
-            'TREE_ROOT': ('/', 'TREE_ROOT', None, 'a at e\xe5ample.com--2004',
+            'TREE_ROOT': ('/', 'TREE_ROOT', None, 'a at e\xc3\xa5ample.com--2004',
                       ('dir', '', '')),
             'id': ('/foo', 'id', 'TREE_ROOT', 'changed-twice',
                    ('tree', 'subtree-version2', '')),
             }, change_tree.by_id)
 
+    def test_to_inventory_non_null_parent(self):
+        journal_entry = journalled_inventory._JournalEntry(
+            'something', 'a-change', {}, True, True)
+        self.assertRaises(errors.BzrError, journal_entry.to_inventory)
+
+    def test_to_inventory_root_id_versioned_not_permitted(self):
+        entries = {
+            'TREE_ROOT': ('/', 'TREE_ROOT', None, 'a-version-id',
+                ('dir', '', '')),
+        }
+        journal_entry = journalled_inventory._JournalEntry(
+            'something', NULL_REVISION, entries, False, True)
+        self.assertRaises(errors.BzrError, journal_entry.to_inventory)
+
+    def test_to_inventory_root_id_unique_not_permitted(self):
+        entries = {
+            'TREE_ROOT': ('/', 'TREE_ROOT', None, 'a-version-id',
+                ('dir', '', '')),
+        }
+        journal_entry = journalled_inventory._JournalEntry(
+            'something', NULL_REVISION, entries, False, True)
+        self.assertRaises(errors.BzrError, journal_entry.to_inventory)
+
+    def test_to_inventory_root_id_not_versioned(self):
+        entries = {
+            'an-id': ('/', 'an-id', None, 'null:',
+                ('dir', '', '')),
+        }
+        journal_entry = journalled_inventory._JournalEntry(
+            'something', NULL_REVISION, entries, True, True)
+        self.assertRaises(errors.BzrError, journal_entry.to_inventory)
+
+    def test_to_inventory_has_tree_not_meant_to(self):
+        entries = {
+            'an-id': ('/', 'an-id', None, 'changed-in',
+                ('dir', '', '')),
+            'a-ref': ('/foo', 'ref-id', 'an-id', 'changed-in',
+                ('tree', 'ref-revision', '')),
+            # a file that followed the root move
+        }
+        journal_entry = journalled_inventory._JournalEntry(
+            'something', NULL_REVISION, entries, True, False)
+        self.assertRaises(errors.BzrError, journal_entry.to_inventory)
+
+    def test_to_inventory_torture(self):
+        # this journal is crafted to have all the following:
+        # - deletes
+        # - renamed roots
+        # - deep dirs
+        # - files moved after parent dir was renamed
+        entries = {
+            # current root:
+            'an-id': ('/', 'an-id', None, 'changed-in',
+                ('dir', '', '')),
+            # an old root:
+            'TREE_ROOT': ('/subdir-now', 'TREE_ROOT', 'an-id', 'moved-root',
+                ('dir', '', '')),
+            # a file that followed the root move
+            'moved-id': ('/underoldroot', 'moved-id', 'TREE_ROOT', 'old-rev',
+                ('file', '30', 'some-sha')),
+            # a deleted path 
+            'deleted-id': ('None', 'deleted-id', None, NULL_REVISION,
+                ('deleted', '', '')),
+            # a tree reference moved to the new root
+            'ref-id': ('/ref', 'ref-id', 'an-id', 'new-rev',
+                ('tree', 'tree-reference-id', '')),
+            # a symlink now in a deep dir
+            'link-id': ('/link', 'link-id', 'deep-id', 'new-rev',
+                ('link', 'target', '')),
+            # a deep dir
+            'deep-id': ('/dir', 'deep-id', 'TREE_ROOT', 'new-rev',
+                ('dir', '', '')),
+        }
+        journal_entry = journalled_inventory._JournalEntry(
+            'something', NULL_REVISION, entries, True, True)
+        inv = journal_entry.to_inventory()
+        # easiest way to check we got the right inventory is to serialise it
+        # and compare the serialised forms.
+        expected = """format: bzr journalled inventory v1 (bzr 1.1)
+parent: null:
+version: something
+/\x00an-id\x00\x00changed-in\x00dir\x00\x00
+/ref\x00ref-id\x00an-id\x00new-rev\x00tree\x00tree-reference-id\x00
+/subdir-now\x00TREE_ROOT\x00an-id\x00moved-root\x00dir\x00\x00
+/subdir-now/dir\x00deep-id\x00TREE_ROOT\x00new-rev\x00dir\x00\x00
+/subdir-now/dir/link\x00link-id\x00deep-id\x00new-rev\x00link\x00target\x00
+/subdir-now/underoldroot\x00moved-id\x00TREE_ROOT\x00old-rev\x00file\x0030\x00some-sha
+"""
+        old_inv = Inventory(None)
+        delta = inventory.make_inv_delta(old_inv, inv)
+        journal = journalled_inventory.InventoryJournal(versioned_root=True,
+            tree_references=True)
+        lines = journal.delta_to_lines(NULL_REVISION, 'something', delta)
+        serialised = ''.join(lines)
+        self.assertIsInstance(serialised, str)
+        self.assertEqual(expected, serialised)
+
 
 class TestContent(TestCase):
 
@@ -409,6 +498,12 @@
         self.assertEqual('link\x00\x00',
             journalled_inventory._link_content(entry))
 
+    def test_link_unicode_target(self):
+        entry = inventory.make_entry('symlink', 'a link', None)
+        entry.symlink_target = ' \xc3\xa5'.decode('utf8')
+        self.assertEqual('link\x00 \xc3\xa5\x00',
+            journalled_inventory._link_content(entry))
+
     def test_link_space_target(self):
         entry = inventory.make_entry('symlink', 'a link', None)
         entry.symlink_target = ' '
@@ -428,8 +523,8 @@
 
     def test_reference_revision(self):
         entry = inventory.make_entry('tree-reference', 'a tree', None)
-        entry.reference_revision = 'foo@\xe5b-lah'
-        self.assertEqual('tree\x00foo@\xe5b-lah\x00',
+        entry.reference_revision = 'foo@\xc3\xa5b-lah'
+        self.assertEqual('tree\x00foo@\xc3\xa5b-lah\x00',
             journalled_inventory._reference_content(entry))
 
     def test_reference_no_reference(self):

=== modified file 'doc/developers/inventory.txt'
--- a/doc/developers/inventory.txt	2008-01-04 00:02:21 +0000
+++ b/doc/developers/inventory.txt	2008-01-04 02:10:02 +0000
@@ -121,7 +121,7 @@
 
 Some explanation is in order. When NEWPATH is 'None' a delete has been
 recorded, and because this journalled inventory is not attempting to be a
-reversible journal, the only other valid fields is 'file-id'. PARENT_ID is ''
+reversible journal, the only other valid field is 'file-id'. PARENT_ID is ''
 when a delete has been recorded or when recording a new root entry. Content
 always has 2 NULL delimiters in it to allow easy parsing.
 



More information about the bazaar-commits mailing list