~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

[merge] bzr.dev 2255, resolve conflicts, update copyrights

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
# created, but it's not for now.
28
28
ROOT_ID = "TREE_ROOT"
29
29
 
30
 
 
31
 
import collections
32
 
import os.path
 
30
import os
33
31
import re
34
32
import sys
 
33
 
 
34
from bzrlib.lazy_import import lazy_import
 
35
lazy_import(globals(), """
 
36
import collections
35
37
import tarfile
36
 
import types
37
 
from warnings import warn
38
38
 
39
39
import bzrlib
40
 
from bzrlib import errors, osutils
41
 
from bzrlib.osutils import (pumpfile, quotefn, splitpath, joinpath,
42
 
                            pathjoin, sha_strings)
43
 
from bzrlib.errors import (NotVersionedError, InvalidEntryName,
44
 
                           BzrError, BzrCheckError, BinaryFile)
 
40
from bzrlib import (
 
41
    errors,
 
42
    generate_ids,
 
43
    osutils,
 
44
    symbol_versioning,
 
45
    workingtree,
 
46
    )
 
47
""")
 
48
 
 
49
from bzrlib.errors import (
 
50
    BzrCheckError,
 
51
    BzrError,
 
52
    )
45
53
from bzrlib.trace import mutter
46
54
 
47
55
 
82
90
    InventoryDirectory('123', 'src', parent_id='TREE_ROOT', revision=None)
83
91
    >>> i.add(InventoryFile('2323', 'hello.c', parent_id='123'))
84
92
    InventoryFile('2323', 'hello.c', parent_id='123', sha1=None, len=None)
85
 
    >>> shouldbe = {0: '', 1: 'src', 2: pathjoin('src','hello.c')}
 
93
    >>> shouldbe = {0: '', 1: 'src', 2: 'src/hello.c'}
86
94
    >>> for ix, j in enumerate(i.iter_entries()):
87
95
    ...   print (j[0] == shouldbe[ix], j[1])
88
96
    ... 
246
254
 
247
255
    def get_tar_item(self, root, dp, now, tree):
248
256
        """Get a tarfile item and a file stream for its content."""
249
 
        item = tarfile.TarInfo(pathjoin(root, dp).encode('utf8'))
 
257
        item = tarfile.TarInfo(osutils.pathjoin(root, dp).encode('utf8'))
250
258
        # TODO: would be cool to actually set it to the timestamp of the
251
259
        # revision it was last changed
252
260
        item.mtime = now
281
289
        """
282
290
        assert isinstance(name, basestring), name
283
291
        if '/' in name or '\\' in name:
284
 
            raise InvalidEntryName(name=name)
 
292
            raise errors.InvalidEntryName(name=name)
285
293
        self.executable = False
286
294
        self.revision = None
287
295
        self.text_sha1 = None
311
319
        
312
320
        This is a template method - implement _put_on_disk in subclasses.
313
321
        """
314
 
        fullpath = pathjoin(dest, dp)
 
322
        fullpath = osutils.pathjoin(dest, dp)
315
323
        self._put_on_disk(fullpath, tree)
316
324
        # mutter("  export {%s} kind %s to %s", self.file_id,
317
325
        #         self.kind, fullpath)
514
522
        self.parent_id = None
515
523
        self.name = u''
516
524
        self.revision = None
517
 
        warn('RootEntry is deprecated as of bzr 0.10.  Please use '
518
 
             'InventoryDirectory instead.',
519
 
            DeprecationWarning, stacklevel=2)
 
525
        symbol_versioning.warn('RootEntry is deprecated as of bzr 0.10.'
 
526
                               '  Please use InventoryDirectory instead.',
 
527
                               DeprecationWarning, stacklevel=2)
520
528
 
521
529
    def __eq__(self, other):
522
530
        if not isinstance(other, RootEntry):
645
653
            else:
646
654
                text_diff(to_label, to_text,
647
655
                          from_label, from_text, output_to)
648
 
        except BinaryFile:
 
656
        except errors.BinaryFile:
649
657
            if reverse:
650
658
                label_pair = (to_label, from_label)
651
659
            else:
677
685
 
678
686
    def _put_on_disk(self, fullpath, tree):
679
687
        """See InventoryEntry._put_on_disk."""
680
 
        pumpfile(tree.get_file(self.file_id), file(fullpath, 'wb'))
 
688
        osutils.pumpfile(tree.get_file(self.file_id), file(fullpath, 'wb'))
681
689
        if tree.is_executable(self.file_id):
