17
18
"""Inventories map files to their name in a revision."""
19
# TODO: Maybe store inventory_id in the file? Not really needed.
21
21
__copyright__ = "Copyright (C) 2005 Canonical Ltd."
22
22
__author__ = "Martin Pool <mbp@canonical.com>"
250
## TODO: Clear up handling of files in subdirectories; we probably
251
## do want to be able to just look them up by name but this
252
## probably means gradually walking down the path, looking up as we go.
249
254
## TODO: Make sure only canonical filenames are stored.
251
256
## TODO: Do something sensible about the possible collisions on
252
257
## case-losing filesystems. Perhaps we should just always forbid
253
258
## such collisions.
255
## TODO: No special cases for root, rather just give it a file id
256
## like everything else.
258
## TODO: Probably change XML serialization to use nesting
260
## _tree should probably just be stored as
261
## InventoryEntry._children on each directory.
260
263
def __init__(self):
261
264
"""Create or read an inventory.
264
267
from there. If the file is specified, read from that. If not,
265
268
the inventory is created empty.
267
self._root = InventoryEntry(None, '', kind='directory')
268
self._byid = {None: self._root}
272
# _tree is indexed by parent_id; at each level a map from name
273
# to ie. The None entry is the root.
274
self._tree = {None: {}}
271
277
def __iter__(self):
280
286
def iter_entries(self, parent_id=None):
281
287
"""Return (path, entry) pairs, in order by name."""
282
kids = self[parent_id].children.items()
288
kids = self._tree[parent_id].items()
284
290
for name, ie in kids:
308
def children(self, parent_id):
309
"""Return entries that are direct children of parent_id."""
310
return self._tree[parent_id]
314
# TODO: return all paths and entries
302
317
def __contains__(self, file_id):
303
318
"""True if this entry contains a file with given id.
323
338
return self._byid[file_id]
326
def get_child(self, parent_id, filename):
327
if parent_id == None:
328
return self._root.children.get(filename)
330
return self[parent_id].children.get(filename)
333
341
def add(self, entry):
334
342
"""Add entry to inventory.
336
344
To add a file to a branch ready to be committed, use Branch.add,
337
345
which calls this."""
338
if entry.file_id in self._byid:
346
if entry.file_id in self:
339
347
bailout("inventory already contains entry with id {%s}" % entry.file_id)
341
parent = self._byid[entry.parent_id]
342
if parent.kind != 'directory':
343
bailout("attempt to add under non-directory {%s}" % parent.file_id)
345
if parent.children.has_key(entry.name):
346
bailout("%s is already versioned" %
347
appendpath(self.id2path(parent.file_id), entry.name))
349
if entry.parent_id != None:
350
if entry.parent_id not in self:
351
bailout("parent_id %s of new entry not found in inventory"
354
if self._tree[entry.parent_id].has_key(entry.name):
355
bailout("%s is already versioned"
356
% appendpath(self.id2path(entry.parent_id), entry.name))
349
358
self._byid[entry.file_id] = entry
350
parent.children[entry.name] = entry
359
self._tree[entry.parent_id][entry.name] = entry
361
if entry.kind == 'directory':
362
self._tree[entry.file_id] = {}
353
365
def add_path(self, relpath, kind, file_id=None):
381
393
ie = self[file_id]
383
assert self[ie.parent_id].children[ie.name] == ie
395
assert self._tree[ie.parent_id][ie.name] == ie
385
397
# TODO: Test deleting all children; maybe hoist to a separate
386
398
# deltree method?
387
399
if ie.kind == 'directory':
388
for cie in ie.children.values():
400
for cie in self._tree[file_id].values():
389
401
del self[cie.file_id]
402
del self._tree[file_id]
392
404
del self._byid[file_id]
393
del self[ie.parent_id].children[ie.name]
405
del self._tree[ie.parent_id][ie.name]
396
408
def id_set(self):
478
490
if isinstance(name, types.StringTypes):
479
491
name = splitpath(name)
484
cie = parent.children[f]
496
cie = self._tree[parent_id][f]
485
497
assert cie.name == f
498
parent_id = cie.file_id
488
500
# or raise an error?
491
return parent.file_id
506
def get_child(self, parent_id, child_name):
507
return self._tree[parent_id].get(child_name)
494
510
def has_filename(self, names):