~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Robert Collins
  • Date: 2005-10-03 15:19:25 UTC
  • mto: (1393.1.30)
  • mto: This revision was merged to the branch mainline in revision 1400.
  • Revision ID: robertc@robertcollins.net-20051003151925-19df6a9a5e9dc42a
remove kind from the InventoryEntry constructor - only child classes should be created now

Show diffs side-by-side

added added

removed removed

Lines of Context:
50
50
    name
51
51
        (within the parent directory)
52
52
 
53
 
    kind
54
 
        'directory' or 'file' or 'symlink'
55
 
 
56
53
    parent_id
57
54
        file_id of the parent directory, or ROOT_ID
58
55
 
196
193
 
197
194
        Note that textual data includes binary content.
198
195
        """
199
 
        if self.kind =='file':
200
 
            return True
201
 
        else:
202
 
            return False
 
196
        return False
203
197
 
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
206
200
        
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.
209
203
 
210
 
        >>> e = InventoryEntry('123', 'hello.c', 'file', ROOT_ID)
 
204
        >>> e = InventoryFile('123', 'hello.c', ROOT_ID)
211
205
        >>> e.name
212
206
        'hello.c'
213
207
        >>> e.file_id
214
208
        '123'
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
218
212
        """
226
220
        self.text_size = None
227
221
        self.file_id = file_id
228
222
        self.name = name
229
 
        self.kind = kind
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)
235
226
 
236
227
    def kind_character(self):
237
228
        """Return a short kind indicator useful for appending to names."""
241
232
 
242
233
    known_kinds = ('file', 'directory', 'symlink', 'root_directory')
243
234
 
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,
247
 
                              text_id)
248
 
 
249
235
    def _put_in_tar(self, item, tree):
250
236
        """populate item for stashing in a tar, and return the content stream.
251
237
 
252
238
        If no content is available, return None.
253
239
        """
254
 
        if self.kind == 'symlink':
255
 
            iterm.type = tarfile.SYMTYPE
256
 
            fileobj = None
257
 
            item.size = 0
258
 
            item.mode = 0755
259
 
            item.linkname = self.symlink_target
260
 
        else:
261
 
            raise BzrError("don't know how to export {%s} of kind %r" %
262
 
                    (self.file_id, self.kind))
263
 
        return fileobj
 
240
        raise BzrError("don't know how to export {%s} of kind %r" %
 
241
                       (self.file_id, self.kind))
264
242
 
265
243
    def put_on_disk(self, dest, dp, tree):
