~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-03-07 10:45:44 UTC
  • mfrom: (2321.1.2 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20070307104544-59e3e6358e4bdb29
(robertc) Merge dirstate and subtrees. (Robert Collins, Martin Pool, Aaaron Bentley, John A Meinel, James Westby)

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
97
97
    (True, InventoryDirectory('TREE_ROOT', u'', parent_id=None, revision=None))
98
98
    (True, InventoryDirectory('123', 'src', parent_id='TREE_ROOT', revision=None))
99
99
    (True, InventoryFile('2323', 'hello.c', parent_id='123', sha1=None, len=None))
100
 
    >>> i.add(InventoryFile('2323', 'bye.c', '123'))
101
 
    Traceback (most recent call last):
102
 
    ...
103
 
    BzrError: inventory already contains entry with id {2323}
104
100
    >>> i.add(InventoryFile('2324', 'bye.c', '123'))
105
101
    InventoryFile('2324', 'bye.c', parent_id='123', sha1=None, len=None)
106
102
    >>> i.add(InventoryDirectory('2325', 'wibble', '123'))
301
297
        self.text_id = text_id
302
298
        self.parent_id = parent_id
303
299
        self.symlink_target = None
 
300
        self.reference_revision = None
304
301
 
305
302
    def kind_character(self):
306
303
        """Return a short kind indicator useful for appending to names."""
335
332
 
336
333
    @staticmethod
337
334
    def versionable_kind(kind):
338
 
        return (kind in ('file', 'directory', 'symlink'))
 
335
        return (kind in ('file', 'directory', 'symlink', 'tree-reference'))
339
336
 
340
337
    def check(self, checker, rev_id, inv, tree):
341
338
        """Check this inventory entry is intact.
473
470
                and (self.kind == other.kind)
474
471
                and (self.revision == other.revision)
475
472
                and (self.executable == other.executable)
 
473
                and (self.reference_revision == other.reference_revision)
476
474
                )
477
475
 
478
476
    def __ne__(self, other):
513
511
class RootEntry(InventoryEntry):
514
512
 
515
513
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
516
 
                 'text_id', 'parent_id', 'children', 'executable', 
517
 
                 'revision', 'symlink_target']
 
514
                 'text_id', 'parent_id', 'children', 'executable',
 
515
                 'revision', 'symlink_target', 'reference_revision']
518
516
 
519
517
    def _check(self, checker, rev_id, tree):
520
518
        """See InventoryEntry._check"""
542
540
    """A directory in an inventory."""
543
541
 
544
542
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
545
 
                 'text_id', 'parent_id', 'children', 'executable', 
546
 
                 'revision', 'symlink_target']
 
543
                 'text_id', 'parent_id', 'children', 'executable',
 
544
                 'revision', 'symlink_target', 'reference_revision']
547
545
 
548
546
    def _check(self, checker, rev_id, tree):
549
547
        """See InventoryEntry._check"""
589
587
    """A file in an inventory."""
590
588
 
591
589
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
592
 
                 'text_id', 'parent_id', 'children', 'executable', 
593
 
                 'revision', 'symlink_target']
 
590
                 'text_id', 'parent_id', 'children', 'executable',
 
591
                 'revision', 'symlink_target', 'reference_revision']
594
592
 
595
593
    def _check(self, checker, tree_revision_id, tree):
596
594
        """See InventoryEntry._check"""
737
735
    """A file in an inventory."""
738
736
 
739
737
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
740
 
                 'text_id', 'parent_id', 'children', 'executable', 
741
 
                 'revision', 'symlink_target']
 
738
                 'text_id', 'parent_id', 'children', 'executable',
 
739
                 'revision', 'symlink_target', 'reference_revision']
742
740
 
743
741
    def _check(self, checker, rev_id, tree):
744
742
        """See InventoryEntry._check"""
825
823
            self.file_id, file_parents, self.symlink_target)
826
824
 
827
825
 
 
826
class TreeReference(InventoryEntry):
 
827
    
 
828
    kind = 'tree-reference'
 
829
    
 
830
    def __init__(self, file_id, name, parent_id, revision=None,
 
831
                 reference_revision=None):
 
832
        InventoryEntry.__init__(self, file_id, name, parent_id)
 
833
        self.revision = revision
 
834
        self.reference_revision = reference_revision
 
835
 
 
836
    def copy(self):
 
837
        return TreeReference(self.file_id, self.name, self.parent_id,
 
838
                             self.revision, self.reference_revision)
 
839
 
 
840
    def _snapshot_text(self, file_parents, work_tree, commit_builder):
 
841
        commit_builder.modified_reference(self.file_id, file_parents)
 
842
 
 
843
    def _read_tree_state(self, path, work_tree):
 
844
        """Populate fields in the inventory entry from the given tree.
 
845
        """
 
846
        self.reference_revision = work_tree.get_reference_revision(
 
847
            self.file_id, path)
 
848
 
 
849
    def _forget_tree_state(self):
 
850
        self.reference_revision = None 
 
851
 
 
852
 
828
853
class Inventory(object):
829
854
    """Inventory of versioned files in a tree.
830
855
 
1089
1114
        parent_id = osutils.safe_file_id(parent_id)
1090
1115
        return self[parent_id].children.get(filename)
1091
1116
 
 
1117
    def _add_child(self, entry):
 
1118
        """Add an entry to the inventory, without adding it to its parent"""
 
1119
        if entry.file_id in self._byid:
 
1120
            raise BzrError("inventory already contains entry with id {%s}" %
 
1121
                           entry.file_id)
 
1122
        self._byid[entry.file_id] = entry
 
1123
        for child in getattr(entry, 'children', {}).itervalues():
 
1124
            self._add_child(child)
 
1125
        return entry
 
1126
 
1092
1127
    def add(self, entry):
1093
1128
        """Add entry to inventory.
1094
1129
 
1098
1133
        Returns the new entry object.
1099
1134
        """
1100
1135
        if entry.file_id in self._byid:
1101
 
            raise BzrError("inventory already contains entry with id {%s}" % entry.file_id)
 
1136
            raise errors.DuplicateFileId(entry.file_id,
 
1137
                                         self._byid[entry.file_id])
1102
1138
 
1103
1139
        if entry.parent_id is None:
1104
1140
            assert self.root is None and len(self._byid) == 0
1105
 
            self._set_root(entry)
1106
 
            return entry
1107
 
        try:
1108
 
            parent = self._byid[entry.parent_id]
1109
 
        except KeyError:
1110
 
            raise BzrError("parent_id {%s} not in inventory" % entry.parent_id)
1111
 
 
1112
 
        if entry.name in parent.children:
1113
 
            raise BzrError("%s is already versioned" %
1114
 
                    osutils.pathjoin(self.id2path(parent.file_id), entry.name))
1115
 
 
1116
 
        self._byid[entry.file_id] = entry
1117
 
        parent.children[entry.name] = entry
1118
 
        return entry
 
1141
            self.root = entry
 
1142
        else:
 
1143
            try:
 
1144
                parent = self._byid[entry.parent_id]
 
1145
            except KeyError:
 
1146
                raise BzrError("parent_id {%s} not in inventory" %
 
1147
                               entry.parent_id)
 
1148
 
 
1149
            if entry.name in parent.children:
 
1150
                raise BzrError("%s is already versioned" %
 
1151
                        osutils.pathjoin(self.id2path(parent.file_id),
 
1152
                        entry.name))
 
1153
            parent.children[entry.name] = entry
 
1154
        return self._add_child(entry)
1119
1155
 
1120
1156
    def add_path(self, relpath, kind, file_id=None, parent_id=None):
1121
1157
        """Add entry from a path.
1198
1234
            try:
1199
1235
                ie = self._byid[file_id]
1200
1236
            except KeyError:
1201
 
                raise BzrError("file_id {%s} not found in inventory" % file_id)
 
1237
                raise errors.NoSuchId(tree=None, file_id=file_id)
1202
1238
            yield ie
1203
1239
            file_id = ie.parent_id
1204
1240
 
1288
1324
        for file_id in reversed(to_delete):
1289
1325
            ie = self[file_id]
1290
1326
            del self._byid[file_id]
1291
 
            if ie.parent_id is not None:
1292
 
                del self[ie.parent_id].children[ie.name]
 
1327
        if ie.parent_id is not None:
 
1328
            del self[ie.parent_id].children[ie.name]
1293
1329
 
1294
1330
    def rename(self, file_id, new_parent_id, new_name):
1295
1331
        """Move a file within the inventory.
1327
1363
        return self.root is not None and file_id == self.root.file_id
1328
1364
 
1329
1365
 
 
1366
entry_factory = {
 
1367
    'directory': InventoryDirectory,
 
1368
    'file': InventoryFile,
 
1369
    'symlink': InventoryLink,
 
1370
    'tree-reference': TreeReference
 
1371
}
 
1372
 
1330
1373
def make_entry(kind, name, parent_id, file_id=None):
1331
1374
    """Create an inventory entry.
1332
1375
 
1340
1383
    else:
1341
1384
        file_id = osutils.safe_file_id(file_id)
1342
1385
 
 
1386
    #------- This has been copied to bzrlib.dirstate.DirState.add, please
 
1387
    # keep them synchronised.
 
1388
    # we dont import normalized_filename directly because we want to be
 
1389
    # able to change the implementation at runtime for tests.
1343
1390
    norm_name, can_access = osutils.normalized_filename(name)
1344
1391
    if norm_name != name:
1345
1392
        if can_access:
1349
1396
            #       if the error was raised with the full path
1350
1397
            raise errors.InvalidNormalization(name)
1351
1398
 
1352
 
    if kind == 'directory':
1353
 
        return InventoryDirectory(file_id, name, parent_id)
1354
 
    elif kind == 'file':
1355
 
        return InventoryFile(file_id, name, parent_id)
1356
 
    elif kind == 'symlink':
1357
 
        return InventoryLink(file_id, name, parent_id)
1358
 
    else:
 
1399
    try:
 
1400
        factory = entry_factory[kind]
 
1401
    except KeyError:
1359
1402
        raise BzrError("unknown kind %r" % kind)
 
1403
    return factory(file_id, name, parent_id)
1360
1404
 
1361
1405
 
1362
1406
_NAME_RE = None