197
194
Note that textual data includes binary content.
199
if self.kind =='file':
204
def __init__(self, file_id, name, kind, parent_id, text_id=None):
198
def __init__(self, file_id, name, parent_id, text_id=None):
205
199
"""Create an InventoryEntry
207
201
The filename must be a single component, relative to the
208
202
parent directory; it cannot be a whole path or relative name.
210
>>> e = InventoryEntry('123', 'hello.c', 'file', ROOT_ID)
204
>>> e = InventoryFile('123', 'hello.c', ROOT_ID)
215
>>> e = InventoryEntry('123', 'src/hello.c', 'file', ROOT_ID)
209
>>> e = InventoryFile('123', 'src/hello.c', ROOT_ID)
216
210
Traceback (most recent call last):
217
211
BzrCheckError: InventoryEntry name 'src/hello.c' is invalid
226
220
self.text_size = None
227
221
self.file_id = file_id
230
223
self.text_id = text_id
231
224
self.parent_id = parent_id
232
225
self.symlink_target = None
233
if kind not in ('directory', 'file', 'symlink'):
234
raise BzrError("unhandled entry kind %r" % kind)
236
227
def kind_character(self):
237
228
"""Return a short kind indicator useful for appending to names."""
242
233
known_kinds = ('file', 'directory', 'symlink', 'root_directory')
244
def __new__(cls, file_id, name, kind, parent_id, text_id=None):
245
"""Factory method to return the appropriate concrete class."""
246
return object.__new__(InventoryEntry, file_id, name, kind, parent_id,
249
235
def _put_in_tar(self, item, tree):
250
236
"""populate item for stashing in a tar, and return the content stream.
252
238
If no content is available, return None.
254
if self.kind == 'symlink':
255
iterm.type = tarfile.SYMTYPE
259
item.linkname = self.symlink_target
261
raise BzrError("don't know how to export {%s} of kind %r" %
262
(self.file_id, self.kind))
240
raise BzrError("don't know how to export {%s} of kind %r" %
241
(self.file_id, self.kind))
265
243
def put_on_disk(self, dest, dp, tree):
266
244
"""Create a representation of self on disk in the prefix dest.
274
252
def _put_on_disk(self, fullpath, tree):
275
253
"""Put this entry onto disk at fullpath, from tree tree."""
276
if self.kind == 'symlink':
278
os.symlink(self.symlink_target, fullpath)
280
raise BzrError("Failed to create symlink %r -> %r, error: %s" % (fullpath, self.symlink_target, e))
282
raise BzrError("don't know how to export {%s} of kind %r" % (self.file_id, self.kind))
254
raise BzrError("don't know how to export {%s} of kind %r" % (self.file_id, self.kind))
284
256
def sorted_children(self):
285
257
l = self.children.items()
305
277
def _check(self, checker, rev_id, tree):
306
278
"""Check this inventory entry for kind specific errors."""
307
if self.kind == 'symlink':
308
if self.text_sha1 != None or self.text_size != None or self.text_id != None:
309
raise BzrCheckError('symlink {%s} has text in revision {%s}'
310
% (self.file_id, rev_id))
311
if self.symlink_target == None:
312
raise BzrCheckError('symlink {%s} has no target in revision {%s}'
313
% (self.file_id, rev_id))
315
raise BzrCheckError('unknown entry kind %r in revision {%s}' %
279
raise BzrCheckError('unknown entry kind %r in revision {%s}' %
320
other = InventoryEntry(self.file_id, self.name, self.kind,
322
other.symlink_target = self.symlink_target
323
other.revision = self.revision
324
# note that children are *not* copied; they're pulled across when
284
"""Clone this inventory entry."""
285
raise NotImplementedError
328
287
def _get_snapshot_change(self, previous_entries):
329
288
if len(previous_entries) > 1:
334
293
return 'modified/renamed/reparented'
336
295
def __repr__(self):
337
return ("%s(%r, %r, kind=%r, parent_id=%r)"
296
return ("%s(%r, %r, parent_id=%r)"
338
297
% (self.__class__.__name__,
344
302
def snapshot(self, revision, path, previous_entries, work_tree,
445
403
self.parent_id = None
448
def __new__(cls, file_id):
449
"""Only present until the InventoryEntry.__new__ can go away."""
450
return object.__new__(RootEntry, file_id)
452
406
def __eq__(self, other):
453
407
if not isinstance(other, RootEntry):
454
408
return NotImplemented
476
430
def __init__(self, file_id, name, parent_id):
477
super(InventoryDirectory, self).__init__(file_id, name, 'directory',
431
super(InventoryDirectory, self).__init__(file_id, name, parent_id)
479
432
self.children = {}
433
self.kind = 'directory'
481
435
def kind_character(self):
482
436
"""See InventoryEntry.kind_character."""
485
def __new__(cls, file_id, name, parent_id):
486
"""Only present until the InventoryEntry.__new__ can go away."""
487
result = object.__new__(InventoryDirectory, file_id, name, 'directory',
489
# type.__call__ is strange, it doesn't __init__ when the returned type
491
#result.__init__(file_id, name, 'directory', parent_id)
494
439
def _put_in_tar(self, item, tree):
495
440
"""See InventoryEntry._put_in_tar."""
496
441
item.type = tarfile.DIRTYPE
504
449
"""See InventoryEntry._put_on_disk."""
505
450
os.mkdir(fullpath)
508
return ("%s(%r, %r, parent_id=%r)"
509
% (self.__class__.__name__,
515
453
class InventoryFile(InventoryEntry):
516
454
"""A file in an inventory."""
545
483
other.revision = self.revision
487
"""See InventoryEntry.has_text."""
548
490
def __init__(self, file_id, name, parent_id):
549
super(InventoryFile, self).__init__(file_id, name, 'file',
491
super(InventoryFile, self).__init__(file_id, name, parent_id)
552
494
def kind_character(self):
553
495
"""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
498
def _put_in_tar(self, item, tree):
566
499
"""See InventoryEntry._put_in_tar."""
567
500
item.type = tarfile.REGTYPE
579
512
if tree.is_executable(self.file_id):
580
513
os.chmod(fullpath, 0755)
583
return ("%s(%r, %r, parent_id=%r)"
584
% (self.__class__.__name__,
516
class InventoryLink(InventoryEntry):
517
"""A file in an inventory."""
519
def _check(self, checker, rev_id, tree):
520
"""See InventoryEntry._check"""
521
if self.text_sha1 != None or self.text_size != None or self.text_id != None:
522
raise BzrCheckError('symlink {%s} has text in revision {%s}'
523
% (self.file_id, rev_id))
524
if self.symlink_target == None:
525
raise BzrCheckError('symlink {%s} has no target in revision {%s}'
526
% (self.file_id, rev_id))
529
other = InventoryLink(self.file_id, self.name, self.parent_id)
530
other.symlink_target = self.symlink_target
531
other.revision = self.revision
534
def __init__(self, file_id, name, parent_id):
535
super(InventoryLink, self).__init__(file_id, name, parent_id)
536
self.kind = 'symlink'
538
def kind_character(self):
539
"""See InventoryEntry.kind_character."""
542
def _put_in_tar(self, item, tree):
543
"""See InventoryEntry._put_in_tar."""
544
iterm.type = tarfile.SYMTYPE
548
item.linkname = self.symlink_target
551
def _put_on_disk(self, fullpath, tree):
552
"""See InventoryEntry._put_on_disk."""
554
os.symlink(self.symlink_target, fullpath)
556
raise BzrError("Failed to create symlink %r -> %r, error: %s" % (fullpath, self.symlink_target, e))
590
559
class Inventory(object):
605
574
inserted, other than through the Inventory API.
607
576
>>> inv = Inventory()
608
>>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
609
InventoryEntry('123-123', 'hello.c', kind='file', parent_id='TREE_ROOT')
577
>>> inv.add(InventoryFile('123-123', 'hello.c', ROOT_ID))
578
InventoryFile('123-123', 'hello.c', parent_id='TREE_ROOT')
610
579
>>> inv['123-123'].name
622
591
>>> [x[0] for x in inv.iter_entries()]
624
593
>>> inv = Inventory('TREE_ROOT-12345678-12345678')
625
>>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
626
InventoryEntry('123-123', 'hello.c', kind='file', parent_id='TREE_ROOT-12345678-12345678')
594
>>> inv.add(InventoryFile('123-123', 'hello.c', ROOT_ID))
595
InventoryFile('123-123', 'hello.c', parent_id='TREE_ROOT-12345678-12345678')
628
597
def __init__(self, root_id=ROOT_ID):
629
598
"""Create or read an inventory.
721
690
"""True if this entry contains a file with given id.
723
692
>>> inv = Inventory()
724
>>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
725
InventoryEntry('123', 'foo.c', kind='file', parent_id='TREE_ROOT')
693
>>> inv.add(InventoryFile('123', 'foo.c', ROOT_ID))
694
InventoryFile('123', 'foo.c', parent_id='TREE_ROOT')
735
704
"""Return the entry for given file_id.
737
706
>>> inv = Inventory()
738
>>> inv.add(InventoryEntry('123123', 'hello.c', 'file', ROOT_ID))
739
InventoryEntry('123123', 'hello.c', kind='file', parent_id='TREE_ROOT')
707
>>> inv.add(InventoryFile('123123', 'hello.c', ROOT_ID))
708
InventoryFile('123123', 'hello.c', parent_id='TREE_ROOT')
740
709
>>> inv['123123'].name
808
777
ie = InventoryDirectory(file_id, parts[-1], parent_id)
809
778
elif kind == 'file':
810
779
ie = InventoryFile(file_id, parts[-1], parent_id)
780
elif kind == 'symlink':
781
ie = InventoryLink(file_id, parts[-1], parent_id)
812
ie = InventoryEntry(file_id, parts[-1],
813
kind=kind, parent_id=parent_id)
783
raise BzrError("unknown kind %r" % kind)
814
784
return self.add(ie)
818
788
"""Remove entry by id.
820
790
>>> inv = Inventory()
821
>>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
822
InventoryEntry('123', 'foo.c', kind='file', parent_id='TREE_ROOT')
791
>>> inv.add(InventoryFile('123', 'foo.c', ROOT_ID))
792
InventoryFile('123', 'foo.c', parent_id='TREE_ROOT')
825
795
>>> del inv['123']
848
818
>>> i2 = Inventory()
851
>>> i1.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
852
InventoryEntry('123', 'foo', kind='file', parent_id='TREE_ROOT')
821
>>> i1.add(InventoryFile('123', 'foo', ROOT_ID))
822
InventoryFile('123', 'foo', parent_id='TREE_ROOT')
855
>>> i2.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
856
InventoryEntry('123', 'foo', kind='file', parent_id='TREE_ROOT')
825
>>> i2.add(InventoryFile('123', 'foo', ROOT_ID))
826
InventoryFile('123', 'foo', parent_id='TREE_ROOT')