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():
93
100
# directories, etc etc.
95
102
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
96
'text_id', 'parent_id', 'children', ]
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
116
128
self.text_sha1 = None
117
129
self.text_size = None
119
130
self.file_id = file_id
158
def to_element(self):
159
"""Convert to XML element"""
160
from bzrlib.xml import Element
164
e.set('name', self.name)
165
e.set('file_id', self.file_id)
166
e.set('kind', self.kind)
168
if self.text_size != None:
169
e.set('text_size', '%d' % self.text_size)
171
for f in ['text_id', 'text_sha1']:
176
# to be conservative, we don't externalize the root pointers
177
# for now, leaving them as null in the xml form. in a future
178
# version it will be implied by nested elements.
179
if self.parent_id != ROOT_ID:
180
assert isinstance(self.parent_id, basestring)
181
e.set('parent_id', self.parent_id)
188
def from_element(cls, elt):
189
assert elt.tag == 'entry'
191
## original format inventories don't have a parent_id for
192
## nodes in the root directory, but it's cleaner to use one
194
parent_id = elt.get('parent_id')
195
if parent_id == None:
198
self = cls(elt.get('file_id'), elt.get('name'), elt.get('kind'), parent_id)
199
self.text_id = elt.get('text_id')
200
self.text_sha1 = elt.get('text_sha1')
202
## mutter("read inventoryentry: %r" % (elt.attrib))
204
v = elt.get('text_size')
205
self.text_size = v and int(v)
210
from_element = classmethod(from_element)
212
169
def __eq__(self, other):
213
170
if not isinstance(other, InventoryEntry):
214
171
return NotImplemented
219
176
and (self.text_size == other.text_size) \
220
177
and (self.text_id == other.text_id) \
221
178
and (self.parent_id == other.parent_id) \
222
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)
225
184
def __ne__(self, other):
267
226
>>> inv = Inventory()
268
227
>>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
228
InventoryEntry('123-123', 'hello.c', kind='file', parent_id='TREE_ROOT')
269
229
>>> inv['123-123'].name
283
243
>>> inv = Inventory('TREE_ROOT-12345678-12345678')
284
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')
286
247
def __init__(self, root_id=ROOT_ID):
287
248
"""Create or read an inventory.
370
331
>>> inv = Inventory()
371
332
>>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
333
InventoryEntry('123', 'foo.c', kind='file', parent_id='TREE_ROOT')
383
345
>>> inv = Inventory()
384
346
>>> inv.add(InventoryEntry('123123', 'hello.c', 'file', ROOT_ID))
347
InventoryEntry('123123', 'hello.c', kind='file', parent_id='TREE_ROOT')
385
348
>>> inv['123123'].name
405
368
"""Add entry to inventory.
407
370
To add a file to a branch ready to be committed, use Branch.add,
373
Returns the new entry object.
409
375
if entry.file_id in self._byid:
410
376
raise BzrError("inventory already contains entry with id {%s}" % entry.file_id)
424
390
self._byid[entry.file_id] = entry
425
391
parent.children[entry.name] = entry
428
395
def add_path(self, relpath, kind, file_id=None):
429
396
"""Add entry from a path.
431
The immediate parent must already be versioned"""
432
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
434
403
parts = bzrlib.osutils.splitpath(relpath)
435
404
if len(parts) == 0:
436
405
raise BzrError("cannot re-add root of inventory")
438
407
if file_id == None:
439
from bzrlib.branch import gen_file_id
440
408
file_id = gen_file_id(relpath)
442
410
parent_path = parts[:-1]
455
423
>>> inv = Inventory()
456
424
>>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
425
InventoryEntry('123', 'foo.c', kind='file', parent_id='TREE_ROOT')
459
428
>>> del inv['123']
475
444
del self[ie.parent_id].children[ie.name]
478
def to_element(self):
479
"""Convert to XML Element"""
480
from bzrlib.xml import Element
482
e = Element('inventory')
484
if self.root.file_id not in (None, ROOT_ID):
485
e.set('file_id', self.root.file_id)
486
for path, ie in self.iter_entries():
487
e.append(ie.to_element())
491
def from_element(cls, elt):
492
"""Construct from XML Element
494
>>> inv = Inventory()
495
>>> inv.add(InventoryEntry('foo.c-123981239', 'foo.c', 'file', ROOT_ID))
496
>>> elt = inv.to_element()
497
>>> inv2 = Inventory.from_element(elt)
501
# XXXX: doctest doesn't run this properly under python2.3
502
assert elt.tag == 'inventory'
503
root_id = elt.get('file_id') or ROOT_ID
506
ie = InventoryEntry.from_element(e)
507
if ie.parent_id == ROOT_ID:
508
ie.parent_id = root_id
512
from_element = classmethod(from_element)
515
447
def __eq__(self, other):
516
448
"""Compare two sets by comparing their contents.
522
454
>>> i1.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
455
InventoryEntry('123', 'foo', kind='file', parent_id='TREE_ROOT')
525
458
>>> i2.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
459
InventoryEntry('123', 'foo', kind='file', parent_id='TREE_ROOT')