~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Alexander Belchenko
  • Date: 2007-04-19 19:28:39 UTC
  • mto: This revision was merged to the branch mainline in revision 2439.
  • Revision ID: bialix@ukr.net-20070419192839-p964uu06n6vbjgrt
changes after John's review

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
193
193
            if self.file_id in inv:
194
194
                ie = inv[self.file_id]
195
195
                assert ie.file_id == self.file_id
 
196
                if ie.kind != self.kind:
 
197
                    # Can't be a candidate if the kind has changed.
 
198
                    continue
196
199
                if ie.revision in candidates:
197
200
                    # same revision value in two different inventories:
198
201
                    # correct possible inconsistencies:
297
300
        self.text_id = text_id
298
301
        self.parent_id = parent_id
299
302
        self.symlink_target = None
 
303
        self.reference_revision = None
300
304
 
301
305
    def kind_character(self):
302
306
        """Return a short kind indicator useful for appending to names."""
331
335
 
332
336
    @staticmethod
333
337
    def versionable_kind(kind):
334
 
        return (kind in ('file', 'directory', 'symlink'))
 
338
        return (kind in ('file', 'directory', 'symlink', 'tree-reference'))
335
339
 
336
340
    def check(self, checker, rev_id, inv, tree):
337
341
        """Check this inventory entry is intact.
469
473
                and (self.kind == other.kind)
470
474
                and (self.revision == other.revision)
471
475
                and (self.executable == other.executable)
 
476
                and (self.reference_revision == other.reference_revision)
472
477
                )
473
478
 
474
479
    def __ne__(self, other):
489
494
        # renamed
490
495
        elif previous_ie.name != self.name:
491
496
            compatible = False
 
497
        elif previous_ie.kind != self.kind:
 
498
            compatible = False
492
499
        return compatible
493
500
 
494
501
    def _read_tree_state(self, path, work_tree):
509
516
class RootEntry(InventoryEntry):
510
517
 
511
518
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
512
 
                 'text_id', 'parent_id', 'children', 'executable', 
513
 
                 'revision', 'symlink_target']
 
519
                 'text_id', 'parent_id', 'children', 'executable',
 
520
                 'revision', 'symlink_target', 'reference_revision']
514
521
 
515
522
    def _check(self, checker, rev_id, tree):
516
523
        """See InventoryEntry._check"""
538
545
    """A directory in an inventory."""
539
546
 
540
547
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
541
 
                 'text_id', 'parent_id', 'children', 'executable', 
542
 
                 'revision', 'symlink_target']
 
548
                 'text_id', 'parent_id', 'children', 'executable',
 
549
                 'revision', 'symlink_target', 'reference_revision']
543
550
 
544
551
    def _check(self, checker, rev_id, tree):
545
552
        """See InventoryEntry._check"""
585
592
    """A file in an inventory."""
586
593
 
587
594
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
588
 
                 'text_id', 'parent_id', 'children', 'executable', 
589
 
                 'revision', 'symlink_target']
 
595
                 'text_id', 'parent_id', 'children', 'executable',
 
596
                 'revision', 'symlink_target', 'reference_revision']
590
597
 
591
598
    def _check(self, checker, tree_revision_id, tree):
592
599
        """See InventoryEntry._check"""
733
740
    """A file in an inventory."""
734
741
 
735
742
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
736
 
                 'text_id', 'parent_id', 'children', 'executable', 
737
 
                 'revision', 'symlink_target']
 
743
                 'text_id', 'parent_id', 'children', 'executable',
 
744
                 'revision', 'symlink_target', 'reference_revision']
738
745
 
739
746
    def _check(self, checker, rev_id, tree):
740
747
        """See InventoryEntry._check"""
821
828
            self.file_id, file_parents, self.symlink_target)
822
829
 
823
830
 
 
831
class TreeReference(InventoryEntry):
 
832
    
 
833
    kind = 'tree-reference'
 
834
    
 
835
    def __init__(self, file_id, name, parent_id, revision=None,
 
836
                 reference_revision=None):
 
837
        InventoryEntry.__init__(self, file_id, name, parent_id)
 
838
        self.revision = revision
 
839
        self.reference_revision = reference_revision
 
840
 
 
841
    def copy(self):
 
842
        return TreeReference(self.file_id, self.name, self.parent_id,
 
843
                             self.revision, self.reference_revision)
 
844
 
 
845
    def _snapshot_text(self, file_parents, work_tree, commit_builder):
 
846
        commit_builder.modified_reference(self.file_id, file_parents)
 
847
 
 
848
    def _read_tree_state(self, path, work_tree):
 
849
        """Populate fields in the inventory entry from the given tree.
 
850
        """
 
851
        self.reference_revision = work_tree.get_reference_revision(
 
852
            self.file_id, path)
 
853
 
 
854
    def _forget_tree_state(self):
 
855
        self.reference_revision = None 
 
856
 
 
857
 
824
858
class Inventory(object):
825
859
    """Inventory of versioned files in a tree.
