1
# Copyright (C) 2005-2010 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
52
52
from bzrlib.symbol_versioning import deprecated_in, deprecated_method
53
53
from bzrlib.trace import mutter
54
from bzrlib.static_tuple import StaticTuple
57
56
class InventoryEntry(object):
959
958
descend(self.root, u'')
962
def path2id(self, relpath):
961
def path2id(self, name):
963
962
"""Walk down through directories to return entry of last component.
965
:param relpath: may be either a list of path components, or a single
966
string, in which case it is automatically split.
964
names may be either a list of path components, or a single
965
string, in which case it is automatically split.
968
967
This returns the entry of the last component in the path,
969
968
which may be either a file or a directory.
971
970
Returns None IFF the path is not found.
973
if isinstance(relpath, basestring):
974
names = osutils.splitpath(relpath)
972
if isinstance(name, basestring):
973
name = osutils.splitpath(name)
975
# mutter("lookup path %r" % name)
979
978
parent = self.root
1600
1596
interesting.add(None) # this will auto-filter it in the loop
1601
1597
remaining_parents.discard(None)
1602
1598
while remaining_parents:
1599
if None in remaining_parents:
1600
import pdb; pdb.set_trace()
1603
1601
next_parents = set()
1604
1602
for entry in self._getitems(remaining_parents):
1605
1603
next_parents.add(entry.parent_id)
1614
1612
while directories_to_expand:
1615
1613
# Expand directories by looking in the
1616
1614
# parent_id_basename_to_file_id map
1617
keys = [StaticTuple(f,).intern() for f in directories_to_expand]
1615
keys = [(f,) for f in directories_to_expand]
1618
1616
directories_to_expand = set()
1619
1617
items = self.parent_id_basename_to_file_id.iteritems(keys)
1620
1618
next_file_ids = set([item[1] for item in items])
1677
1675
# to filter out empty names because of non rich-root...
1678
1676
sections = bytes.split('\n')
1679
1677
kind, file_id = sections[0].split(': ')
1680
return (sections[2], intern(file_id), intern(sections[3]))
1678
return (sections[2], file_id, sections[3])
1682
1680
def _bytes_to_entry(self, bytes):
1683
1681
"""Deserialise a serialised entry."""
1705
1703
result.reference_revision = sections[4]
1707
1705
raise ValueError("Not a serialised entry %r" % bytes)
1708
result.file_id = intern(result.file_id)
1709
result.revision = intern(sections[3])
1706
result.revision = sections[3]
1710
1707
if result.parent_id == '':
1711
1708
result.parent_id = None
1712
1709
self._fileid_to_entry_cache[result.file_id] = result
1811
1808
deletes.add(file_id)
1813
new_key = StaticTuple(file_id,)
1810
new_key = (file_id,)
1814
1811
new_value = result._entry_to_bytes(entry)
1815
1812
# Update caches. It's worth doing this whether
1816
1813
# we're propagating the old caches or not.
1819
1816
if old_path is None:
1822
old_key = StaticTuple(file_id,)
1819
old_key = (file_id,)
1823
1820
if self.id2path(file_id) != old_path:
1824
1821
raise errors.InconsistentDelta(old_path, file_id,
1825
1822
"Entry was at wrong other path %r." %
1826
1823
self.id2path(file_id))
1827
1824
altered.add(file_id)
1828
id_to_entry_delta.append(StaticTuple(old_key, new_key, new_value))
1825
id_to_entry_delta.append((old_key, new_key, new_value))
1829
1826
if result.parent_id_basename_to_file_id is not None:
1830
1827
# parent_id, basename changes
1831
1828
if old_path is None:
1918
1915
raise errors.BzrError('Duplicate key in inventory: %r\n%r'
1919
1916
% (key, bytes))
1920
1917
info[key] = value
1921
revision_id = intern(info['revision_id'])
1922
root_id = intern(info['root_id'])
1923
search_key_name = intern(info.get('search_key_name', 'plain'))
1924
parent_id_basename_to_file_id = intern(info.get(
1925
'parent_id_basename_to_file_id', None))
1926
if not parent_id_basename_to_file_id.startswith('sha1:'):
1927
raise ValueError('parent_id_basename_to_file_id should be a sha1'
1928
' key not %r' % (parent_id_basename_to_file_id,))
1918
revision_id = info['revision_id']
1919
root_id = info['root_id']
1920
search_key_name = info.get('search_key_name', 'plain')
1921
parent_id_basename_to_file_id = info.get(
1922
'parent_id_basename_to_file_id', None)
1929
1923
id_to_entry = info['id_to_entry']
1930
if not id_to_entry.startswith('sha1:'):
1931
raise ValueError('id_to_entry should be a sha1'
1932
' key not %r' % (id_to_entry,))
1934
1925
result = CHKInventory(search_key_name)
1935
1926
result.revision_id = revision_id
1938
1929
result._search_key_name)
1939
1930
if parent_id_basename_to_file_id is not None:
1940
1931
result.parent_id_basename_to_file_id = chk_map.CHKMap(
1941
chk_store, StaticTuple(parent_id_basename_to_file_id,),
1932
chk_store, (parent_id_basename_to_file_id,),
1942
1933
search_key_func=search_key_func)
1944
1935
result.parent_id_basename_to_file_id = None
1946
result.id_to_entry = chk_map.CHKMap(chk_store,
1947
StaticTuple(id_to_entry,),
1937
result.id_to_entry = chk_map.CHKMap(chk_store, (id_to_entry,),
1948
1938
search_key_func=search_key_func)
1949
1939
if (result.revision_id,) != expected_revision_id:
1950
1940
raise ValueError("Mismatched revision id and expected: %r, %r" %
1972
1962
id_to_entry_dict = {}
1973
1963
parent_id_basename_dict = {}
1974
1964
for path, entry in inventory.iter_entries():
1975
key = StaticTuple(entry.file_id,).intern()
1976
id_to_entry_dict[key] = entry_to_bytes(entry)
1965
id_to_entry_dict[(entry.file_id,)] = entry_to_bytes(entry)
1977
1966
p_id_key = parent_id_basename_key(entry)
1978
1967
parent_id_basename_dict[p_id_key] = entry.file_id
2002
1991
parent_id = entry.parent_id
2005
return StaticTuple(parent_id, entry.name.encode('utf8')).intern()
1994
return parent_id, entry.name.encode('utf8')
2007
1996
def __getitem__(self, file_id):
2008
1997
"""map a single file_id -> InventoryEntry."""
2015
2004
return self._bytes_to_entry(
2016
self.id_to_entry.iteritems([StaticTuple(file_id,)]).next()[1])
2005
self.id_to_entry.iteritems([(file_id,)]).next()[1])
2017
2006
except StopIteration:
2018
2007
# really we're passing an inventory, not a tree...
2019
2008
raise errors.NoSuchId(self, file_id)
2032
2021
remaining.append(file_id)
2034
2023
result.append(entry)
2035
file_keys = [StaticTuple(f,).intern() for f in remaining]
2024
file_keys = [(f,) for f in remaining]
2036
2025
for file_key, value in self.id_to_entry.iteritems(file_keys):
2037
2026
entry = self._bytes_to_entry(value)
2038
2027
result.append(entry)
2043
2032
# Perhaps have an explicit 'contains' method on CHKMap ?
2044
2033
if self._fileid_to_entry_cache.get(file_id, None) is not None:
2047
self.id_to_entry.iteritems([StaticTuple(file_id,)]))) == 1
2035
return len(list(self.id_to_entry.iteritems([(file_id,)]))) == 1
2049
2037
def is_root(self, file_id):
2050
2038
return file_id == self.root_id
2179
2167
delta.append((old_path, new_path, file_id, entry))
2182
def path2id(self, relpath):
2170
def path2id(self, name):
2183
2171
"""See CommonInventory.path2id()."""
2184
2172
# TODO: perhaps support negative hits?
2185
result = self._path_to_fileid_cache.get(relpath, None)
2173
result = self._path_to_fileid_cache.get(name, None)
2186
2174
if result is not None:
2188
if isinstance(relpath, basestring):
2189
names = osutils.splitpath(relpath)
2176
if isinstance(name, basestring):
2177
names = osutils.splitpath(name)
2192
2180
current_id = self.root_id
2193
2181
if current_id is None:
2195
2183
parent_id_index = self.parent_id_basename_to_file_id
2197
2184
for basename in names:
2198
if cur_path is None:
2201
cur_path = cur_path + '/' + basename
2185
# TODO: Cache each path we figure out in this function.
2202
2186
basename_utf8 = basename.encode('utf8')
2203
file_id = self._path_to_fileid_cache.get(cur_path, None)
2187
key_filter = [(current_id, basename_utf8)]
2189
for (parent_id, name_utf8), file_id in parent_id_index.iteritems(
2190
key_filter=key_filter):
2191
if parent_id != current_id or name_utf8 != basename_utf8:
2192
raise errors.BzrError("corrupt inventory lookup! "
2193
"%r %r %r %r" % (parent_id, current_id, name_utf8,
2204
2195
if file_id is None:
2205
key_filter = [StaticTuple(current_id, basename_utf8)]
2206
items = parent_id_index.iteritems(key_filter)
2207
for (parent_id, name_utf8), file_id in items:
2208
if parent_id != current_id or name_utf8 != basename_utf8:
2209
raise errors.BzrError("corrupt inventory lookup! "
2210
"%r %r %r %r" % (parent_id, current_id, name_utf8,
2215
self._path_to_fileid_cache[cur_path] = file_id
2216
2197
current_id = file_id
2198
self._path_to_fileid_cache[name] = current_id
2217
2199
return current_id
2219
2201
def to_lines(self):
2224
2206
lines.append('search_key_name: %s\n' % (self._search_key_name,))
2225
2207
lines.append("root_id: %s\n" % self.root_id)
2226
2208
lines.append('parent_id_basename_to_file_id: %s\n' %
2227
(self.parent_id_basename_to_file_id.key()[0],))
2209
self.parent_id_basename_to_file_id.key())
2228
2210
lines.append("revision_id: %s\n" % self.revision_id)
2229
lines.append("id_to_entry: %s\n" % (self.id_to_entry.key()[0],))
2211
lines.append("id_to_entry: %s\n" % self.id_to_entry.key())
2231
2213
lines.append("revision_id: %s\n" % self.revision_id)
2232
2214
lines.append("root_id: %s\n" % self.root_id)
2233
2215
if self.parent_id_basename_to_file_id is not None:
2234
2216
lines.append('parent_id_basename_to_file_id: %s\n' %
2235
(self.parent_id_basename_to_file_id.key()[0],))
2236
lines.append("id_to_entry: %s\n" % (self.id_to_entry.key()[0],))
2217
self.parent_id_basename_to_file_id.key())
2218
lines.append("id_to_entry: %s\n" % self.id_to_entry.key())
2280
2262
parent_id_index = self._chk_inventory.parent_id_basename_to_file_id
2281
2263
child_keys = set()
2282
2264
for (parent_id, name_utf8), file_id in parent_id_index.iteritems(
2283
key_filter=[StaticTuple(self.file_id,)]):
2284
child_keys.add(StaticTuple(file_id,))
2265
key_filter=[(self.file_id,)]):
2266
child_keys.add((file_id,))
2286
2268
for file_id_key in child_keys:
2287
2269
entry = self._chk_inventory._fileid_to_entry_cache.get(