28
28
# This should really be an id randomly assigned when the tree is
29
29
# created, but it's not for now.
30
ROOT_ID = b"TREE_ROOT"
32
from ..lazy_import import lazy_import
32
from bzrlib.lazy_import import lazy_import
33
33
lazy_import(globals(), """
44
from breezy.bzr import (
53
from ..sixish import (
52
from bzrlib.static_tuple import StaticTuple
53
from bzrlib.symbol_versioning import (
60
from ..static_tuple import StaticTuple
63
59
class InventoryEntry(object):
113
109
>>> i.add(InventoryFile('2326', 'wibble.c', '2325'))
114
110
InventoryFile('2326', 'wibble.c', parent_id='2325', sha1=None, len=None, revision=None)
115
>>> i.get_entry('2326')
116
112
InventoryFile('2326', 'wibble.c', parent_id='2325', sha1=None, len=None, revision=None)
117
113
>>> for path, entry in i.iter_entries():
396
392
# to provide a per-fileid log. The hash of every directory content is
397
393
# "da..." below (the sha1sum of '').
398
394
checker.add_pending_item(rev_id,
399
(b'texts', self.file_id, self.revision), b'text',
400
b'da39a3ee5e6b4b0d3255bfef95601890afd80709')
395
('texts', self.file_id, self.revision), 'text',
396
'da39a3ee5e6b4b0d3255bfef95601890afd80709')
403
399
other = InventoryDirectory(self.file_id, self.name, self.parent_id)
436
429
"""See InventoryEntry._check"""
437
430
# TODO: check size too.
438
431
checker.add_pending_item(tree_revision_id,
439
(b'texts', self.file_id, self.revision), b'text',
432
('texts', self.file_id, self.revision), 'text',
441
434
if self.text_size is None:
442
435
checker._report_items.append(
461
454
def _diff(self, text_diff, from_label, tree, to_label, to_entry, to_tree,
462
455
output_to, reverse=False):
463
456
"""See InventoryEntry._diff."""
464
from breezy.diff import DiffText
457
from bzrlib.diff import DiffText
465
458
from_file_id = self.file_id
467
460
to_file_id = to_entry.file_id
468
to_path = to_tree.id2path(to_file_id)
470
462
to_file_id = None
472
if from_file_id is not None:
473
from_path = tree.id2path(from_file_id)
477
464
to_file_id, from_file_id = from_file_id, to_file_id
478
465
tree, to_tree = to_tree, tree
479
466
from_label, to_label = to_label, from_label
480
467
differ = DiffText(tree, to_tree, output_to, 'utf-8', '', '',
482
return differ.diff_text(from_path, to_path, from_label, to_label,
483
from_file_id, to_file_id)
469
return differ.diff_text(from_file_id, to_file_id, from_label, to_label)
485
471
def has_text(self):
486
472
"""See InventoryEntry.has_text."""
493
479
def _read_tree_state(self, path, work_tree):
494
480
"""See InventoryEntry._read_tree_state."""
495
self.text_sha1 = work_tree.get_file_sha1(path, self.file_id)
481
self.text_sha1 = work_tree.get_file_sha1(self.file_id, path=path)
496
482
# FIXME: 20050930 probe for the text size when getting sha1
497
483
# in _read_tree_state
498
self.executable = work_tree.is_executable(path, self.file_id)
484
self.executable = work_tree.is_executable(self.file_id, path=path)
500
486
def __repr__(self):
501
487
return ("%s(%r, %r, parent_id=%r, sha1=%r, len=%s, revision=%s)"
543
529
% (self.file_id, tree_revision_id))
544
530
# Symlinks are stored as ''
545
531
checker.add_pending_item(tree_revision_id,
546
(b'texts', self.file_id, self.revision), b'text',
547
b'da39a3ee5e6b4b0d3255bfef95601890afd80709')
532
('texts', self.file_id, self.revision), 'text',
533
'da39a3ee5e6b4b0d3255bfef95601890afd80709')
550
536
other = InventoryLink(self.file_id, self.name, self.parent_id)
564
550
def _diff(self, text_diff, from_label, tree, to_label, to_entry, to_tree,
565
551
output_to, reverse=False):
566
552
"""See InventoryEntry._diff."""
567
from breezy.diff import DiffSymlink
553
from bzrlib.diff import DiffSymlink
568
554
old_target = self.symlink_target
569
555
if to_entry is not None:
570
556
new_target = to_entry.symlink_target
587
573
def _read_tree_state(self, path, work_tree):
588
574
"""See InventoryEntry._read_tree_state."""
589
self.symlink_target = work_tree.get_symlink_target(
590
work_tree.id2path(self.file_id), self.file_id)
575
self.symlink_target = work_tree.get_symlink_target(self.file_id)
592
577
def _forget_tree_state(self):
593
578
self.symlink_target = None
655
640
"""Return as a string the path to file_id.
657
642
>>> i = Inventory()
658
>>> e = i.add(InventoryDirectory(b'src-id', 'src', ROOT_ID))
659
>>> e = i.add(InventoryFile(b'foo-id', 'foo.c', parent_id='src-id'))
660
>>> print i.id2path(b'foo-id')
643
>>> e = i.add(InventoryDirectory('src-id', 'src', ROOT_ID))
644
>>> e = i.add(InventoryFile('foo-id', 'foo.c', parent_id='src-id'))
645
>>> print i.id2path('foo-id')
663
648
:raises NoSuchId: If file_id is not present in the inventory.
680
665
from_dir = self.root
681
666
yield '', self.root
682
elif isinstance(from_dir, bytes):
683
from_dir = self.get_entry(from_dir)
667
elif isinstance(from_dir, basestring):
668
from_dir = self[from_dir]
685
670
# unrolling the recursive called changed the time from
686
671
# 440ms/663ms (inline/total) to 116ms/116ms
687
children = sorted(viewitems(from_dir.children))
672
children = from_dir.children.items()
688
674
if not recursive:
689
675
for name, ie in children:
721
708
def _preload_cache(self):
722
709
"""Populate any caches, we are about to access all items.
724
711
The default implementation does nothing, because CommonInventory doesn't
729
def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None):
716
def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None,
717
yield_parents=False):
730
718
"""Iterate over the entries in a directory first order.
732
720
This returns all entries for a directory before returning
734
722
lexicographically sorted order, and is a hybrid between
735
723
depth-first and breadth-first.
725
:param yield_parents: If True, yield the parents from the root leading
726
down to specific_file_ids that have been requested. This has no
727
impact if specific_file_ids is None.
737
728
:return: This yields (path, entry) pairs
739
730
if specific_file_ids and not isinstance(specific_file_ids, set):
749
740
if self.root is None:
751
742
# Optimize a common case
752
if (specific_file_ids is not None and
743
if (not yield_parents and specific_file_ids is not None and
753
744
len(specific_file_ids) == 1):
754
745
file_id = list(specific_file_ids)[0]
755
if file_id is not None:
757
path = self.id2path(file_id)
758
except errors.NoSuchId:
761
yield path, self.get_entry(file_id)
746
if self.has_id(file_id):
747
yield self.id2path(file_id), self[file_id]
763
749
from_dir = self.root
764
if (specific_file_ids is None or
750
if (specific_file_ids is None or yield_parents or
765
751
self.root.file_id in specific_file_ids):
766
752
yield u'', self.root
767
elif isinstance(from_dir, (str, text_type)):
768
from_dir = self.get_entry(from_dir)
753
elif isinstance(from_dir, basestring):
754
from_dir = self[from_dir]
770
756
if specific_file_ids is not None:
771
757
# TODO: jam 20070302 This could really be done as a loop rather
791
777
cur_relpath, cur_dir = stack.pop()
794
for child_name, child_ie in sorted(viewitems(cur_dir.children)):
780
for child_name, child_ie in sorted(cur_dir.children.iteritems()):
796
782
child_relpath = cur_relpath + child_name
798
784
if (specific_file_ids is None or
799
child_ie.file_id in specific_file_ids):
785
child_ie.file_id in specific_file_ids or
786
(yield_parents and child_ie.file_id in parents)):
800
787
yield child_relpath, child_ie
802
789
if child_ie.kind == 'directory':
815
802
for file_id in deletes:
816
803
delta.append((old.id2path(file_id), None, file_id, None))
817
804
for file_id in adds:
818
delta.append((None, self.id2path(file_id), file_id, self.get_entry(file_id)))
805
delta.append((None, self.id2path(file_id), file_id, self[file_id]))
819
806
for file_id in common:
820
if old.get_entry(file_id) != self.get_entry(file_id):
807
if old[file_id] != self[file_id]:
821
808
delta.append((old.id2path(file_id), self.id2path(file_id),
822
file_id, self.get_entry(file_id)))
809
file_id, self[file_id]))
825
812
def make_entry(self, kind, name, parent_id, file_id=None):
826
"""Simple thunk to breezy.bzr.inventory.make_entry."""
813
"""Simple thunk to bzrlib.inventory.make_entry."""
827
814
return make_entry(kind, name, parent_id, file_id)
829
816
def entries(self):
844
832
descend(self.root, u'')
847
def get_entry_by_path(self, relpath):
848
"""Return an inventory entry by path.
835
def path2id(self, relpath):
836
"""Walk down through directories to return entry of last component.
850
838
:param relpath: may be either a list of path components, or a single
851
839
string, in which case it is automatically split.
878
866
# or raise an error?
882
def path2id(self, relpath):
883
"""Walk down through directories to return entry of last component.
885
:param relpath: may be either a list of path components, or a single
886
string, in which case it is automatically split.
888
This returns the entry of the last component in the path,
889
which may be either a file or a directory.
891
Returns None IFF the path is not found.
893
ie = self.get_entry_by_path(relpath)
869
return parent.file_id
898
871
def filter(self, specific_fileids):
899
872
"""Get an inventory view filtered against a set of file-ids.
1056
1029
for old_path, file_id in sorted(((op, f) for op, np, f, e in delta
1057
1030
if op is not None), reverse=True):
1058
1031
# Preserve unaltered children of file_id for later reinsertion.
1059
file_id_children = getattr(self.get_entry(file_id), 'children', {})
1032
file_id_children = getattr(self[file_id], 'children', {})
1060
1033
if len(file_id_children):
1061
1034
children[file_id] = file_id_children
1062
1035
if self.id2path(file_id) != old_path:
1136
1109
XXX: We may not want to merge this into bzr.dev.
1138
1111
if self.root is None:
1140
return iter(viewvalues(self._byid))
1113
for _, ie in self._byid.iteritems():
1142
1116
def __len__(self):
1143
1117
"""Returns number of entries."""
1144
1118
return len(self._byid)
1146
def get_entry(self, file_id):
1120
def __getitem__(self, file_id):
1147
1121
"""Return the entry for given file_id.
1149
1123
>>> inv = Inventory()
1150
1124
>>> inv.add(InventoryFile('123123', 'hello.c', ROOT_ID))
1151
1125
InventoryFile('123123', 'hello.c', parent_id='TREE_ROOT', sha1=None, len=None, revision=None)
1152
>>> inv.get_entry('123123').name
1126
>>> inv['123123'].name
1162
1136
return self._byid[file_id].kind
1164
1138
def get_child(self, parent_id, filename):
1165
return self.get_entry(parent_id).children.get(filename)
1139
return self[parent_id].children.get(filename)
1167
1141
def _add_child(self, entry):
1168
1142
"""Add an entry to the inventory, without adding it to its parent"""
1232
1204
InventoryFile('123', 'foo.c', parent_id='TREE_ROOT', sha1=None, len=None, revision=None)
1233
1205
>>> inv.has_id('123')
1235
>>> inv.delete('123')
1236
1208
>>> inv.has_id('123')
1239
ie = self.get_entry(file_id)
1240
1212
del self._byid[file_id]
1241
1213
if ie.parent_id is not None:
1242
del self.get_entry(ie.parent_id).children[ie.name]
1214
del self[ie.parent_id].children[ie.name]
1244
1216
def __eq__(self, other):
1245
1217
"""Compare two sets by comparing their contents.
1284
1256
def _make_delta(self, old):
1285
1257
"""Make an inventory delta from two inventories."""
1286
old_getter = old.get_entry
1287
new_getter = self.get_entry
1288
old_ids = set(old.iter_all_ids())
1289
new_ids = set(self.iter_all_ids())
1258
old_getter = getattr(old, '_byid', old)
1259
new_getter = self._byid
1260
old_ids = set(old_getter)
1261
new_ids = set(new_getter)
1290
1262
adds = new_ids - old_ids
1291
1263
deletes = old_ids - new_ids
1292
1264
if not adds and not deletes:
1297
1269
for file_id in deletes:
1298
1270
delta.append((old.id2path(file_id), None, file_id, None))
1299
1271
for file_id in adds:
1300
delta.append((None, self.id2path(file_id), file_id, self.get_entry(file_id)))
1272
delta.append((None, self.id2path(file_id), file_id, self[file_id]))
1301
1273
for file_id in common:
1302
new_ie = new_getter(file_id)
1303
old_ie = old_getter(file_id)
1274
new_ie = new_getter[file_id]
1275
old_ie = old_getter[file_id]
1304
1276
# If xml_serializer returns the cached InventoryEntries (rather
1305
1277
# than always doing .copy()), inlining the 'is' check saves 2.7M
1306
1278
# calls to __eq__. Under lsprof this saves 20s => 6s.
1323
1295
ie = to_find_delete.pop()
1324
1296
to_delete.append(ie.file_id)
1325
1297
if ie.kind == 'directory':
1326
to_find_delete.extend(viewvalues(ie.children))
1298
to_find_delete.extend(ie.children.values())
1327
1299
for file_id in reversed(to_delete):
1328
ie = self.get_entry(file_id)
1329
1301
del self._byid[file_id]
1330
1302
if ie.parent_id is not None:
1331
del self.get_entry(ie.parent_id).children[ie.name]
1303
del self[ie.parent_id].children[ie.name]
1333
1305
self.root = None
1429
1401
if entry.parent_id is not None:
1430
1402
parent_str = entry.parent_id
1433
1405
name_str = entry.name.encode("utf8")
1434
1406
if entry.kind == 'file':
1435
1407
if entry.executable:
1439
return b"file: %s\n%s\n%s\n%s\n%s\n%d\n%s" % (
1411
return "file: %s\n%s\n%s\n%s\n%s\n%d\n%s" % (
1440
1412
entry.file_id, parent_str, name_str, entry.revision,
1441
1413
entry.text_sha1, entry.text_size, exec_str)
1442
1414
elif entry.kind == 'directory':
1443
return b"dir: %s\n%s\n%s\n%s" % (
1415
return "dir: %s\n%s\n%s\n%s" % (
1444
1416
entry.file_id, parent_str, name_str, entry.revision)
1445
1417
elif entry.kind == 'symlink':
1446
return b"symlink: %s\n%s\n%s\n%s\n%s" % (
1418
return "symlink: %s\n%s\n%s\n%s\n%s" % (
1447
1419
entry.file_id, parent_str, name_str, entry.revision,
1448
1420
entry.symlink_target.encode("utf8"))
1449
1421
elif entry.kind == 'tree-reference':
1450
return b"tree: %s\n%s\n%s\n%s\n%s" % (
1422
return "tree: %s\n%s\n%s\n%s\n%s" % (
1451
1423
entry.file_id, parent_str, name_str, entry.revision,
1452
1424
entry.reference_revision)
1515
1487
keys = [StaticTuple(f,).intern() for f in directories_to_expand]
1516
1488
directories_to_expand = set()
1517
1489
items = self.parent_id_basename_to_file_id.iteritems(keys)
1518
next_file_ids = {item[1] for item in items}
1490
next_file_ids = set([item[1] for item in items])
1519
1491
next_file_ids = next_file_ids.difference(interesting)
1520
1492
interesting.update(next_file_ids)
1521
1493
for entry in self._getitems(next_file_ids):
1568
def _bytes_to_utf8name_key(data):
1569
"""Get the file_id, revision_id key out of data."""
1540
def _bytes_to_utf8name_key(bytes):
1541
"""Get the file_id, revision_id key out of bytes."""
1570
1542
# We don't normally care about name, except for times when we want
1571
1543
# to filter out empty names because of non rich-root...
1572
sections = data.split(b'\n')
1573
kind, file_id = sections[0].split(b': ')
1574
return (sections[2], bytesintern(file_id), bytesintern(sections[3]))
1544
sections = bytes.split('\n')
1545
kind, file_id = sections[0].split(': ')
1546
return (sections[2], intern(file_id), intern(sections[3]))
1576
1548
def _bytes_to_entry(self, bytes):
1577
1549
"""Deserialise a serialised entry."""
1578
sections = bytes.split(b'\n')
1579
if sections[0].startswith(b"file: "):
1550
sections = bytes.split('\n')
1551
if sections[0].startswith("file: "):
1580
1552
result = InventoryFile(sections[0][6:],
1581
1553
sections[2].decode('utf8'),
1583
1555
result.text_sha1 = sections[4]
1584
1556
result.text_size = int(sections[5])
1585
result.executable = sections[6] == b"Y"
1586
elif sections[0].startswith(b"dir: "):
1557
result.executable = sections[6] == "Y"
1558
elif sections[0].startswith("dir: "):
1587
1559
result = CHKInventoryDirectory(sections[0][5:],
1588
1560
sections[2].decode('utf8'),
1589
1561
sections[1], self)
1590
elif sections[0].startswith(b"symlink: "):
1562
elif sections[0].startswith("symlink: "):
1591
1563
result = InventoryLink(sections[0][9:],
1592
1564
sections[2].decode('utf8'),
1594
1566
result.symlink_target = sections[4].decode('utf8')
1595
elif sections[0].startswith(b"tree: "):
1567
elif sections[0].startswith("tree: "):
1596
1568
result = TreeReference(sections[0][6:],
1597
1569
sections[2].decode('utf8'),
1599
1571
result.reference_revision = sections[4]
1601
1573
raise ValueError("Not a serialised entry %r" % bytes)
1602
result.file_id = bytesintern(result.file_id)
1603
result.revision = bytesintern(sections[3])
1604
if result.parent_id == b'':
1574
result.file_id = intern(result.file_id)
1575
result.revision = intern(sections[3])
1576
if result.parent_id == '':
1605
1577
result.parent_id = None
1606
1578
self._fileid_to_entry_cache[result.file_id] = result
1624
1596
result = CHKInventory(self._search_key_name)
1625
1597
if propagate_caches:
1626
1598
# Just propagate the path-to-fileid cache for now
1627
result._path_to_fileid_cache = self._path_to_fileid_cache.copy()
1599
result._path_to_fileid_cache = dict(self._path_to_fileid_cache.iteritems())
1628
1600
search_key_func = chk_map.search_key_registry.get(self._search_key_name)
1629
1601
self.id_to_entry._ensure_root()
1630
1602
maximum_size = self.id_to_entry._root_node.maximum_size
1738
1710
new_key, [None, None])[1] = new_value
1739
1711
# validate that deletes are complete.
1740
1712
for file_id in deletes:
1741
entry = self.get_entry(file_id)
1713
entry = self[file_id]
1742
1714
if entry.kind != 'directory':
1744
1716
# This loop could potentially be better by using the id_basename
1745
1717
# map to just get the child file ids.
1746
for child in viewvalues(entry.children):
1718
for child in entry.children.values():
1747
1719
if child.file_id not in altered:
1748
1720
raise errors.InconsistentDelta(self.id2path(child.file_id),
1749
1721
child.file_id, "Child not deleted or reparented when "
1755
1727
# re-keying, but its simpler to just output that as a delete+add
1756
1728
# to spend less time calculating the delta.
1757
1729
delta_list = []
1758
for key, (old_key, value) in viewitems(parent_id_basename_delta):
1730
for key, (old_key, value) in parent_id_basename_delta.iteritems():
1759
1731
if value is not None:
1760
1732
delta_list.append((old_key, key, value))
1764
1736
parents.discard(('', None))
1765
1737
for parent_path, parent in parents:
1767
if result.get_entry(parent).kind != 'directory':
1739
if result[parent].kind != 'directory':
1768
1740
raise errors.InconsistentDelta(result.id2path(parent), parent,
1769
1741
'Not a directory, but given children')
1770
1742
except errors.NoSuchId:
1786
1758
:return: A CHKInventory
1788
lines = bytes.split(b'\n')
1789
if lines[-1] != b'':
1760
lines = bytes.split('\n')
1790
1762
raise AssertionError('bytes to deserialize must end with an eol')
1792
if lines[0] != b'chkinventory:':
1764
if lines[0] != 'chkinventory:':
1793
1765
raise ValueError("not a serialised CHKInventory: %r" % bytes)
1795
allowed_keys = frozenset((b'root_id', b'revision_id',
1796
b'parent_id_basename_to_file_id',
1797
b'search_key_name', b'id_to_entry'))
1767
allowed_keys = frozenset(['root_id', 'revision_id', 'search_key_name',
1768
'parent_id_basename_to_file_id',
1798
1770
for line in lines[1:]:
1799
key, value = line.split(b': ', 1)
1771
key, value = line.split(': ', 1)
1800
1772
if key not in allowed_keys:
1801
1773
raise errors.BzrError('Unknown key in inventory: %r\n%r'
1802
1774
% (key, bytes))
1804
1776
raise errors.BzrError('Duplicate key in inventory: %r\n%r'
1805
1777
% (key, bytes))
1806
1778
info[key] = value
1807
revision_id = bytesintern(info[b'revision_id'])
1808
root_id = bytesintern(info[b'root_id'])
1809
search_key_name = bytesintern(info.get(b'search_key_name', b'plain'))
1810
parent_id_basename_to_file_id = bytesintern(info.get(
1811
b'parent_id_basename_to_file_id', None))
1812
if not parent_id_basename_to_file_id.startswith(b'sha1:'):
1779
revision_id = intern(info['revision_id'])
1780
root_id = intern(info['root_id'])
1781
search_key_name = intern(info.get('search_key_name', 'plain'))
1782
parent_id_basename_to_file_id = intern(info.get(
1783
'parent_id_basename_to_file_id', None))
1784
if not parent_id_basename_to_file_id.startswith('sha1:'):
1813
1785
raise ValueError('parent_id_basename_to_file_id should be a sha1'
1814
1786
' key not %r' % (parent_id_basename_to_file_id,))
1815
id_to_entry = info[b'id_to_entry']
1816
if not id_to_entry.startswith(b'sha1:'):
1787
id_to_entry = info['id_to_entry']
1788
if not id_to_entry.startswith('sha1:'):
1817
1789
raise ValueError('id_to_entry should be a sha1'
1818
1790
' key not %r' % (id_to_entry,))
1821
1793
result.revision_id = revision_id
1822
1794
result.root_id = root_id
1823
1795
search_key_func = chk_map.search_key_registry.get(
1824
result._search_key_name.decode("ascii"))
1796
result._search_key_name)
1825
1797
if parent_id_basename_to_file_id is not None:
1826
1798
result.parent_id_basename_to_file_id = chk_map.CHKMap(
1827
1799
chk_store, StaticTuple(parent_id_basename_to_file_id,),
1887
1859
if entry.parent_id is not None:
1888
1860
parent_id = entry.parent_id
1891
1863
return StaticTuple(parent_id, entry.name.encode('utf8')).intern()
1893
def get_entry(self, file_id):
1865
def __getitem__(self, file_id):
1894
1866
"""map a single file_id -> InventoryEntry."""
1895
1867
if file_id is None:
1896
1868
raise errors.NoSuchId(self, file_id)
1901
1873
return self._bytes_to_entry(
1902
next(self.id_to_entry.iteritems([StaticTuple(file_id,)]))[1])
1874
self.id_to_entry.iteritems([StaticTuple(file_id,)]).next()[1])
1903
1875
except StopIteration:
1904
1876
# really we're passing an inventory, not a tree...
1905
1877
raise errors.NoSuchId(self, file_id)
1907
1879
def _getitems(self, file_ids):
1908
"""Similar to get_entry, but lets you query for multiple.
1880
"""Similar to __getitem__, but lets you query for multiple.
1910
1882
The returned order is undefined. And currently if an item doesn't
1911
1883
exist, it isn't included in the output.
1982
1954
last_parent_id = last_parent_ie = None
1983
1955
pid_items = self.parent_id_basename_to_file_id.iteritems()
1984
1956
for key, child_file_id in pid_items:
1985
if key == (b'', b''): # This is the root
1957
if key == ('', ''): # This is the root
1986
1958
if child_file_id != self.root_id:
1987
1959
raise ValueError('Data inconsistency detected.'
1988
1960
' We expected data with key ("","") to match'
2099
2071
def _make_delta(self, old):
2100
2072
"""Make an inventory delta from two inventories."""
2101
if not isinstance(old, CHKInventory):
2073
if type(old) != CHKInventory:
2102
2074
return CommonInventory._make_delta(self, old)
2104
2076
for key, old_value, self_value in \
2121
2093
def path2id(self, relpath):
2122
2094
"""See CommonInventory.path2id()."""
2123
2095
# TODO: perhaps support negative hits?
2124
if isinstance(relpath, (str, text_type)):
2096
if isinstance(relpath, basestring):
2125
2097
names = osutils.splitpath(relpath)
2127
2099
names = relpath
2161
2133
def to_lines(self):
2162
2134
"""Serialise the inventory to lines."""
2163
lines = [b"chkinventory:\n"]
2135
lines = ["chkinventory:\n"]
2164
2136
if self._search_key_name != 'plain':
2165
2137
# custom ordering grouping things that don't change together
2166
lines.append(b'search_key_name: %s\n' % (
2167
self._search_key_name.encode('ascii')))
2168
lines.append(b"root_id: %s\n" % self.root_id)
2169
lines.append(b'parent_id_basename_to_file_id: %s\n' %
2138
lines.append('search_key_name: %s\n' % (self._search_key_name,))
2139
lines.append("root_id: %s\n" % self.root_id)
2140
lines.append('parent_id_basename_to_file_id: %s\n' %
2170
2141
(self.parent_id_basename_to_file_id.key()[0],))
2171
lines.append(b"revision_id: %s\n" % self.revision_id)
2172
lines.append(b"id_to_entry: %s\n" % (self.id_to_entry.key()[0],))
2142
lines.append("revision_id: %s\n" % self.revision_id)
2143
lines.append("id_to_entry: %s\n" % (self.id_to_entry.key()[0],))
2174
lines.append(b"revision_id: %s\n" % self.revision_id)
2175
lines.append(b"root_id: %s\n" % self.root_id)
2145
lines.append("revision_id: %s\n" % self.revision_id)
2146
lines.append("root_id: %s\n" % self.root_id)
2176
2147
if self.parent_id_basename_to_file_id is not None:
2177
lines.append(b'parent_id_basename_to_file_id: %s\n' %
2148
lines.append('parent_id_basename_to_file_id: %s\n' %
2178
2149
(self.parent_id_basename_to_file_id.key()[0],))
2179
lines.append(b"id_to_entry: %s\n" % (self.id_to_entry.key()[0],))
2150
lines.append("id_to_entry: %s\n" % (self.id_to_entry.key()[0],))
2183
2154
def root(self):
2184
2155
"""Get the root entry."""
2185
return self.get_entry(self.root_id)
2156
return self[self.root_id]
2188
2159
class CHKInventoryDirectory(InventoryDirectory):
2270
2241
accessed on this platform by the normalized path.
2271
2242
:return: The NFC normalised version of name.
2273
#------- This has been copied to breezy.dirstate.DirState.add, please
2244
#------- This has been copied to bzrlib.dirstate.DirState.add, please
2274
2245
# keep them synchronised.
2275
2246
# we dont import normalized_filename directly because we want to be
2276
2247
# able to change the implementation at runtime for tests.