~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Robert Collins
  • Date: 2006-08-08 23:19:29 UTC
  • mfrom: (1884 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1912.
  • Revision ID: robertc@robertcollins.net-20060808231929-4e3e298190214b3a
current status

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
import types
37
37
 
38
38
import bzrlib
 
39
from bzrlib import errors, osutils
39
40
from bzrlib.osutils import (pumpfile, quotefn, splitpath, joinpath,
40
41
                            pathjoin, sha_strings)
41
42
from bzrlib.errors import (NotVersionedError, InvalidEntryName,
77
78
    >>> i.path2id('')
78
79
    'TREE_ROOT'
79
80
    >>> i.add(InventoryDirectory('123', 'src', ROOT_ID))
80
 
    InventoryDirectory('123', 'src', parent_id='TREE_ROOT')
 
81
    InventoryDirectory('123', 'src', parent_id='TREE_ROOT', revision=None)
81
82
    >>> i.add(InventoryFile('2323', 'hello.c', parent_id='123'))
82
 
    InventoryFile('2323', 'hello.c', parent_id='123')
 
83
    InventoryFile('2323', 'hello.c', parent_id='123', sha1=None, len=None)
83
84
    >>> shouldbe = {0: 'src', 1: pathjoin('src','hello.c')}
84
85
    >>> for ix, j in enumerate(i.iter_entries()):
85
86
    ...   print (j[0] == shouldbe[ix], j[1])
86
87
    ... 
87
 
    (True, InventoryDirectory('123', 'src', parent_id='TREE_ROOT'))
88
 
    (True, InventoryFile('2323', 'hello.c', parent_id='123'))
 
88
    (True, InventoryDirectory('123', 'src', parent_id='TREE_ROOT', revision=None))
 
89
    (True, InventoryFile('2323', 'hello.c', parent_id='123', sha1=None, len=None))
89
90
    >>> i.add(InventoryFile('2323', 'bye.c', '123'))
90
91
    Traceback (most recent call last):
91
92
    ...
92
93
    BzrError: inventory already contains entry with id {2323}
93
94
    >>> i.add(InventoryFile('2324', 'bye.c', '123'))
94
 
    InventoryFile('2324', 'bye.c', parent_id='123')
 
95
    InventoryFile('2324', 'bye.c', parent_id='123', sha1=None, len=None)
95
96
    >>> i.add(InventoryDirectory('2325', 'wibble', '123'))
96
 
    InventoryDirectory('2325', 'wibble', parent_id='123')
 
97
    InventoryDirectory('2325', 'wibble', parent_id='123', revision=None)
97
98
    >>> i.path2id('src/wibble')
98
99
    '2325'
99
100
    >>> '2325' in i
100
101
    True
101
102
    >>> i.add(InventoryFile('2326', 'wibble.c', '2325'))
102
 
    InventoryFile('2326', 'wibble.c', parent_id='2325')
 
103
    InventoryFile('2326', 'wibble.c', parent_id='2325', sha1=None, len=None)
103
104
    >>> i['2326']
104
 
    InventoryFile('2326', 'wibble.c', parent_id='2325')
 
105
    InventoryFile('2326', 'wibble.c', parent_id='2325', sha1=None, len=None)
105
106
    >>> for path, entry in i.iter_entries():
106
107
    ...     print path
107
108
    ...     assert i.path2id(path)
123
124
    RENAMED = 'renamed'
124
125
    MODIFIED_AND_RENAMED = 'modified and renamed'
125
126
    
126
 
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
127
 
                 'text_id', 'parent_id', 'children', 'executable', 
128
 
                 'revision']
 
127
    __slots__ = []
129
128
 
130
129
    def detect_changes(self, old_entry):
131
130
        """Return a (text_modified, meta_modified) from this to old_entry.
160
159
                            versioned_file_store,
161
160
                            transaction,
162
161
                            entry_vf=None):
163
 
        """Return the revisions and entries that directly preceed this.
 
162
        """Return the revisions and entries that directly precede this.
164
163
 
165
164
        Returned as a map from revision to inventory entry.
166
165
 
319
318
        raise BzrError("don't know how to export {%s} of kind %r" % (self.file_id, self.kind))
320
319
 
321
320
    def sorted_children(self):
322
 
        l = self.children.items()
323
 
        l.sort()
324
 
        return l
 
321
        return sorted(self.children.items())
325
322
 
326
323
    @staticmethod
327
324
    def versionable_kind(kind):
341
338
        :param inv: Inventory from which the entry was loaded.
342
339
        :param tree: RevisionTree for this entry.
343
340
        """
344
 
        if self.parent_id != None:
 
341
        if self.parent_id is not None:
345
342
            if not inv.has_id(self.parent_id):
346
343
                raise BzrCheckError('missing parent {%s} in inventory for revision {%s}'
347
344
                        % (self.parent_id, rev_id))
397
394
        return 'unchanged'
398
395
 
399
396
    def __repr__(self):
400
 
        return ("%s(%r, %r, parent_id=%r)"
 
397
        return ("%s(%r, %r, parent_id=%r, revision=%r)"
401
398
                % (self.__class__.__name__,
402
399
                   self.file_id,
403
400
                   self.name,
404
 
                   self.parent_id))
 
401
                   self.parent_id,
 
402
                   self.revision))
