~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Jelmer Vernooij
  • Date: 2010-08-17 22:24:01 UTC
  • mfrom: (5379 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5389.
  • Revision ID: jelmer@samba.org-20100817222401-x6iblsx36pu6bi3r
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
import re
36
36
import tarfile
37
37
 
38
 
import bzrlib
39
38
from bzrlib import (
40
39
    chk_map,
41
40
    errors,
42
41
    generate_ids,
43
42
    osutils,
44
 
    symbol_versioning,
45
43
    )
46
44
""")
47
45
 
49
47
    BzrCheckError,
50
48
    BzrError,
51
49
    )
52
 
from bzrlib.symbol_versioning import deprecated_in, deprecated_method
53
50
from bzrlib.trace import mutter
54
51
from bzrlib.static_tuple import StaticTuple
55
52
 
131
128
    RENAMED = 'renamed'
132
129
    MODIFIED_AND_RENAMED = 'modified and renamed'
133
130
 
134
 
    __slots__ = []
 
131
    __slots__ = ['file_id', 'revision', 'parent_id', 'name']
 
132
 
 
133
    # Attributes that all InventoryEntry instances are expected to have, but
 
134
    # that don't vary for all kinds of entry.  (e.g. symlink_target is only
 
135
    # relevant to InventoryLink, so there's no reason to make every
 
136
    # InventoryFile instance allocate space to hold a value for it.)
 
137
    # Attributes that only vary for files: executable, text_sha1, text_size,
 
138
    # text_id
 
139
    executable = False
 
140
    text_sha1 = None
 
141
    text_size = None
 
142
    text_id = None
 
143
    # Attributes that only vary for symlinks: symlink_target
 
144
    symlink_target = None
 
145
    # Attributes that only vary for tree-references: reference_revision
 
146
    reference_revision = None
 
147
 
135
148
 
136
149
    def detect_changes(self, old_entry):
137
150
        """Return a (text_modified, meta_modified) from this to old_entry.
187
200
        """
188
201
        return False
189
202
 
190
 
    def __init__(self, file_id, name, parent_id, text_id=None):
 
203
    def __init__(self, file_id, name, parent_id):
191
204
        """Create an InventoryEntry
192
205
 
193
206
        The filename must be a single component, relative to the
204
217
        """
205
218
        if '/' in name or '\\' in name:
206
219
            raise errors.InvalidEntryName(name=name)
207
 
        self.executable = False
 
220
        self.file_id = file_id
208
221
        self.revision = None
209
 
        self.text_sha1 = None
210
 
        self.text_size = None
211
 
        self.file_id = file_id
212
222
        self.name = name
213
 
        self.text_id = text_id
214
223
        self.parent_id = parent_id
215
 
        self.symlink_target = None
216
 
        self.reference_revision = None
217
224
 
218
225
    def kind_character(self):
219
226
        """Return a short kind indicator useful for appending to names."""
221
228
 
222
229
    known_kinds = ('file', 'directory', 'symlink')
223
230
 
224
 
    def _put_in_tar(self, item, tree):
225
 
        """populate item for stashing in a tar, and return the content stream.
226
 
 
227
 
        If no content is available, return None.
228
 
        """
229
 
        raise BzrError("don't know how to export {%s} of kind %r" %
230
 
                       (self.file_id, self.kind))
231
 
 
232
 
    def _put_on_disk(self, fullpath, tree):
233
 
        """Put this entry onto disk at fullpath, from tree tree."""
234
 
        raise BzrError("don't know how to export {%s} of kind %r" % (self.file_id, self.kind))
235
 
 
236
231
    def sorted_children(self):
237
232
        return sorted(self.children.items())
238
233
 
379
374
class InventoryDirectory(InventoryEntry):
380
375
    """A directory in an inventory."""
381
376
 
382
 
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
383
 
                 'text_id', 'parent_id', 'children', 'executable',
384
 
                 'revision', 'symlink_target', 'reference_revision']
 
377
    __slots__ = ['children']
 
378
 
 
379
    kind = 'directory'
385
380
 
386
381
    def _check(self, checker, rev_id):
387
382
        """See InventoryEntry._check"""
388
 
        if (self.text_sha1 is not None or self.text_size is not None or
389
 
            self.text_id is not None):
390
 
            checker._report_items.append('directory {%s} has text in revision {%s}'
391
 
                                % (self.file_id, rev_id))
392
383
        # In non rich root repositories we do not expect a file graph for the
393
384
        # root.
394
385
        if self.name == '' and not checker.rich_roots:
410
401
    def __init__(self, file_id, name, parent_id):
411
402
        super(InventoryDirectory, self).__init__(file_id, name, parent_id)
412
403
        self.children = {}
413
 
        self.kind = 'directory'
414
404
 
415
405
    def kind_character(self):
416
406
        """See InventoryEntry.kind_character."""
417
407
        return '/'
418
408
 
419
 
    def _put_in_tar(self, item, tree):
420
 
        """See InventoryEntry._put_in_tar."""
421
 
        item.type = tarfile.DIRTYPE
422
 
        fileobj = None
423
 
        item.name += '/'
424
 
        item.size = 0
425
 
        item.mode = 0755
426
 
        return fileobj
427
 
 
428
 
    def _put_on_disk(self, fullpath, tree):
429
 
        """See InventoryEntry._put_on_disk."""
430
 
        os.mkdir(fullpath)
431
 
 
432
409
 
433
410
class InventoryFile(InventoryEntry):
434
411
    """A file in an inventory."""
435
412
 
436
 
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
437
 
                 'text_id', 'parent_id', 'children', 'executable',
438
 
                 'revision', 'symlink_target', 'reference_revision']
 
413
    __slots__ = ['text_sha1', 'text_size', 'text_id', 'executable']
 
414
 
 
415
    kind = 'file'
 
416
 
 
417
    def __init__(self, file_id, name, parent_id):
 
418
        super(InventoryFile, self).__init__(file_id, name, parent_id)
 
419
        self.text_sha1 = None
 
420
        self.text_size = None
 
421
        self.text_id = None
 
422
        self.executable = False
439
423
 
440
424
    def _check(self, checker, tree_revision_id):
441
425
        """See InventoryEntry._check"""
484
468
        """See InventoryEntry.has_text."""
485
469
        return True
486
470
 
487
 
    def __init__(self, file_id, name, parent_id):
488
 
        super(InventoryFile, self).__init__(file_id, name, parent_id)
489
 
        self.kind = 'file'
490
 
 
491
471
    def kind_character(self):
492
472
        """See InventoryEntry.kind_character."""
493
473
        return ''
494
474
 
495
 
    def _put_in_tar(self, item, tree):
496
 
        """See InventoryEntry._put_in_tar."""
497
 
        item.type = tarfile.REGTYPE
498
 
        fileobj = tree.get_file(self.file_id)
499
 
        item.size = self.text_size
500
 
        if tree.is_executable(self.file_id):
501
 
            item.mode = 0755
502
 
        else:
503
 
            item.mode = 0644
504
 
        return fileobj
505
 
 
506
 
    def _put_on_disk(self, fullpath, tree):
507
 
        """See InventoryEntry._put_on_disk."""
508
 
        osutils.pumpfile(tree.get_file(self.file_id), file(fullpath, 'wb'))
509
 
        if tree.is_executable(self.file_id):
510
 
            os.chmod(fullpath, 0755)
511
 
 
512
475
    def _read_tree_state(self, path, work_tree):
513
476
        """See InventoryEntry._read_tree_state."""
514
477
        self.text_sha1 = work_tree.get_file_sha1(self.file_id, path=path)
546
509
class InventoryLink(InventoryEntry):
547
510
    """A file in an inventory."""
548
511
 
549
 
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
550
 
                 'text_id', 'parent_id', 'children', 'executable',
551
 
                 'revision', 'symlink_target', 'reference_revision']
 
512
    __slots__ = ['symlink_target']
 
513
 
 
514
    kind = 'symlink'
 
515
 
 
516
    def __init__(self, file_id, name, parent_id):
 
517
        super(InventoryLink, self).__init__(file_id, name, parent_id)
 
518
        self.symlink_target = None
552
519
 
553
520
    def _check(self, checker, tree_revision_id):
554
521
        """See InventoryEntry._check"""
555
 
        if self.text_sha1 is not None or self.text_size is not None or self.text_id is not None:
556
 
            checker._report_items.append(
557
 
               'symlink {%s} has text in revision {%s}'
558
 
                    % (self.file_id, tree_revision_id))
559
522
        if self.symlink_target is None:
560
523
            checker._report_items.append(
561
524
                'symlink {%s} has no target in revision {%s}'
599
562
        differ = DiffSymlink(old_tree, new_tree, output_to)
600
563
        return differ.diff_symlink(old_target, new_target)
601
564
 
602
 
    def __init__(self, file_id, name, parent_id):
603
 
        super(InventoryLink, self).__init__(file_id, name, parent_id)
604
 
        self.kind = 'symlink'
605
 
 
606
565
    def kind_character(self):
607
566
        """See InventoryEntry.kind_character."""
608
567
        return ''
609
568
 
610
 
    def _put_in_tar(self, item, tree):
611
 
        """See InventoryEntry._put_in_tar."""
612
 
        item.type = tarfile.SYMTYPE
613
 
        fileobj = None
614
 
        item.size = 0
615
 
        item.mode = 0755
616
 
        item.linkname = self.symlink_target
617
 
        return fileobj
618
 
 
619
 
    def _put_on_disk(self, fullpath, tree):
620
 
        """See InventoryEntry._put_on_disk."""
621
 
        try:
622
 
            os.symlink(self.symlink_target, fullpath)
623
 
        except OSError,e:
624
 
            raise BzrError("Failed to create symlink %r -> %r, error: %s" % (fullpath, self.symlink_target, e))
625
 
 
626
569
    def _read_tree_state(self, path, work_tree):
627
570
        """See InventoryEntry._read_tree_state."""
628
571
        self.symlink_target = work_tree.get_symlink_target(self.file_id)
640
583
 
641
584
class TreeReference(InventoryEntry):
642
585
 
 
586
    __slots__ = ['reference_revision']
 
587
 
643
588
    kind = 'tree-reference'
644
589
 
645
590
    def __init__(self, file_id, name, parent_id, revision=None,
1233
1178
    def add(self, entry):
1234
1179
        """Add entry to inventory.
1235
1180
 
1236
 
        To add  a file to a branch ready to be committed, use Branch.add,
1237
 
        which calls this.
1238
 
 
1239
1181
        :return: entry
1240
1182
        """
1241
1183
        if entry.file_id in self._byid:
2192
2134
class CHKInventoryDirectory(InventoryDirectory):
2193
2135
    """A directory in an inventory."""
2194
2136
 
2195
 
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
2196
 
                 'text_id', 'parent_id', '_children', 'executable',
2197
 
                 'revision', 'symlink_target', 'reference_revision',
2198
 
                 '_chk_inventory']
 
2137
    __slots__ = ['_children', '_chk_inventory']
2199
2138
 
2200
2139
    def __init__(self, file_id, name, parent_id, chk_inventory):
2201
2140
        # Don't call InventoryDirectory.__init__ - it isn't right for this
2202
2141
        # class.
2203
2142
        InventoryEntry.__init__(self, file_id, name, parent_id)
2204
2143
        self._children = None
2205
 
        self.kind = 'directory'
2206
2144
        self._chk_inventory = chk_inventory
2207
2145
 
2208
2146
    @property