~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 14:47:12 UTC
  • mto: (1393.1.30)
  • mto: This revision was merged to the branch mainline in revision 1400.
  • Revision ID: robertc@robertcollins.net-20051003144712-44b3339bd5cfcf69
factor out file related logic from InventoryEntry to InventoryFile

Show diffs side-by-side

added added

removed removed

Lines of Context:
77
77
    'TREE_ROOT'
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():
83
83
    ...   print j
84
84
    ... 
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):
89
89
    ...
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')
96
96
    '2325'
97
97
    >>> '2325' in i
98
98
    True
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')
101
101
    >>> i['2326']
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)
235
235
 
236
236
    def kind_character(self):
237
237
        """Return a short kind indicator useful for appending to names."""
238
 
        if self.kind == 'file':
239
 
            return ''
240
238
        if self.kind == 'symlink':
241
239
            return ''
242
240
        raise RuntimeError('unreachable code')
253
251
 
254
252
        If no content is available, return None.
255
253
        """
256
 
        if self.kind == 'file':
257
 
            item.type = tarfile.REGTYPE
258
 
            fileobj = tree.get_file(self.file_id)
259
 
            item.size = self.text_size
260
 
            if tree.is_executable(self.file_id):
261
 
                item.mode = 0755
262
 
            else:
263
 
                item.mode = 0644
264
 
        elif self.kind == 'symlink':
 
254
        if self.kind == 'symlink':
265
255
            iterm.type = tarfile.SYMTYPE
266
256
            fileobj = None
267
257
            item.size = 0
283
273
 
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':
291
277
            try:
292
278
                os.symlink(self.symlink_target, fullpath)
293
279
            except OSError,e:
318
304
 
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))
329
 
                else:
330
 
                    checker.repeated_text_cnt += 1
331
 
                    return
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))
352
319
    def copy(self):
353
320
        other = InventoryEntry(self.file_id, self.name, self.kind,
354
321
                               self.parent_id)
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
549
512
                   self.parent_id))
550
513
 
551
514
 
 
515
class InventoryFile(InventoryEntry):
 
516
    """A file in an inventory."""
 
517
 
 
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))
 
527
            else:
 
528
                checker.repeated_text_cnt += 1
 
529
                return
 
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
 
538
 
 
539
    def copy(self):
 
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
 
546
        return other
 
547
 
 
548
    def __init__(self, file_id, name, parent_id):
 
549
        super(InventoryFile, self).__init__(file_id, name, 'file',
 
550
                                                 parent_id)
 
551
 
 
552
    def kind_character(self):
 
553
        """See InventoryEntry.kind_character."""
 
554
        return ''
 
555
 
 
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
    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):
 
571
            item.mode = 0755
 
572
        else:
 
573
            item.mode = 0644
 
574
        return fileobj
 
575
 
 
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)
 
581
 
 
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))
 
588
 
 
589
 
552
590
class Inventory(object):
553
591
    """Inventory of versioned files in a tree.
554
592
 
768
806
 
769
807
        if kind == 'directory':
770
808
            ie = InventoryDirectory(file_id, parts[-1], parent_id)
 
809
        elif kind == 'file':
 
810
            ie = InventoryFile(file_id, parts[-1], parent_id)
771
811
        else:
772
812
            ie = InventoryEntry(file_id, parts[-1],
773
813
                                kind=kind, parent_id=parent_id)