405
403
 
406
404
    def snapshot(self, revision, path, previous_entries,
407
405
                 work_tree, commit_builder):
471
469
    def _unchanged(self, previous_ie):
472
470
        """Has this entry changed relative to previous_ie.
473
471
 
474
 
        This method should be overriden in child classes.
 
472
        This method should be overridden in child classes.
475
473
        """
476
474
        compatible = True
477
475
        # different inv parent
499
497
 
500
498
class RootEntry(InventoryEntry):
501
499
 
 
500
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
 
501
                 'text_id', 'parent_id', 'children', 'executable', 
 
502
                 'revision', 'symlink_target']
 
503
 
502
504
    def _check(self, checker, rev_id, tree):
503
505
        """See InventoryEntry._check"""
504
506
 
508
510
        self.kind = 'root_directory'
509
511
        self.parent_id = None
510
512
        self.name = u''
 
513
        self.revision = None
511
514
 
512
515
    def __eq__(self, other):
513
516
        if not isinstance(other, RootEntry):
520
523
class InventoryDirectory(InventoryEntry):
521
524
    """A directory in an inventory."""
522
525
 
 
526
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
 
527
                 'text_id', 'parent_id', 'children', 'executable', 
 
528
                 'revision', 'symlink_target']
 
529
 
523
530
    def _check(self, checker, rev_id, tree):
524
531
        """See InventoryEntry._check"""
525
 
        if self.text_sha1 != None or self.text_size != None or self.text_id != None:
 
532
        if self.text_sha1 is not None or self.text_size is not None or self.text_id is not None:
526
533
            raise BzrCheckError('directory {%s} has text in revision {%s}'
527
534
                                % (self.file_id, rev_id))
528
535
 
563
570
class InventoryFile(InventoryEntry):
564
571
    """A file in an inventory."""
565
572
 
 
573
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
 
574
                 'text_id', 'parent_id', 'children', 'executable', 
 
575
                 'revision', 'symlink_target']
 
576
 
566
577
    def _check(self, checker, tree_revision_id, tree):
567
578
        """See InventoryEntry._check"""
568
579
        t = (self.file_id, self.revision)
607
618
 
608
619
    def detect_changes(self, old_entry):
609
620
        """See InventoryEntry.detect_changes."""
610
 
        assert self.text_sha1 != None
611
 
        assert old_entry.text_sha1 != None
 
621
        assert self.text_sha1 is not None
 
622
        assert old_entry.text_sha1 is not None
