129
130
RENAMED = 'renamed'
130
131
MODIFIED_AND_RENAMED = 'modified and renamed'
132
__slots__ = ['file_id', 'revision', 'parent_id', 'name']
134
# Attributes that all InventoryEntry instances are expected to have, but
135
# that don't vary for all kinds of entry. (e.g. symlink_target is only
136
# relevant to InventoryLink, so there's no reason to make every
137
# InventoryFile instance allocate space to hold a value for it.)
138
# Attributes that only vary for files: executable, text_sha1, text_size,
144
# Attributes that only vary for symlinks: symlink_target
145
symlink_target = None
146
# Attributes that only vary for tree-references: reference_revision
147
reference_revision = None
150
135
def detect_changes(self, old_entry):
151
136
"""Return a (text_modified, meta_modified) from this to old_entry.
219
214
if '/' in name or '\\' in name:
220
215
raise errors.InvalidEntryName(name=name)
216
self.executable = False
218
self.text_sha1 = None
219
self.text_size = None
221
220
self.file_id = file_id
222
self.text_id = text_id
224
223
self.parent_id = parent_id
224
self.symlink_target = None
225
self.reference_revision = None
226
227
def kind_character(self):
227
228
"""Return a short kind indicator useful for appending to names."""
228
raise errors.BzrError('unknown kind %r' % self.kind)
229
raise BzrError('unknown kind %r' % self.kind)
230
231
known_kinds = ('file', 'directory', 'symlink')
233
def _put_in_tar(self, item, tree):
234
"""populate item for stashing in a tar, and return the content stream.
236
If no content is available, return None.
238
raise BzrError("don't know how to export {%s} of kind %r" %
239
(self.file_id, self.kind))
241
@deprecated_method(deprecated_in((1, 6, 0)))
242
def put_on_disk(self, dest, dp, tree):
243
"""Create a representation of self on disk in the prefix dest.
245
This is a template method - implement _put_on_disk in subclasses.
247
fullpath = osutils.pathjoin(dest, dp)
248
self._put_on_disk(fullpath, tree)
249
# mutter(" export {%s} kind %s to %s", self.file_id,
250
# self.kind, fullpath)
252
def _put_on_disk(self, fullpath, tree):
253
"""Put this entry onto disk at fullpath, from tree tree."""
254
raise BzrError("don't know how to export {%s} of kind %r" % (self.file_id, self.kind))
232
256
def sorted_children(self):
233
257
return sorted(self.children.items())
248
272
:param rev_id: Revision id from which this InventoryEntry was loaded.
249
273
Not necessarily the last-changed revision for this file.
250
274
:param inv: Inventory from which the entry was loaded.
275
:param tree: RevisionTree for this entry.
252
277
if self.parent_id is not None:
253
278
if not inv.has_id(self.parent_id):
254
raise errors.BzrCheckError(
255
'missing parent {%s} in inventory for revision {%s}' % (
256
self.parent_id, rev_id))
257
checker._add_entry_to_text_key_references(inv, self)
258
self._check(checker, rev_id)
279
raise BzrCheckError('missing parent {%s} in inventory for revision {%s}'
280
% (self.parent_id, rev_id))
281
self._check(checker, rev_id, tree)
260
def _check(self, checker, rev_id):
283
def _check(self, checker, rev_id, tree):
261
284
"""Check this inventory entry for kind specific errors."""
262
checker._report_items.append(
263
'unknown entry kind %r in revision {%s}' % (self.kind, rev_id))
285
raise BzrCheckError('unknown entry kind %r in revision {%s}' %
266
289
"""Clone this inventory entry."""
399
class RootEntry(InventoryEntry):
401
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
402
'text_id', 'parent_id', 'children', 'executable',
403
'revision', 'symlink_target', 'reference_revision']
405
def _check(self, checker, rev_id, tree):
406
"""See InventoryEntry._check"""
408
def __init__(self, file_id):
409
self.file_id = file_id
411
self.kind = 'directory'
412
self.parent_id = None
415
symbol_versioning.warn('RootEntry is deprecated as of bzr 0.10.'
416
' Please use InventoryDirectory instead.',
417
DeprecationWarning, stacklevel=2)
419
def __eq__(self, other):
420
if not isinstance(other, RootEntry):
421
return NotImplemented
423
return (self.file_id == other.file_id) \
424
and (self.children == other.children)
376
427
class InventoryDirectory(InventoryEntry):
377
428
"""A directory in an inventory."""
379
__slots__ = ['children']
383
def _check(self, checker, rev_id):
430
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
431
'text_id', 'parent_id', 'children', 'executable',
432
'revision', 'symlink_target', 'reference_revision']
434
def _check(self, checker, rev_id, tree):
384
435
"""See InventoryEntry._check"""
385
# In non rich root repositories we do not expect a file graph for the
387
if self.name == '' and not checker.rich_roots:
389
# Directories are stored as an empty file, but the file should exist
390
# to provide a per-fileid log. The hash of every directory content is
391
# "da..." below (the sha1sum of '').
392
checker.add_pending_item(rev_id,
393
('texts', self.file_id, self.revision), 'text',
394
'da39a3ee5e6b4b0d3255bfef95601890afd80709')
436
if self.text_sha1 is not None or self.text_size is not None or self.text_id is not None:
437
raise BzrCheckError('directory {%s} has text in revision {%s}'
438
% (self.file_id, rev_id))
397
441
other = InventoryDirectory(self.file_id, self.name, self.parent_id)
403
447
def __init__(self, file_id, name, parent_id):
404
448
super(InventoryDirectory, self).__init__(file_id, name, parent_id)
405
449
self.children = {}
450
self.kind = 'directory'
407
452
def kind_character(self):
408
453
"""See InventoryEntry.kind_character."""
456
def _put_in_tar(self, item, tree):
457
"""See InventoryEntry._put_in_tar."""
458
item.type = tarfile.DIRTYPE
465
def _put_on_disk(self, fullpath, tree):
466
"""See InventoryEntry._put_on_disk."""
412
470
class InventoryFile(InventoryEntry):
413
471
"""A file in an inventory."""
415
__slots__ = ['text_sha1', 'text_size', 'text_id', 'executable']
419
def __init__(self, file_id, name, parent_id):
420
super(InventoryFile, self).__init__(file_id, name, parent_id)
421
self.text_sha1 = None
422
self.text_size = None
424
self.executable = False
426
def _check(self, checker, tree_revision_id):
473
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
474
'text_id', 'parent_id', 'children', 'executable',
475
'revision', 'symlink_target', 'reference_revision']
477
def _check(self, checker, tree_revision_id, tree):
427
478
"""See InventoryEntry._check"""
428
# TODO: check size too.
429
checker.add_pending_item(tree_revision_id,
430
('texts', self.file_id, self.revision), 'text',
432
if self.text_size is None:
433
checker._report_items.append(
434
'fileid {%s} in {%s} has None for text_size' % (self.file_id,
479
key = (self.file_id, self.revision)
480
if key in checker.checked_texts:
481
prev_sha = checker.checked_texts[key]
482
if prev_sha != self.text_sha1:
484
'mismatched sha1 on {%s} in {%s} (%s != %s) %r' %
485
(self.file_id, tree_revision_id, prev_sha, self.text_sha1,
488
checker.repeated_text_cnt += 1
491
checker.checked_text_cnt += 1
492
# We can't check the length, because Weave doesn't store that
493
# information, and the whole point of looking at the weave's
494
# sha1sum is that we don't have to extract the text.
495
if (self.text_sha1 != tree._repository.texts.get_sha1s([key])[key]):
496
raise BzrCheckError('text {%s} version {%s} wrong sha1' % key)
497
checker.checked_texts[key] = self.text_sha1
438
500
other = InventoryFile(self.file_id, self.name, self.parent_id)
470
532
"""See InventoryEntry.has_text."""
535
def __init__(self, file_id, name, parent_id):
536
super(InventoryFile, self).__init__(file_id, name, parent_id)
473
539
def kind_character(self):
474
540
"""See InventoryEntry.kind_character."""
543
def _put_in_tar(self, item, tree):
544
"""See InventoryEntry._put_in_tar."""
545
item.type = tarfile.REGTYPE
546
fileobj = tree.get_file(self.file_id)
547
item.size = self.text_size
548
if tree.is_executable(self.file_id):
554
def _put_on_disk(self, fullpath, tree):
555
"""See InventoryEntry._put_on_disk."""
556
osutils.pumpfile(tree.get_file(self.file_id), file(fullpath, 'wb'))
557
if tree.is_executable(self.file_id):
558
os.chmod(fullpath, 0755)
477
560
def _read_tree_state(self, path, work_tree):
478
561
"""See InventoryEntry._read_tree_state."""
479
562
self.text_sha1 = work_tree.get_file_sha1(self.file_id, path=path)
511
594
class InventoryLink(InventoryEntry):
512
595
"""A file in an inventory."""
514
__slots__ = ['symlink_target']
518
def __init__(self, file_id, name, parent_id):
519
super(InventoryLink, self).__init__(file_id, name, parent_id)
520
self.symlink_target = None
522
def _check(self, checker, tree_revision_id):
597
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
598
'text_id', 'parent_id', 'children', 'executable',
599
'revision', 'symlink_target', 'reference_revision']
601
def _check(self, checker, rev_id, tree):
523
602
"""See InventoryEntry._check"""
603
if self.text_sha1 is not None or self.text_size is not None or self.text_id is not None:
604
raise BzrCheckError('symlink {%s} has text in revision {%s}'
605
% (self.file_id, rev_id))
524
606
if self.symlink_target is None:
525
checker._report_items.append(
526
'symlink {%s} has no target in revision {%s}'
527
% (self.file_id, tree_revision_id))
528
# Symlinks are stored as ''
529
checker.add_pending_item(tree_revision_id,
530
('texts', self.file_id, self.revision), 'text',
531
'da39a3ee5e6b4b0d3255bfef95601890afd80709')
607
raise BzrCheckError('symlink {%s} has no target in revision {%s}'
608
% (self.file_id, rev_id))
534
611
other = InventoryLink(self.file_id, self.name, self.parent_id)
564
641
differ = DiffSymlink(old_tree, new_tree, output_to)
565
642
return differ.diff_symlink(old_target, new_target)
644
def __init__(self, file_id, name, parent_id):
645
super(InventoryLink, self).__init__(file_id, name, parent_id)
646
self.kind = 'symlink'
567
648
def kind_character(self):
568
649
"""See InventoryEntry.kind_character."""
652
def _put_in_tar(self, item, tree):
653
"""See InventoryEntry._put_in_tar."""
654
item.type = tarfile.SYMTYPE
658
item.linkname = self.symlink_target
661
def _put_on_disk(self, fullpath, tree):
662
"""See InventoryEntry._put_on_disk."""
664
os.symlink(self.symlink_target, fullpath)
666
raise BzrError("Failed to create symlink %r -> %r, error: %s" % (fullpath, self.symlink_target, e))
571
668
def _read_tree_state(self, path, work_tree):
572
669
"""See InventoryEntry._read_tree_state."""
573
670
self.symlink_target = work_tree.get_symlink_target(self.file_id)
864
947
descend(self.root, u'')
867
def path2id(self, relpath):
950
def path2id(self, name):
868
951
"""Walk down through directories to return entry of last component.
870
:param relpath: may be either a list of path components, or a single
871
string, in which case it is automatically split.
953
names may be either a list of path components, or a single
954
string, in which case it is automatically split.
873
956
This returns the entry of the last component in the path,
874
957
which may be either a file or a directory.
876
959
Returns None IFF the path is not found.
878
if isinstance(relpath, basestring):
879
names = osutils.splitpath(relpath)
961
if isinstance(name, basestring):
962
name = osutils.splitpath(name)
964
# mutter("lookup path %r" % name)
884
967
parent = self.root
1346
1430
new_name = ensure_normalized_name(new_name)
1347
1431
if not is_valid_name(new_name):
1348
raise errors.BzrError("not an acceptable filename: %r" % new_name)
1432
raise BzrError("not an acceptable filename: %r" % new_name)
1350
1434
new_parent = self._byid[new_parent_id]
1351
1435
if new_name in new_parent.children:
1352
raise errors.BzrError("%r already exists in %r" %
1353
(new_name, self.id2path(new_parent_id)))
1436
raise BzrError("%r already exists in %r" % (new_name, self.id2path(new_parent_id)))
1355
1438
new_parent_idpath = self.get_idpath(new_parent_id)
1356
1439
if file_id in new_parent_idpath:
1357
raise errors.BzrError(
1358
"cannot move directory %r into a subdirectory of itself, %r"
1440
raise BzrError("cannot move directory %r into a subdirectory of itself, %r"
1359
1441
% (self.id2path(file_id), self.id2path(new_parent_id)))
1361
1443
file_ie = self._byid[file_id]
1458
1539
raise ValueError("unknown kind %r" % entry.kind)
1460
def _expand_fileids_to_parents_and_children(self, file_ids):
1461
"""Give a more wholistic view starting with the given file_ids.
1463
For any file_id which maps to a directory, we will include all children
1464
of that directory. We will also include all directories which are
1465
parents of the given file_ids, but we will not include their children.
1472
fringle # fringle-id
1476
if given [foo-id] we will include
1477
TREE_ROOT as interesting parents
1479
foo-id, baz-id, frob-id, fringle-id
1483
# TODO: Pre-pass over the list of fileids to see if anything is already
1484
# deserialized in self._fileid_to_entry_cache
1486
directories_to_expand = set()
1487
children_of_parent_id = {}
1488
# It is okay if some of the fileids are missing
1489
for entry in self._getitems(file_ids):
1490
if entry.kind == 'directory':
1491
directories_to_expand.add(entry.file_id)
1492
interesting.add(entry.parent_id)
1493
children_of_parent_id.setdefault(entry.parent_id, set()
1494
).add(entry.file_id)
1496
# Now, interesting has all of the direct parents, but not the
1497
# parents of those parents. It also may have some duplicates with
1499
remaining_parents = interesting.difference(file_ids)
1500
# When we hit the TREE_ROOT, we'll get an interesting parent of None,
1501
# but we don't actually want to recurse into that
1502
interesting.add(None) # this will auto-filter it in the loop
1503
remaining_parents.discard(None)
1504
while remaining_parents:
1505
next_parents = set()
1506
for entry in self._getitems(remaining_parents):
1507
next_parents.add(entry.parent_id)
1508
children_of_parent_id.setdefault(entry.parent_id, set()
1509
).add(entry.file_id)
1510
# Remove any search tips we've already processed
1511
remaining_parents = next_parents.difference(interesting)
1512
interesting.update(remaining_parents)
1513
# We should probably also .difference(directories_to_expand)
1514
interesting.update(file_ids)
1515
interesting.discard(None)
1516
while directories_to_expand:
1517
# Expand directories by looking in the
1518
# parent_id_basename_to_file_id map
1519
keys = [StaticTuple(f,).intern() for f in directories_to_expand]
1520
directories_to_expand = set()
1521
items = self.parent_id_basename_to_file_id.iteritems(keys)
1522
next_file_ids = set([item[1] for item in items])
1523
next_file_ids = next_file_ids.difference(interesting)
1524
interesting.update(next_file_ids)
1525
for entry in self._getitems(next_file_ids):
1526
if entry.kind == 'directory':
1527
directories_to_expand.add(entry.file_id)
1528
children_of_parent_id.setdefault(entry.parent_id, set()
1529
).add(entry.file_id)
1530
return interesting, children_of_parent_id
1532
def filter(self, specific_fileids):
1533
"""Get an inventory view filtered against a set of file-ids.
1535
Children of directories and parents are included.
1537
The result may or may not reference the underlying inventory
1538
so it should be treated as immutable.
1541
parent_to_children) = self._expand_fileids_to_parents_and_children(
1543
# There is some overlap here, but we assume that all interesting items
1544
# are in the _fileid_to_entry_cache because we had to read them to
1545
# determine if they were a dir we wanted to recurse, or just a file
1546
# This should give us all the entries we'll want to add, so start
1548
other = Inventory(self.root_id)
1549
other.root.revision = self.root.revision
1550
other.revision_id = self.revision_id
1551
if not interesting or not parent_to_children:
1552
# empty filter, or filtering entrys that don't exist
1553
# (if even 1 existed, then we would have populated
1554
# parent_to_children with at least the tree root.)
1556
cache = self._fileid_to_entry_cache
1557
remaining_children = collections.deque(parent_to_children[self.root_id])
1558
while remaining_children:
1559
file_id = remaining_children.popleft()
1561
if ie.kind == 'directory':
1562
ie = ie.copy() # We create a copy to depopulate the .children attribute
1563
# TODO: depending on the uses of 'other' we should probably alwyas
1564
# '.copy()' to prevent someone from mutating other and
1565
# invaliding our internal cache
1567
if file_id in parent_to_children:
1568
remaining_children.extend(parent_to_children[file_id])
1572
1542
def _bytes_to_utf8name_key(bytes):
1573
1543
"""Get the file_id, revision_id key out of bytes."""
1603
1573
result.reference_revision = sections[4]
1605
1575
raise ValueError("Not a serialised entry %r" % bytes)
1606
result.file_id = intern(result.file_id)
1607
result.revision = intern(sections[3])
1576
result.revision = sections[3]
1608
1577
if result.parent_id == '':
1609
1578
result.parent_id = None
1610
1579
self._fileid_to_entry_cache[result.file_id] = result
1582
def _get_mutable_inventory(self):
1583
"""See CommonInventory._get_mutable_inventory."""
1584
entries = self.iter_entries()
1585
inv = Inventory(None, self.revision_id)
1586
for path, inv_entry in entries:
1587
inv.add(inv_entry.copy())
1613
1590
def create_by_apply_delta(self, inventory_delta, new_revision_id,
1614
1591
propagate_caches=False):
1615
1592
"""Create a new CHKInventory by applying inventory_delta to this one.
1808
1785
raise errors.BzrError('Duplicate key in inventory: %r\n%r'
1809
1786
% (key, bytes))
1810
1787
info[key] = value
1811
revision_id = intern(info['revision_id'])
1812
root_id = intern(info['root_id'])
1813
search_key_name = intern(info.get('search_key_name', 'plain'))
1814
parent_id_basename_to_file_id = intern(info.get(
1815
'parent_id_basename_to_file_id', None))
1816
if not parent_id_basename_to_file_id.startswith('sha1:'):
1817
raise ValueError('parent_id_basename_to_file_id should be a sha1'
1818
' key not %r' % (parent_id_basename_to_file_id,))
1788
revision_id = info['revision_id']
1789
root_id = info['root_id']
1790
search_key_name = info.get('search_key_name', 'plain')
1791
parent_id_basename_to_file_id = info.get(
1792
'parent_id_basename_to_file_id', None)
1819
1793
id_to_entry = info['id_to_entry']
1820
if not id_to_entry.startswith('sha1:'):
1821
raise ValueError('id_to_entry should be a sha1'
1822
' key not %r' % (id_to_entry,))
1824
1795
result = CHKInventory(search_key_name)
1825
1796
result.revision_id = revision_id
1828
1799
result._search_key_name)
1829
1800
if parent_id_basename_to_file_id is not None:
1830
1801
result.parent_id_basename_to_file_id = chk_map.CHKMap(
1831
chk_store, StaticTuple(parent_id_basename_to_file_id,),
1802
chk_store, (parent_id_basename_to_file_id,),
1832
1803
search_key_func=search_key_func)
1834
1805
result.parent_id_basename_to_file_id = None
1836
result.id_to_entry = chk_map.CHKMap(chk_store,
1837
StaticTuple(id_to_entry,),
1807
result.id_to_entry = chk_map.CHKMap(chk_store, (id_to_entry,),
1838
1808
search_key_func=search_key_func)
1839
1809
if (result.revision_id,) != expected_revision_id:
1840
1810
raise ValueError("Mismatched revision id and expected: %r, %r" %
1905
1874
return self._bytes_to_entry(
1906
self.id_to_entry.iteritems([StaticTuple(file_id,)]).next()[1])
1875
self.id_to_entry.iteritems([(file_id,)]).next()[1])
1907
1876
except StopIteration:
1908
1877
# really we're passing an inventory, not a tree...
1909
1878
raise errors.NoSuchId(self, file_id)
1911
def _getitems(self, file_ids):
1912
"""Similar to __getitem__, but lets you query for multiple.
1914
The returned order is undefined. And currently if an item doesn't
1915
exist, it isn't included in the output.
1919
for file_id in file_ids:
1920
entry = self._fileid_to_entry_cache.get(file_id, None)
1922
remaining.append(file_id)
1924
result.append(entry)
1925
file_keys = [StaticTuple(f,).intern() for f in remaining]
1926
for file_key, value in self.id_to_entry.iteritems(file_keys):
1927
entry = self._bytes_to_entry(value)
1928
result.append(entry)
1929
self._fileid_to_entry_cache[entry.file_id] = entry
1932
1880
def has_id(self, file_id):
1933
1881
# Perhaps have an explicit 'contains' method on CHKMap ?
1934
1882
if self._fileid_to_entry_cache.get(file_id, None) is not None:
1937
self.id_to_entry.iteritems([StaticTuple(file_id,)]))) == 1
1884
return len(list(self.id_to_entry.iteritems([(file_id,)]))) == 1
1939
1886
def is_root(self, file_id):
1940
1887
return file_id == self.root_id
1970
1917
self._fileid_to_entry_cache[file_id] = ie
1973
def _preload_cache(self):
1974
"""Make sure all file-ids are in _fileid_to_entry_cache"""
1975
if self._fully_cached:
1976
return # No need to do it again
1977
# The optimal sort order is to use iteritems() directly
1978
cache = self._fileid_to_entry_cache
1979
for key, entry in self.id_to_entry.iteritems():
1981
if file_id not in cache:
1982
ie = self._bytes_to_entry(entry)
1986
last_parent_id = last_parent_ie = None
1987
pid_items = self.parent_id_basename_to_file_id.iteritems()
1988
for key, child_file_id in pid_items:
1989
if key == ('', ''): # This is the root
1990
if child_file_id != self.root_id:
1991
raise ValueError('Data inconsistency detected.'
1992
' We expected data with key ("","") to match'
1993
' the root id, but %s != %s'
1994
% (child_file_id, self.root_id))
1996
parent_id, basename = key
1997
ie = cache[child_file_id]
1998
if parent_id == last_parent_id:
1999
parent_ie = last_parent_ie
2001
parent_ie = cache[parent_id]
2002
if parent_ie.kind != 'directory':
2003
raise ValueError('Data inconsistency detected.'
2004
' An entry in the parent_id_basename_to_file_id map'
2005
' has parent_id {%s} but the kind of that object'
2006
' is %r not "directory"' % (parent_id, parent_ie.kind))
2007
if parent_ie._children is None:
2008
parent_ie._children = {}
2009
basename = basename.decode('utf-8')
2010
if basename in parent_ie._children:
2011
existing_ie = parent_ie._children[basename]
2012
if existing_ie != ie:
2013
raise ValueError('Data inconsistency detected.'
2014
' Two entries with basename %r were found'
2015
' in the parent entry {%s}'
2016
% (basename, parent_id))
2017
if basename != ie.name:
2018
raise ValueError('Data inconsistency detected.'
2019
' In the parent_id_basename_to_file_id map, file_id'
2020
' {%s} is listed as having basename %r, but in the'
2021
' id_to_entry map it is %r'
2022
% (child_file_id, basename, ie.name))
2023
parent_ie._children[basename] = ie
2024
self._fully_cached = True
2026
1920
def iter_changes(self, basis):
2027
1921
"""Generate a Tree.iter_changes change list between this and basis.
2122
2016
delta.append((old_path, new_path, file_id, entry))
2125
def path2id(self, relpath):
2019
def path2id(self, name):
2126
2020
"""See CommonInventory.path2id()."""
2127
2021
# TODO: perhaps support negative hits?
2128
result = self._path_to_fileid_cache.get(relpath, None)
2022
result = self._path_to_fileid_cache.get(name, None)
2129
2023
if result is not None:
2131
if isinstance(relpath, basestring):
2132
names = osutils.splitpath(relpath)
2025
if isinstance(name, basestring):
2026
names = osutils.splitpath(name)
2135
2029
current_id = self.root_id
2136
2030
if current_id is None:
2138
2032
parent_id_index = self.parent_id_basename_to_file_id
2140
2033
for basename in names:
2141
if cur_path is None:
2144
cur_path = cur_path + '/' + basename
2034
# TODO: Cache each path we figure out in this function.
2145
2035
basename_utf8 = basename.encode('utf8')
2146
file_id = self._path_to_fileid_cache.get(cur_path, None)
2036
key_filter = [(current_id, basename_utf8)]
2038
for (parent_id, name_utf8), file_id in parent_id_index.iteritems(
2039
key_filter=key_filter):
2040
if parent_id != current_id or name_utf8 != basename_utf8:
2041
raise errors.BzrError("corrupt inventory lookup! "
2042
"%r %r %r %r" % (parent_id, current_id, name_utf8,
2147
2044
if file_id is None:
2148
key_filter = [StaticTuple(current_id, basename_utf8)]
2149
items = parent_id_index.iteritems(key_filter)
2150
for (parent_id, name_utf8), file_id in items:
2151
if parent_id != current_id or name_utf8 != basename_utf8:
2152
raise errors.BzrError("corrupt inventory lookup! "
2153
"%r %r %r %r" % (parent_id, current_id, name_utf8,
2158
self._path_to_fileid_cache[cur_path] = file_id
2159
2046
current_id = file_id
2047
self._path_to_fileid_cache[name] = current_id
2160
2048
return current_id
2162
2050
def to_lines(self):
2167
2055
lines.append('search_key_name: %s\n' % (self._search_key_name,))
2168
2056
lines.append("root_id: %s\n" % self.root_id)
2169
2057
lines.append('parent_id_basename_to_file_id: %s\n' %
2170
(self.parent_id_basename_to_file_id.key()[0],))
2058
self.parent_id_basename_to_file_id.key())
2171
2059
lines.append("revision_id: %s\n" % self.revision_id)
2172
lines.append("id_to_entry: %s\n" % (self.id_to_entry.key()[0],))
2060
lines.append("id_to_entry: %s\n" % self.id_to_entry.key())
2174
2062
lines.append("revision_id: %s\n" % self.revision_id)
2175
2063
lines.append("root_id: %s\n" % self.root_id)
2176
2064
if self.parent_id_basename_to_file_id is not None:
2177
2065
lines.append('parent_id_basename_to_file_id: %s\n' %
2178
(self.parent_id_basename_to_file_id.key()[0],))
2179
lines.append("id_to_entry: %s\n" % (self.id_to_entry.key()[0],))
2066
self.parent_id_basename_to_file_id.key())
2067
lines.append("id_to_entry: %s\n" % self.id_to_entry.key())
2188
2076
class CHKInventoryDirectory(InventoryDirectory):
2189
2077
"""A directory in an inventory."""
2191
__slots__ = ['_children', '_chk_inventory']
2079
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
2080
'text_id', 'parent_id', '_children', 'executable',
2081
'revision', 'symlink_target', 'reference_revision',
2193
2084
def __init__(self, file_id, name, parent_id, chk_inventory):
2194
2085
# Don't call InventoryDirectory.__init__ - it isn't right for this
2196
2087
InventoryEntry.__init__(self, file_id, name, parent_id)
2197
2088
self._children = None
2089
self.kind = 'directory'
2198
2090
self._chk_inventory = chk_inventory