266
244
        """Create a representation of self on disk in the prefix dest.
273
251
 
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':
277
 
            try:
278
 
                os.symlink(self.symlink_target, fullpath)
279
 
            except OSError,e:
280
 
                raise BzrError("Failed to create symlink %r -> %r, error: %s" % (fullpath, self.symlink_target, e))
281
 
        else:
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))
283
255
 
284
256
    def sorted_children(self):
285
257
        l = self.children.items()
304
276
 
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))
314
 
        else:
315
 
            raise BzrCheckError('unknown entry kind %r in revision {%s}' % 
316
 
                                (self.kind, rev_id))
 
279
        raise BzrCheckError('unknown entry kind %r in revision {%s}' % 
 
280
                            (self.kind, rev_id))
317
281
 
318
282
 
319
283
    def copy(self):
320
 
        other = InventoryEntry(self.file_id, self.name, self.kind,
321
 
                               self.parent_id)
322
 
        other.symlink_target = self.symlink_target
323
 
        other.revision = self.revision
324
 
        # note that children are *not* copied; they're pulled across when
325
 
        # others are added
326
 
        return other
 
284
        """Clone this inventory entry."""
 
285
        raise NotImplementedError
327
286
 
328
287
    def _get_snapshot_change(self, previous_entries):
329
288
        if len(previous_entries) > 1:
334
293
            return 'modified/renamed/reparented'
335
294
 
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__,
339
298
                   self.file_id,
340
299
                   self.name,
341
 
                   self.kind,
342
300
                   self.parent_id))
343
301
 
344
302
    def snapshot(self, revision, path, previous_entries, work_tree, 
445
403
        self.parent_id = None
446
404
        self.name = ''
447
405
 
448
 
    def __new__(cls, file_id):
449
 
        """Only present until the InventoryEntry.__new__ can go away."""
450
 
        return object.__new__(RootEntry, file_id)
451
 
 
452
406
    def __eq__(self, other):
453
407
        if not isinstance(other, RootEntry):
454
408
            return NotImplemented
474
428
        return other
475
429
 
476
430
    def __init__(self, file_id, name, parent_id):
477
 
        super(InventoryDirectory, self).__init__(file_id, name, 'directory',
478
 
                                                 parent_id)
 
431
        super(InventoryDirectory, self).__init__(file_id, name, parent_id)
479
432
        self.children = {}
 
433
        self.kind = 'directory'
480
434
 
481
435
    def kind_character(self):
482
436
        """See InventoryEntry.kind_character."""
483
437
        return '/'
484
438
 
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',
488
 
                                parent_id)
489
 
        # type.__call__ is strange, it doesn't __init__ when the returned type
490
 
        # differs
491
 
        #result.__init__(file_id, name, 'directory', parent_id)
492
 
        return result
493
 
 
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)
506
451
 
507
 
    def __repr__(self):
508
 
        return ("%s(%r, %r, parent_id=%r)"
509
 
                % (self.__class__.__name__,
510
 
                   self.file_id,
511
 
                   self.name,
512
 
                   self.parent_id))
513
 
 
514
452
 
515
453
class InventoryFile(InventoryEntry):
516
454
    """A file in an inventory."""
545
483
        other.revision = self.revision
546
484
        return other
547
485
 
 
486
    def has_text(self):
 
487
        """See InventoryEntry.has_text."""
 
488
        return True
 
489
 
548
490
    def __init__(self, file_id, name, parent_id):
549
 
        super(InventoryFile, self).__init__(file_id, name, 'file',
550
 
                                                 parent_id)
 
491
        super(InventoryFile, self).__init__(file_id, name, parent_id)
 
492
        self.kind = 'file'
551
493
 
552
494
    def kind_character(self):
553
495
        """See InventoryEntry.kind_character."""
554
496
        return ''
555
497
 
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',
559
 
                                parent_id)
560
 
        # type.__call__ is strange, it doesn't __init__ when the returned type
561
 
        # differs
562
 
        #result.__init__(file_id, name, 'directory', parent_id)
563
 
        return result
564
 
 
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)
581
514
 
582
 
    def __repr__(self):
583
 
        return ("%s(%r, %r, parent_id=%r)"
584
 
                % (self.__class__.__name__,
585
 
                   self.file_id,
586
 
                   self.name,
587
 
                   self.parent_id))
 
515
 
 
516
class InventoryLink(InventoryEntry):
 
517
    """A file in an inventory."""
 
518
 
 
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))
 
527
 
 
528
    def copy(self):
 
529
        other = InventoryLink(self.file_id, self.name, self.parent_id)
 
530
        other.symlink_target = self.symlink_target
 
531
        other.revision = self.revision
 
532
        return other
 
533
 
 
534
    def __init__(self, file_id, name, parent_id):
 
535
        super(InventoryLink, self).__init__(file_id, name, parent_id)
 
536
        self.kind = 'symlink'
 
537
 
 
538
    def kind_character(self):
 
539
        """See InventoryEntry.kind_character."""
 
540
        return ''
 
541
 
 
542
    def _put_in_tar(self, item, tree):
 
543
        """See InventoryEntry._put_in_tar."""
 
544
        iterm.type = tarfile.SYMTYPE
 
545
        fileobj = None
 
546
        item.size = 0
 
547
        item.mode = 0755
 
548
        item.linkname = self.symlink_target
 
549
        return fileobj
 
550
 
 
551
    def _put_on_disk(self, fullpath, tree):
 
552
        """See InventoryEntry._put_on_disk."""
 
553
        try:
 
554
            os.symlink(self.symlink_target, fullpath)
 
555
        except OSError,e:
 
556
            raise BzrError("Failed to create symlink %r -> %r, error: %s" % (fullpath, self.symlink_target, e))
588
557
 
589
558
 
590
559
class Inventory(object):
605
574
    inserted, other than through the Inventory API.
606
575
 
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
611
580
    'hello.c'
612
581
 
622
591
    >>> [x[0] for x in inv.iter_entries()]
623
592
    ['hello.c']
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')
627
596
    """
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.
722
691
 
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')
726
695
        >>> '123' in inv
727
696
        True
728
697
        >>> '456' in inv
735
704
        """Return the entry for given file_id.
736
705
 
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
741
710
        'hello.c'
742
711
        """
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)
811
782
        else:
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)
815
785
 
816
786
 
818
788
        """Remove entry by id.
819
789
 
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')
823
793
        >>> '123' in inv
824
794
        True
825
795
        >>> del inv['123']
848
818
        >>> i2 = Inventory()
849
819
        >>> i1 == i2
850
820
        True
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')
853
823
        >>> i1 == i2
854
824
        False
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')
857
827
        >>> i1 == i2
858
828
        True
859
829
        """