612
623
        text_modified = (self.text_sha1 != old_entry.text_sha1)
613
624
        meta_modified = (self.executable != old_entry.executable)
614
625
        return text_modified, meta_modified
671
682
        # in _read_tree_state
672
683
        self.executable = work_tree.is_executable(self.file_id, path=path)
673
684
 
 
685
    def __repr__(self):
 
686
        return ("%s(%r, %r, parent_id=%r, sha1=%r, len=%s)"
 
687
                % (self.__class__.__name__,
 
688
                   self.file_id,
 
689
                   self.name,
 
690
                   self.parent_id,
 
691
                   self.text_sha1,
 
692
                   self.text_size))
 
693
 
674
694
    def _forget_tree_state(self):
675
695
        self.text_sha1 = None
676
 
        self.executable = None
677
696
 
678
697
    def _snapshot_text(self, file_parents, work_tree, commit_builder):
679
698
        """See InventoryEntry._snapshot_text."""
699
718
class InventoryLink(InventoryEntry):
700
719
    """A file in an inventory."""
701
720
 
702
 
    __slots__ = ['symlink_target']
 
721
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
 
722
                 'text_id', 'parent_id', 'children', 'executable', 
 
723
                 'revision', 'symlink_target']
703
724
 
704
725
    def _check(self, checker, rev_id, tree):
705
726
        """See InventoryEntry._check"""
706
 
        if self.text_sha1 != None or self.text_size != None or self.text_id != None:
 
727
        if self.text_sha1 is not None or self.text_size is not None or self.text_id is not None:
707
728
            raise BzrCheckError('symlink {%s} has text in revision {%s}'
708
729
                    % (self.file_id, rev_id))
709
730
        if self.symlink_target is None:
805
826
 
806
827
    >>> inv = Inventory()
807
828
    >>> inv.add(InventoryFile('123-123', 'hello.c', ROOT_ID))
808
 
    InventoryFile('123-123', 'hello.c', parent_id='TREE_ROOT')
 
829
    InventoryFile('123-123', 'hello.c', parent_id='TREE_ROOT', sha1=None, len=None)
809
830
    >>> inv['123-123'].name
810
831
    'hello.c'
811
832
 
822
843
    [u'hello.c']
823
844
    >>> inv = Inventory('TREE_ROOT-12345678-12345678')
824
845
    >>> inv.add(InventoryFile('123-123', 'hello.c', ROOT_ID))
825
 
    InventoryFile('123-123', 'hello.c', parent_id='TREE_ROOT-12345678-12345678')
 
846
    InventoryFile('123-123', 'hello.c', parent_id='TREE_ROOT-12345678-12345678', sha1=None, len=None)
826
847
    """
827
848
    def __init__(self, root_id=ROOT_ID, revision_id=None):
828
849
        """Create or read an inventory.
839
860
        #if root_id is None:
840
861
        #    root_id = bzrlib.branch.gen_file_id('TREE_ROOT')
841
862
        self.root = RootEntry(root_id)
 
863
        # FIXME: this isn't ever used, changing it to self.revision may break
 
864
        # things. TODO make everything use self.revision_id
842
865
        self.revision_id = revision_id
843
866
        self._byid = {self.root.file_id: self.root}
844
867
 
974
997
 
975
998
        >>> inv = Inventory()
976
999
        >>> inv.add(InventoryFile('123', 'foo.c', ROOT_ID))
977
 
        InventoryFile('123', 'foo.c', parent_id='TREE_ROOT')
 
1000
        InventoryFile('123', 'foo.c', parent_id='TREE_ROOT', sha1=None, len=None)
978
1001
        >>> '123' in inv
979
1002
        True
980
1003
        >>> '456' in inv
987
1010
 
988
1011
        >>> inv = Inventory()
989
1012
        >>> inv.add(InventoryFile('123123', 'hello.c', ROOT_ID))
990
 
        InventoryFile('123123', 'hello.c', parent_id='TREE_ROOT')
 