682
690
            os.chmod(fullpath, 0755)
683
691
 
849
857
    ['', u'hello.c']
850
858
    >>> inv = Inventory('TREE_ROOT-12345678-12345678')
851
859
    >>> inv.add(InventoryFile('123-123', 'hello.c', ROOT_ID))
 
860
    Traceback (most recent call last):
 
861
    BzrError: parent_id {TREE_ROOT} not in inventory
 
862
    >>> inv.add(InventoryFile('123-123', 'hello.c', 'TREE_ROOT-12345678-12345678'))
852
863
    InventoryFile('123-123', 'hello.c', parent_id='TREE_ROOT-12345678-12345678', sha1=None, len=None)
853
864
    """
854
865
    def __init__(self, root_id=ROOT_ID, revision_id=None):
861
872
        The inventory is created with a default root directory, with
862
873
        an id of None.
863
874
        """
864
 
        # We are letting Branch.create() create a unique inventory
865
 
        # root id. Rather than generating a random one here.
866
 
        #if root_id is None:
867
 
        #    root_id = bzrlib.branch.gen_file_id('TREE_ROOT')
868
875
        if root_id is not None:
869
876
            self._set_root(InventoryDirectory(root_id, '', None))
870
877
        else:
871
878
            self.root = None
872
879
            self._byid = {}
873
 
        # FIXME: this isn't ever used, changing it to self.revision may break
874
 
        # things. TODO make everything use self.revision_id
875
880
        self.revision_id = revision_id
876
881
 
877
882
    def _set_root(self, ie):
898
903
    def iter_entries(self, from_dir=None):
899
904
        """Return (path, entry) pairs, in order by name."""
900
905
        if from_dir is None:
901
 
            assert self.root
 
906
            if self.root is None:
 
907
                return
902
908
            from_dir = self.root
903
909
            yield '', self.root
904
910
        elif isinstance(from_dir, basestring):
938
944
                # if we finished all children, pop it off the stack
939
945
                stack.pop()
940
946
 
941
 
    def iter_entries_by_dir(self, from_dir=None):
 
947
    def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None):
