28
28
from bzrlib.osutils import uuid, quotefn, splitpath, joinpath, appendpath
29
29
from bzrlib.trace import mutter
30
from bzrlib.errors import NotVersionedError
31
33
class InventoryEntry(object):
32
34
"""Description of a versioned file.
55
57
>>> i.add(InventoryEntry('123', 'src', 'directory', ROOT_ID))
58
InventoryEntry('123', 'src', kind='directory', parent_id='TREE_ROOT')
56
59
>>> i.add(InventoryEntry('2323', 'hello.c', 'file', parent_id='123'))
60
InventoryEntry('2323', 'hello.c', kind='file', parent_id='123')
57
61
>>> for j in i.iter_entries():
65
69
BzrError: inventory already contains entry with id {2323}
66
70
>>> i.add(InventoryEntry('2324', 'bye.c', 'file', '123'))
71
InventoryEntry('2324', 'bye.c', kind='file', parent_id='123')
67
72
>>> i.add(InventoryEntry('2325', 'wibble', 'directory', '123'))
73
InventoryEntry('2325', 'wibble', kind='directory', parent_id='123')
68
74
>>> i.path2id('src/wibble')
72
78
>>> i.add(InventoryEntry('2326', 'wibble.c', 'file', '2325'))
79
InventoryEntry('2326', 'wibble.c', kind='file', parent_id='2325')
74
81
InventoryEntry('2326', 'wibble.c', kind='file', parent_id='2325')
75
82
>>> for j in i.iter_entries():
92
99
# TODO: split InventoryEntry into subclasses for files,
93
100
# directories, etc etc.
102
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
103
'text_id', 'parent_id', 'children',
104
'text_version', 'entry_version', ]
98
107
def __init__(self, file_id, name, kind, parent_id, text_id=None):
99
108
"""Create an InventoryEntry
110
119
Traceback (most recent call last):
111
120
BzrCheckError: InventoryEntry name 'src/hello.c' is invalid
122
assert isinstance(name, basestring), name
113
123
if '/' in name or '\\' in name:
114
124
raise BzrCheckError('InventoryEntry name %r is invalid' % name)
126
self.text_version = None
127
self.entry_version = None
128
self.text_sha1 = None
129
self.text_size = None
116
130
self.file_id = file_id
155
def to_element(self):
156
"""Convert to XML element"""
157
from bzrlib.xml import Element
161
e.set('name', self.name)
162
e.set('file_id', self.file_id)
163
e.set('kind', self.kind)
165
if self.text_size != None:
166
e.set('text_size', '%d' % self.text_size)
168
for f in ['text_id', 'text_sha1']:
173
# to be conservative, we don't externalize the root pointers
174
# for now, leaving them as null in the xml form. in a future
175
# version it will be implied by nested elements.
176
if self.parent_id != ROOT_ID:
177
assert isinstance(self.parent_id, basestring)
178
e.set('parent_id', self.parent_id)
185
def from_element(cls, elt):
186
assert elt.tag == 'entry'
188
## original format inventories don't have a parent_id for
189
## nodes in the root directory, but it's cleaner to use one
191
parent_id = elt.get('parent_id')
192
if parent_id == None:
195
self = cls(elt.get('file_id'), elt.get('name'), elt.get('kind'), parent_id)
196
self.text_id = elt.get('text_id')
197
self.text_sha1 = elt.get('text_sha1')
199
## mutter("read inventoryentry: %r" % (elt.attrib))
201
v = elt.get('text_size')
202
self.text_size = v and int(v)
207
from_element = classmethod(from_element)
209
169
def __eq__(self, other):
210
170
if not isinstance(other, InventoryEntry):
211
171
return NotImplemented
216
176
and (self.text_size == other.text_size) \
217
177
and (self.text_id == other.text_id) \
218
178
and (self.parent_id == other.parent_id) \
219
and (self.kind == other.kind)
179
and (self.kind == other.kind) \
180
and (self.text_version == other.text_version) \
181
and (self.entry_version == other.entry_version)
222
184
def __ne__(self, other):
264
226
>>> inv = Inventory()
265
227
>>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
228
InventoryEntry('123-123', 'hello.c', kind='file', parent_id='TREE_ROOT')
266
229
>>> inv['123-123'].name
280
243
>>> inv = Inventory('TREE_ROOT-12345678-12345678')
281
244
>>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
245
InventoryEntry('123-123', 'hello.c', kind='file', parent_id='TREE_ROOT-12345678-12345678')
283
247
def __init__(self, root_id=ROOT_ID):
284
248
"""Create or read an inventory.
367
331
>>> inv = Inventory()
368
332
>>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
333
InventoryEntry('123', 'foo.c', kind='file', parent_id='TREE_ROOT')
380
345
>>> inv = Inventory()
381
346
>>> inv.add(InventoryEntry('123123', 'hello.c', 'file', ROOT_ID))
347
InventoryEntry('123123', 'hello.c', kind='file', parent_id='TREE_ROOT')
382
348
>>> inv['123123'].name
402
368
"""Add entry to inventory.
404
370
To add a file to a branch ready to be committed, use Branch.add,
373
Returns the new entry object.
406
375
if entry.file_id in self._byid:
407
376
raise BzrError("inventory already contains entry with id {%s}" % entry.file_id)
421
390
self._byid[entry.file_id] = entry
422
391
parent.children[entry.name] = entry
425
395
def add_path(self, relpath, kind, file_id=None):
426
396
"""Add entry from a path.
428
The immediate parent must already be versioned"""
429
from bzrlib.errors import NotVersionedError
398
The immediate parent must already be versioned.
400
Returns the new entry object."""
401
from bzrlib.branch import gen_file_id
431
403
parts = bzrlib.osutils.splitpath(relpath)
432
404
if len(parts) == 0:
433
405
raise BzrError("cannot re-add root of inventory")
435
407
if file_id == None:
436
from bzrlib.branch import gen_file_id
437
408
file_id = gen_file_id(relpath)
439
410
parent_path = parts[:-1]
452
423
>>> inv = Inventory()
453
424
>>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
425
InventoryEntry('123', 'foo.c', kind='file', parent_id='TREE_ROOT')
456
428
>>> del inv['123']
472
444
del self[ie.parent_id].children[ie.name]
475
def to_element(self):
476
"""Convert to XML Element"""
477
from bzrlib.xml import Element
479
e = Element('inventory')
481
if self.root.file_id not in (None, ROOT_ID):
482
e.set('file_id', self.root.file_id)
483
for path, ie in self.iter_entries():
484
e.append(ie.to_element())
488
def from_element(cls, elt):
489
"""Construct from XML Element
491
>>> inv = Inventory()
492
>>> inv.add(InventoryEntry('foo.c-123981239', 'foo.c', 'file', ROOT_ID))
493
>>> elt = inv.to_element()
494
>>> inv2 = Inventory.from_element(elt)
498
# XXXX: doctest doesn't run this properly under python2.3
499
assert elt.tag == 'inventory'
500
root_id = elt.get('file_id') or ROOT_ID
503
ie = InventoryEntry.from_element(e)
504
if ie.parent_id == ROOT_ID:
505
ie.parent_id = root_id
509
from_element = classmethod(from_element)
512
447
def __eq__(self, other):
513
448
"""Compare two sets by comparing their contents.
519
454
>>> i1.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
455
InventoryEntry('123', 'foo', kind='file', parent_id='TREE_ROOT')
522
458
>>> i2.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
459
InventoryEntry('123', 'foo', kind='file', parent_id='TREE_ROOT')