1013
        InventoryFile('123123', 'hello.c', parent_id='TREE_ROOT', sha1=None, len=None)
991
1014
        >>> inv['123123'].name
992
1015
        'hello.c'
993
1016
        """
1024
1047
        except KeyError:
1025
1048
            raise BzrError("parent_id {%s} not in inventory" % entry.parent_id)
1026
1049
 
1027
 
        if parent.children.has_key(entry.name):
 
1050
        if entry.name in parent.children:
1028
1051
            raise BzrError("%s is already versioned" %
1029
1052
                    pathjoin(self.id2path(parent.file_id), entry.name))
1030
1053
 
1039
1062
 
1040
1063
        Returns the new entry object."""
1041
1064
        
1042
 
        parts = bzrlib.osutils.splitpath(relpath)
 
1065
        parts = osutils.splitpath(relpath)
1043
1066
 
1044
1067
        if len(parts) == 0:
1045
1068
            if file_id is None:
1060
1083
 
1061
1084
        >>> inv = Inventory()
1062
1085
        >>> inv.add(InventoryFile('123', 'foo.c', ROOT_ID))
1063
 
        InventoryFile('123', 'foo.c', parent_id='TREE_ROOT')
 
1086
        InventoryFile('123', 'foo.c', parent_id='TREE_ROOT', sha1=None, len=None)
1064
1087
        >>> '123' in inv
1065
1088
        True
1066
1089
        >>> del inv['123']
1084
1107
        >>> i1 == i2
1085
1108
        True
1086
1109
        >>> i1.add(InventoryFile('123', 'foo', ROOT_ID))
1087
 
        InventoryFile('123', 'foo', parent_id='TREE_ROOT')
 
1110
        InventoryFile('123', 'foo', parent_id='TREE_ROOT', sha1=None, len=None)
1088
1111
        >>> i1 == i2
1089
1112
        False
1090
1113
        >>> i2.add(InventoryFile('123', 'foo', ROOT_ID))
1091
 
        InventoryFile('123', 'foo', parent_id='TREE_ROOT')
 
1114
        InventoryFile('123', 'foo', parent_id='TREE_ROOT', sha1=None, len=None)
1092
1115
        >>> i1 == i2
1093
1116
        True
1094
1117
        """
1095
1118
        if not isinstance(other, Inventory):
1096
1119
            return NotImplemented
1097
1120
 
1098
 
        if len(self._byid) != len(other._byid):
1099
 
            # shortcut: obviously not the same
1100
 
            return False
1101
 
 
1102
1121
        return self._byid == other._byid
1103
1122
 
1104
1123
    def __ne__(self, other):
1109
1128
 
1110
1129
    def _iter_file_id_parents(self, file_id):
1111
1130
        """Yield the parents of file_id up to the root."""
1112
 
        while file_id != None:
 
1131
        while file_id is not None:
1113
1132
            try:
1114
1133
                ie = self._byid[file_id]
1115
1134
            except KeyError:
1219
1238
    """
1220
1239
    if file_id is None:
1221
1240
        file_id = bzrlib.workingtree.gen_file_id(name)
 
1241
 
 
1242
    norm_name, can_access = osutils.normalized_filename(name)
 
1243
    if norm_name != name:
 
1244
        if can_access:
 
1245
            name = norm_name
 
1246
        else:
 
1247
            # TODO: jam 20060701 This would probably be more useful
 
1248
            #       if the error was raised with the full path
 
1249
            raise errors.InvalidNormalization(name)
 
1250
 
1222
1251
    if kind == 'directory':
1223
1252
        return InventoryDirectory(file_id, name, parent_id)
1224
1253
    elif kind == 'file':
1229
1258
        raise BzrError("unknown kind %r" % kind)
1230
1259
 
1231
1260
 
1232
 
 
1233
1261
_NAME_RE = None
1234
1262
 
1235
1263
def is_valid_name(name):