942
948
        """Iterate over the entries in a directory first order.
943
949
 
944
950
        This returns all entries for a directory before returning
951
957
        # TODO? Perhaps this should return the from_dir so that the root is
952
958
        # yielded? or maybe an option?
953
959
        if from_dir is None:
954
 
            assert self.root
 
960
            if self.root is None:
 
961
                return
 
962
            # Optimize a common case
 
963
            if specific_file_ids is not None and len(specific_file_ids) == 1:
 
964
                file_id = list(specific_file_ids)[0]
 
965
                if file_id in self:
 
966
                    yield self.id2path(file_id), self[file_id]
 
967
                return 
955
968
            from_dir = self.root
956
 
            yield '', self.root
 
969
            if (specific_file_ids is None or 
 
970
                self.root.file_id in specific_file_ids):
 
971
                yield '', self.root
957
972
        elif isinstance(from_dir, basestring):
958
973
            from_dir = self._byid[from_dir]
 
974
 
 
975
        if specific_file_ids is not None:
 
976
            parents = set()
 
977
            def add_ancestors(file_id):
 
978
                if file_id not in self:
 
979
                    return
 
980
                parent_id = self[file_id].parent_id
 
981
                if parent_id is None:
 
982
                    return
 
983
                if parent_id not in parents:
 
984
                    parents.add(parent_id)
 
985
                    add_ancestors(parent_id)
 
986
            for file_id in specific_file_ids:
 
987
                add_ancestors(file_id)
 
988
        else:
 
989
            parents = None
959
990
            
960
991
        stack = [(u'', from_dir)]
961
992
        while stack:
966
997
 
967
998
                child_relpath = cur_relpath + child_name
968
999
 
969
 
                yield child_relpath, child_ie
 
1000
                if (specific_file_ids is None or 
 
1001
                    child_ie.file_id in specific_file_ids):
 
1002
                    yield child_relpath, child_ie
970
1003
 
971
1004
                if child_ie.kind == 'directory':
972
 
                    child_dirs.append((child_relpath+'/', child_ie))
 
1005
                    if parents is None or child_ie.file_id in parents:
 
1006
                        child_dirs.append((child_relpath+'/', child_ie))
973
1007
            stack.extend(reversed(child_dirs))
974
1008
 
975
1009
    def entries(self):
982
1016
            kids = dir_ie.children.items()
983
1017
            kids.sort()
984
1018
            for name, ie in kids:
985
 
                child_path = pathjoin(dir_path, name)
 
1019
                child_path = osutils.pathjoin(dir_path, name)
986
1020
                accum.append((child_path, ie))
987
1021
                if ie.kind == 'directory':
988
1022
                    descend(ie, child_path)
1001
1035
            kids.sort()
1002
1036
 
1003
1037
            for name, child_ie in kids:
1004
 
                child_path = pathjoin(parent_path, name)
 
1038
                child_path = osutils.pathjoin(parent_path, name)
1005
1039
                descend(child_ie, child_path)
1006
1040
        descend(self.root, u'')
1007
1041
        return accum
1031
1065
        try:
1032
1066
            return self._byid[file_id]
1033
1067
        except KeyError:
1034
 
            if file_id is None:
1035
 
                raise BzrError("can't look up file_id None")
1036
 
            else:
1037
 
                raise BzrError("file_id {%s} not in inventory" % file_id)
 
1068
            # really we're passing an inventory, not a tree...
 
1069
            raise errors.NoSuchId(self, file_id)
1038
1070
 
1039
1071
    def get_file_kind(self, file_id):
1040
1072
        return self._byid[file_id].kind
1057
1089
            assert self.root is None and len(self._byid) == 0
1058
1090
            self._set_root(entry)
1059
1091
            return entry
1060
 
        if entry.parent_id == ROOT_ID:
1061
 
            assert self.root is not None, self
1062
 
            entry.parent_id = self.root.file_id
1063
 
 
1064
1092
        try:
1065
1093
            parent = self._byid[entry.parent_id]
1066
1094
        except KeyError:
1068
1096
 
1069
1097
        if entry.name in parent.children:
1070
1098
            raise BzrError("%s is already versioned" %
1071
 
                    pathjoin(self.id2path(parent.file_id), entry.name))
 
1099
                    osutils.pathjoin(self.id2path(parent.file_id), entry.name))
1072
1100
 
1073
1101
        self._byid[entry.file_id] = entry
1074
1102
        parent.children[entry.name] = entry
1085
1113
 
1086
1114
        if len(parts) == 0:
1087
1115
            if file_id is None:
1088
 
                file_id = bzrlib.workingtree.gen_root_id()
 
1116
                file_id = generate_ids.gen_root_id()
1089
1117
            self.root = InventoryDirectory(file_id, '', None)
1090
1118
            self._byid = {self.root.file_id: self.root}
1091
 
            return
 
1119
            return self.root
1092
1120
        else:
1093
1121
            parent_path = parts[:-1]
1094
1122
            parent_id = self.path2id(parent_path)
1095
1123
            if parent_id is None:
1096
 
                raise NotVersionedError(path=parent_path)
 
1124
                raise errors.NotVersionedError(path=parent_path)
1097
1125
        ie = make_entry(kind, parts[-1], parent_id, file_id)
1098
1126
        return self.add(ie)
1099
1127
 
1193
1221
 
1194
1222
        Returns None IFF the path is not found.
1195
1223
        """
1196
 
        if isinstance(name, types.StringTypes):
1197
 
            name = splitpath(name)
 
1224
        if isinstance(name, basestring):
 
1225
            name = osutils.splitpath(name)
1198
1226
 
1199
1227
        # mutter("lookup path %r" % name)
1200
1228
 
1201
1229
        parent = self.root
 
1230
        if parent is None:
 
1231
            return None
1202
1232
        for f in name:
1203
1233
            try:
1204
 
                cie = parent.children[f]
 
1234
                children = getattr(parent, 'children', None)
 
1235
                if children is None:
 
1236
                    return None
 
1237
                cie = children[f]
1205
1238
                assert cie.name == f
1206
1239
                assert cie.parent_id == parent.file_id
1207
1240
                parent = cie
1264
1297
        file_ie.name = new_name
1265
1298
        file_ie.parent_id = new_parent_id
1266
1299
 
 
1300
    def is_root(self, file_id):
 
1301
        return self.root is not None and file_id == self.root.file_id
 
1302
 
1267
1303
 
1268
1304
def make_entry(kind, name, parent_id, file_id=None):
1269
1305
    """Create an inventory entry.
1274
1310
    :param file_id: the file_id to use. if None, one will be created.
1275
1311
    """
1276
1312
    if file_id is None:
1277
 
        file_id = bzrlib.workingtree.gen_file_id(name)
 
1313
        file_id = generate_ids.gen_file_id(name)
1278
1314
 
1279
1315
    norm_name, can_access = osutils.normalized_filename(name)
1280
1316
    if norm_name != name: