27
27
# created, but it's not for now.
28
28
ROOT_ID = "TREE_ROOT"
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
37
from warnings import warn
49
from bzrlib.errors import (
40
from bzrlib import errors, osutils
41
from bzrlib.osutils import (pumpfile, quotefn, splitpath, joinpath,
42
pathjoin, sha_strings)
43
from bzrlib.errors import (NotVersionedError, InvalidEntryName,
44
BzrError, BzrCheckError, BinaryFile)
53
45
from bzrlib.trace import mutter
90
82
InventoryDirectory('123', 'src', parent_id='TREE_ROOT', revision=None)
91
83
>>> i.add(InventoryFile('2323', 'hello.c', parent_id='123'))
92
84
InventoryFile('2323', 'hello.c', parent_id='123', sha1=None, len=None)
93
>>> shouldbe = {0: '', 1: 'src', 2: 'src/hello.c'}
85
>>> shouldbe = {0: '', 1: 'src', 2: pathjoin('src','hello.c')}
94
86
>>> for ix, j in enumerate(i.iter_entries()):
95
87
... print (j[0] == shouldbe[ix], j[1])
97
(True, InventoryDirectory('TREE_ROOT', u'', parent_id=None, revision=None))
89
(True, InventoryDirectory('TREE_ROOT', '', parent_id=None, revision=None))
98
90
(True, InventoryDirectory('123', 'src', parent_id='TREE_ROOT', revision=None))
99
91
(True, InventoryFile('2323', 'hello.c', parent_id='123', sha1=None, len=None))
92
>>> i.add(InventoryFile('2323', 'bye.c', '123'))
93
Traceback (most recent call last):
95
BzrError: inventory already contains entry with id {2323}
100
96
>>> i.add(InventoryFile('2324', 'bye.c', '123'))
101
97
InventoryFile('2324', 'bye.c', parent_id='123', sha1=None, len=None)
102
98
>>> i.add(InventoryDirectory('2325', 'wibble', '123'))
251
247
def get_tar_item(self, root, dp, now, tree):
252
248
"""Get a tarfile item and a file stream for its content."""
253
item = tarfile.TarInfo(osutils.pathjoin(root, dp).encode('utf8'))
249
item = tarfile.TarInfo(pathjoin(root, dp).encode('utf8'))
254
250
# TODO: would be cool to actually set it to the timestamp of the
255
251
# revision it was last changed
286
282
assert isinstance(name, basestring), name
287
283
if '/' in name or '\\' in name:
288
raise errors.InvalidEntryName(name=name)
284
raise InvalidEntryName(name=name)
289
285
self.executable = False
290
286
self.revision = None
291
287
self.text_sha1 = None
292
288
self.text_size = None
293
289
self.file_id = file_id
294
assert isinstance(file_id, (str, None.__class__)), \
295
'bad type %r for %r' % (type(file_id), file_id)
297
291
self.text_id = text_id
298
292
self.parent_id = parent_id
318
312
This is a template method - implement _put_on_disk in subclasses.
320
fullpath = osutils.pathjoin(dest, dp)
314
fullpath = pathjoin(dest, dp)
321
315
self._put_on_disk(fullpath, tree)
322
316
# mutter(" export {%s} kind %s to %s", self.file_id,
323
317
# self.kind, fullpath)
522
514
self.parent_id = None
524
516
self.revision = None
525
symbol_versioning.warn('RootEntry is deprecated as of bzr 0.10.'
526
' Please use InventoryDirectory instead.',
527
DeprecationWarning, stacklevel=2)
517
warn('RootEntry is deprecated as of bzr 0.10. Please use '
518
'InventoryDirectory instead.',
519
DeprecationWarning, stacklevel=2)
529
521
def __eq__(self, other):
530
522
if not isinstance(other, RootEntry):
654
646
text_diff(to_label, to_text,
655
647
from_label, from_text, output_to)
656
except errors.BinaryFile:
658
650
label_pair = (to_label, from_label)
686
678
def _put_on_disk(self, fullpath, tree):
687
679
"""See InventoryEntry._put_on_disk."""
688
osutils.pumpfile(tree.get_file(self.file_id), file(fullpath, 'wb'))
680
pumpfile(tree.get_file(self.file_id), file(fullpath, 'wb'))
689
681
if tree.is_executable(self.file_id):
690
682
os.chmod(fullpath, 0755)
858
850
>>> inv = Inventory('TREE_ROOT-12345678-12345678')
859
851
>>> inv.add(InventoryFile('123-123', 'hello.c', ROOT_ID))
860
Traceback (most recent call last):
861
BzrError: parent_id {TREE_ROOT} not in inventory
862
>>> inv.add(InventoryFile('123-123', 'hello.c', 'TREE_ROOT-12345678-12345678'))
863
852
InventoryFile('123-123', 'hello.c', parent_id='TREE_ROOT-12345678-12345678', sha1=None, len=None)
865
854
def __init__(self, root_id=ROOT_ID, revision_id=None):
872
861
The inventory is created with a default root directory, with
864
# We are letting Branch.create() create a unique inventory
865
# root id. Rather than generating a random one here.
867
# root_id = bzrlib.branch.gen_file_id('TREE_ROOT')
875
868
if root_id is not None:
876
assert root_id.__class__ == str
877
self._set_root(InventoryDirectory(root_id, u'', None))
869
self._set_root(InventoryDirectory(root_id, '', None))
873
# FIXME: this isn't ever used, changing it to self.revision may break
874
# things. TODO make everything use self.revision_id
881
875
self.revision_id = revision_id
883
877
def _set_root(self, ie):
904
898
def iter_entries(self, from_dir=None):
905
899
"""Return (path, entry) pairs, in order by name."""
906
900
if from_dir is None:
907
if self.root is None:
909
902
from_dir = self.root
910
903
yield '', self.root
911
904
elif isinstance(from_dir, basestring):
945
938
# if we finished all children, pop it off the stack
948
def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None):
941
def iter_entries_by_dir(self, from_dir=None):
949
942
"""Iterate over the entries in a directory first order.
951
944
This returns all entries for a directory before returning
956
949
:return: This yields (path, entry) pairs
958
if specific_file_ids:
959
specific_file_ids = [osutils.safe_file_id(fid)
960
for fid in specific_file_ids]
961
951
# TODO? Perhaps this should return the from_dir so that the root is
962
952
# yielded? or maybe an option?
963
953
if from_dir is None:
964
if self.root is None:
966
# Optimize a common case
967
if specific_file_ids is not None and len(specific_file_ids) == 1:
968
file_id = list(specific_file_ids)[0]
970
yield self.id2path(file_id), self[file_id]
972
955
from_dir = self.root
973
if (specific_file_ids is None or
974
self.root.file_id in specific_file_ids):
976
957
elif isinstance(from_dir, basestring):
977
958
from_dir = self._byid[from_dir]
979
if specific_file_ids is not None:
981
def add_ancestors(file_id):
982
if file_id not in self:
984
parent_id = self[file_id].parent_id
985
if parent_id is None:
987
if parent_id not in parents:
988
parents.add(parent_id)
989
add_ancestors(parent_id)
990
for file_id in specific_file_ids:
991
add_ancestors(file_id)
995
960
stack = [(u'', from_dir)]
1002
967
child_relpath = cur_relpath + child_name
1004
if (specific_file_ids is None or
1005
child_ie.file_id in specific_file_ids):
1006
yield child_relpath, child_ie
969
yield child_relpath, child_ie
1008
971
if child_ie.kind == 'directory':
1009
if parents is None or child_ie.file_id in parents:
1010
child_dirs.append((child_relpath+'/', child_ie))
972
child_dirs.append((child_relpath+'/', child_ie))
1011
973
stack.extend(reversed(child_dirs))
1013
975
def entries(self):
1020
982
kids = dir_ie.children.items()
1022
984
for name, ie in kids:
1023
child_path = osutils.pathjoin(dir_path, name)
985
child_path = pathjoin(dir_path, name)
1024
986
accum.append((child_path, ie))
1025
987
if ie.kind == 'directory':
1026
988
descend(ie, child_path)
1041
1003
for name, child_ie in kids:
1042
child_path = osutils.pathjoin(parent_path, name)
1004
child_path = pathjoin(parent_path, name)
1043
1005
descend(child_ie, child_path)
1044
1006
descend(self.root, u'')
1067
1028
>>> inv['123123'].name
1070
file_id = osutils.safe_file_id(file_id)
1072
1032
return self._byid[file_id]
1073
1033
except KeyError:
1074
# really we're passing an inventory, not a tree...
1075
raise errors.NoSuchId(self, file_id)
1035
raise BzrError("can't look up file_id None")
1037
raise BzrError("file_id {%s} not in inventory" % file_id)
1077
1039
def get_file_kind(self, file_id):
1078
file_id = osutils.safe_file_id(file_id)
1079
1040
return self._byid[file_id].kind
1081
1042
def get_child(self, parent_id, filename):
1082
parent_id = osutils.safe_file_id(parent_id)
1083
1043
return self[parent_id].children.get(filename)
1085
1045
def add(self, entry):
1091
1051
Returns the new entry object.
1093
1053
if entry.file_id in self._byid:
1094
raise errors.DuplicateFileId(entry.file_id,
1095
self._byid[entry.file_id])
1054
raise BzrError("inventory already contains entry with id {%s}" % entry.file_id)
1097
1056
if entry.parent_id is None:
1098
1057
assert self.root is None and len(self._byid) == 0
1099
1058
self._set_root(entry)
1060
if entry.parent_id == ROOT_ID:
1061
assert self.root is not None, self
1062
entry.parent_id = self.root.file_id
1102
1065
parent = self._byid[entry.parent_id]
1103
1066
except KeyError:
1106
1069
if entry.name in parent.children:
1107
1070
raise BzrError("%s is already versioned" %
1108
osutils.pathjoin(self.id2path(parent.file_id), entry.name))
1071
pathjoin(self.id2path(parent.file_id), entry.name))
1110
1073
self._byid[entry.file_id] = entry
1111
1074
parent.children[entry.name] = entry
1123
1086
if len(parts) == 0:
1124
1087
if file_id is None:
1125
file_id = generate_ids.gen_root_id()
1127
file_id = osutils.safe_file_id(file_id)
1088
file_id = bzrlib.workingtree.gen_root_id()
1128
1089
self.root = InventoryDirectory(file_id, '', None)
1129
1090
self._byid = {self.root.file_id: self.root}
1132
1093
parent_path = parts[:-1]
1133
1094
parent_id = self.path2id(parent_path)
1134
1095
if parent_id is None:
1135
raise errors.NotVersionedError(path=parent_path)
1096
raise NotVersionedError(path=parent_path)
1136
1097
ie = make_entry(kind, parts[-1], parent_id, file_id)
1137
1098
return self.add(ie)
1188
1148
def _iter_file_id_parents(self, file_id):
1189
1149
"""Yield the parents of file_id up to the root."""
1190
file_id = osutils.safe_file_id(file_id)
1191
1150
while file_id is not None:
1193
1152
ie = self._byid[file_id]
1204
1163
is equal to the depth of the file in the tree, counting the
1205
1164
root directory as depth 1.
1207
file_id = osutils.safe_file_id(file_id)
1209
1167
for parent in self._iter_file_id_parents(file_id):
1210
1168
p.insert(0, parent.file_id)
1219
1177
>>> print i.id2path('foo-id')
1222
file_id = osutils.safe_file_id(file_id)
1223
1180
# get all names, skipping root
1224
1181
return '/'.join(reversed(
1225
1182
[parent.name for parent in
1237
1194
Returns None IFF the path is not found.
1239
if isinstance(name, basestring):
1240
name = osutils.splitpath(name)
1196
if isinstance(name, types.StringTypes):
1197
name = splitpath(name)
1242
1199
# mutter("lookup path %r" % name)
1244
1201
parent = self.root
1249
children = getattr(parent, 'children', None)
1250
if children is None:
1204
cie = parent.children[f]
1253
1205
assert cie.name == f
1254
1206
assert cie.parent_id == parent.file_id
1263
1215
return bool(self.path2id(names))
1265
1217
def has_id(self, file_id):
1266
file_id = osutils.safe_file_id(file_id)
1267
1218
return (file_id in self._byid)
1269
1220
def remove_recursive_id(self, file_id):
1291
1241
This can change either the name, or the parent, or both.
1293
This does not move the working file.
1295
file_id = osutils.safe_file_id(file_id)
1243
This does not move the working file."""
1296
1244
if not is_valid_name(new_name):
1297
1245
raise BzrError("not an acceptable filename: %r" % new_name)
1316
1264
file_ie.name = new_name
1317
1265
file_ie.parent_id = new_parent_id
1319
def is_root(self, file_id):
1320
file_id = osutils.safe_file_id(file_id)
1321
return self.root is not None and file_id == self.root.file_id
1325
'directory':InventoryDirectory,
1326
'file':InventoryFile,
1327
'symlink':InventoryLink,
1330
1268
def make_entry(kind, name, parent_id, file_id=None):
1331
1269
"""Create an inventory entry.
1336
1274
:param file_id: the file_id to use. if None, one will be created.
1338
1276
if file_id is None:
1339
file_id = generate_ids.gen_file_id(name)
1341
file_id = osutils.safe_file_id(file_id)
1277
file_id = bzrlib.workingtree.gen_file_id(name)
1343
#------- This has been copied to bzrlib.dirstate.DirState.add, please
1344
# keep them synchronised.
1345
# we dont import normalized_filename directly because we want to be
1346
# able to change the implementation at runtime for tests.
1347
1279
norm_name, can_access = osutils.normalized_filename(name)
1348
1280
if norm_name != name:
1353
1285
# if the error was raised with the full path
1354
1286
raise errors.InvalidNormalization(name)
1357
factory = entry_factory[kind]
1288
if kind == 'directory':
1289
return InventoryDirectory(file_id, name, parent_id)
1290
elif kind == 'file':
1291
return InventoryFile(file_id, name, parent_id)
1292
elif kind == 'symlink':
1293
return InventoryLink(file_id, name, parent_id)
1359
1295
raise BzrError("unknown kind %r" % kind)
1360
return factory(file_id, name, parent_id)
1363
1298
_NAME_RE = None