78
78
>>> i.add(InventoryDirectory('123', 'src', ROOT_ID))
79
79
InventoryDirectory('123', 'src', parent_id='TREE_ROOT')
80
>>> i.add(InventoryEntry('2323', 'hello.c', 'file', parent_id='123'))
81
InventoryEntry('2323', 'hello.c', kind='file', parent_id='123')
80
>>> i.add(InventoryFile('2323', 'hello.c', parent_id='123'))
81
InventoryFile('2323', 'hello.c', parent_id='123')
82
82
>>> for j in i.iter_entries():
85
85
('src', InventoryDirectory('123', 'src', parent_id='TREE_ROOT'))
86
('src/hello.c', InventoryEntry('2323', 'hello.c', kind='file', parent_id='123'))
87
>>> i.add(InventoryEntry('2323', 'bye.c', 'file', '123'))
86
('src/hello.c', InventoryFile('2323', 'hello.c', parent_id='123'))
87
>>> i.add(InventoryFile('2323', 'bye.c', '123'))
88
88
Traceback (most recent call last):
90
90
BzrError: inventory already contains entry with id {2323}
91
>>> i.add(InventoryEntry('2324', 'bye.c', 'file', '123'))
92
InventoryEntry('2324', 'bye.c', kind='file', parent_id='123')
91
>>> i.add(InventoryFile('2324', 'bye.c', '123'))
92
InventoryFile('2324', 'bye.c', parent_id='123')
93
93
>>> i.add(InventoryDirectory('2325', 'wibble', '123'))
94
94
InventoryDirectory('2325', 'wibble', parent_id='123')
95
95
>>> i.path2id('src/wibble')
99
>>> i.add(InventoryEntry('2326', 'wibble.c', 'file', '2325'))
100
InventoryEntry('2326', 'wibble.c', kind='file', parent_id='2325')
99
>>> i.add(InventoryFile('2326', 'wibble.c', '2325'))
100
InventoryFile('2326', 'wibble.c', parent_id='2325')
102
InventoryEntry('2326', 'wibble.c', kind='file', parent_id='2325')
102
InventoryFile('2326', 'wibble.c', parent_id='2325')
103
103
>>> for path, entry in i.iter_entries():
104
104
... print path.replace('\\\\', '/') # for win32 os.sep
105
105
... assert i.path2id(path)
284
274
def _put_on_disk(self, fullpath, tree):
285
275
"""Put this entry onto disk at fullpath, from tree tree."""
286
if self.kind == 'file':
287
pumpfile(tree.get_file(self.file_id), file(fullpath, 'wb'))
288
if tree.is_executable(self.file_id):
289
os.chmod(fullpath, 0755)
290
elif self.kind == 'symlink':
276
if self.kind == 'symlink':
292
278
os.symlink(self.symlink_target, fullpath)
293
279
except OSError,e:
319
305
def _check(self, checker, rev_id, tree):
320
306
"""Check this inventory entry for kind specific errors."""
321
if self.kind == 'file':
322
revision = self.revision
323
t = (self.file_id, revision)
324
if t in checker.checked_texts:
325
prev_sha = checker.checked_texts[t]
326
if prev_sha != self.text_sha1:
327
raise BzrCheckError('mismatched sha1 on {%s} in {%s}' %
328
(self.file_id, rev_id))
330
checker.repeated_text_cnt += 1
332
mutter('check version {%s} of {%s}', rev_id, self.file_id)
333
file_lines = tree.get_file_lines(self.file_id)
334
checker.checked_text_cnt += 1
335
if self.text_size != sum(map(len, file_lines)):
336
raise BzrCheckError('text {%s} wrong size' % self.text_id)
337
if self.text_sha1 != sha_strings(file_lines):
338
raise BzrCheckError('text {%s} wrong sha1' % self.text_id)
339
checker.checked_texts[t] = self.text_sha1
340
elif self.kind == 'symlink':
307
if self.kind == 'symlink':
341
308
if self.text_sha1 != None or self.text_size != None or self.text_id != None:
342
309
raise BzrCheckError('symlink {%s} has text in revision {%s}'
343
310
% (self.file_id, rev_id))
353
320
other = InventoryEntry(self.file_id, self.name, self.kind,
355
other.executable = self.executable
356
other.text_id = self.text_id
357
other.text_sha1 = self.text_sha1
358
other.text_size = self.text_size
359
322
other.symlink_target = self.symlink_target
360
323
other.revision = self.revision
361
324
# note that children are *not* copied; they're pulled across when
515
class InventoryFile(InventoryEntry):
516
"""A file in an inventory."""
518
def _check(self, checker, rev_id, tree):
519
"""See InventoryEntry._check"""
520
revision = self.revision
521
t = (self.file_id, revision)
522
if t in checker.checked_texts:
523
prev_sha = checker.checked_texts[t]
524
if prev_sha != self.text_sha1:
525
raise BzrCheckError('mismatched sha1 on {%s} in {%s}' %
526
(self.file_id, rev_id))
528
checker.repeated_text_cnt += 1
530
mutter('check version {%s} of {%s}', rev_id, self.file_id)
531
file_lines = tree.get_file_lines(self.file_id)
532
checker.checked_text_cnt += 1
533
if self.text_size != sum(map(len, file_lines)):
534
raise BzrCheckError('text {%s} wrong size' % self.text_id)
535
if self.text_sha1 != sha_strings(file_lines):
536
raise BzrCheckError('text {%s} wrong sha1' % self.text_id)
537
checker.checked_texts[t] = self.text_sha1
540
other = InventoryFile(self.file_id, self.name, self.parent_id)
541
other.executable = self.executable
542
other.text_id = self.text_id
543
other.text_sha1 = self.text_sha1
544
other.text_size = self.text_size
545
other.revision = self.revision
548
def __init__(self, file_id, name, parent_id):
549
super(InventoryFile, self).__init__(file_id, name, 'file',
552
def kind_character(self):
553
"""See InventoryEntry.kind_character."""
556
def __new__(cls, file_id, name, parent_id):
557
"""Only present until the InventoryEntry.__new__ can go away."""
558
result = object.__new__(InventoryFile, file_id, name, 'directory',
560
# type.__call__ is strange, it doesn't __init__ when the returned type
562
#result.__init__(file_id, name, 'directory', parent_id)
565
def _put_in_tar(self, item, tree):
566
"""See InventoryEntry._put_in_tar."""
567
item.type = tarfile.REGTYPE
568
fileobj = tree.get_file(self.file_id)
569
item.size = self.text_size
570
if tree.is_executable(self.file_id):
576
def _put_on_disk(self, fullpath, tree):
577
"""See InventoryEntry._put_on_disk."""
578
pumpfile(tree.get_file(self.file_id), file(fullpath, 'wb'))
579
if tree.is_executable(self.file_id):
580
os.chmod(fullpath, 0755)
583
return ("%s(%r, %r, parent_id=%r)"
584
% (self.__class__.__name__,
552
590
class Inventory(object):
553
591
"""Inventory of versioned files in a tree.