826
860
 
956
990
        :return: This yields (path, entry) pairs
957
991
        """
958
992
        if specific_file_ids:
959
 
            specific_file_ids = [osutils.safe_file_id(fid)
960
 
                                 for fid in specific_file_ids]
 
993
            safe = osutils.safe_file_id
 
994
            specific_file_ids = set(safe(fid) for fid in specific_file_ids)
961
995
        # TODO? Perhaps this should return the from_dir so that the root is
962
996
        # yielded? or maybe an option?
963
997
        if from_dir is None:
977
1011
            from_dir = self._byid[from_dir]
978
1012
 
979
1013
        if specific_file_ids is not None:
 
1014
            # TODO: jam 20070302 This could really be done as a loop rather
 
1015
            #       than a bunch of recursive calls.
980
1016
            parents = set()
 
1017
            byid = self._byid
981
1018
            def add_ancestors(file_id):
982
 
                if file_id not in self:
 
1019
                if file_id not in byid:
983
1020
                    return
984
 
                parent_id = self[file_id].parent_id
 
1021
                parent_id = byid[file_id].parent_id
985
1022
                if parent_id is None:
986
1023
                    return
987
1024
                if parent_id not in parents:
1082
1119
        parent_id = osutils.safe_file_id(parent_id)
1083
1120
        return self[parent_id].children.get(filename)
1084
1121
 
 
1122
    def _add_child(self, entry):
 
1123
        """Add an entry to the inventory, without adding it to its parent"""
 
1124
        if entry.file_id in self._byid:
 
1125
            raise BzrError("inventory already contains entry with id {%s}" %
 
1126
                           entry.file_id)
 
1127
        self._byid[entry.file_id] = entry
 
1128
        for child in getattr(entry, 'children', {}).itervalues():
 
1129
            self._add_child(child)
 
1130
        return entry
 
1131
 
1085
1132
    def add(self, entry):
1086
1133
        """Add entry to inventory.
1087
1134
 
1096
1143
 
1097
1144
        if entry.parent_id is None:
1098
1145
            assert self.root is None and len(self._byid) == 0
1099
 
            self._set_root(entry)
1100
 
            return entry
1101
 
        try:
1102
 
            parent = self._byid[entry.parent_id]
1103
 
        except KeyError:
1104
 
            raise BzrError("parent_id {%s} not in inventory" % entry.parent_id)
1105
 
 
1106
 
        if entry.name in parent.children:
1107
 
            raise BzrError("%s is already versioned" %
1108
 
                    osutils.pathjoin(self.id2path(parent.file_id), entry.name))
1109
 
 
1110
 
        self._byid[entry.file_id] = entry
1111
 
        parent.children[entry.name] = entry
1112
 
        return entry
 
1146
            self.root = entry
 
1147
        else:
 
1148
            try:
 
1149
                parent = self._byid[entry.parent_id]
 
1150
            except KeyError:
 
1151
                raise BzrError("parent_id {%s} not in inventory" %
 
1152
                               entry.parent_id)
 
1153
 
 
1154
            if entry.name in parent.children:
 
1155
                raise BzrError("%s is already versioned" %
 
1156
                        osutils.pathjoin(self.id2path(parent.file_id),
 
1157
                        entry.name).encode('utf-8'))
 
1158
            parent.children[entry.name] = entry
 
1159
        return self._add_child(entry)
1113
1160
 
1114
1161
    def add_path(self, relpath, kind, file_id=None, parent_id=None):
1115
1162
        """Add entry from a path.
1192
1239
            try:
1193
1240
                ie = self._byid[file_id]
1194
1241
            except KeyError:
1195
 
                raise BzrError("file_id {%s} not found in inventory" % file_id)
 
1242
                raise errors.NoSuchId(tree=None, file_id=file_id)
1196
1243
            yield ie
1197
1244
            file_id = ie.parent_id
1198
1245
 
1282
1329
        for file_id in reversed(to_delete):
1283
1330
            ie = self[file_id]
1284
1331
            del self._byid[file_id]
1285
 
            if ie.parent_id is not None:
1286
 
                del self[ie.parent_id].children[ie.name]
 
1332
        if ie.parent_id is not None:
 
1333
            del self[ie.parent_id].children[ie.name]
 
1334
        else:
 
1335
            self.root = None
1287
1336
 
1288
1337
    def rename(self, file_id, new_parent_id, new_name):
1289
1338
        """Move a file within the inventory.
1322
1371
 
1323
1372
 
1324
1373
entry_factory = {
1325
 
    'directory':InventoryDirectory,
1326
 
    'file':InventoryFile,
1327
 
    'symlink':InventoryLink,
 
1374
    'directory': InventoryDirectory,
 
1375
    'file': InventoryFile,
 
1376
    'symlink': InventoryLink,
 
1377
    'tree-reference': TreeReference
1328
1378
}
1329
1379
 
1330
1380
def make_entry(kind, name, parent_id, file_id=None):