~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Olaf Conradi
  • Date: 2006-03-28 23:30:02 UTC
  • mto: (1661.1.1 bzr.mbp.remember)
  • mto: This revision was merged to the branch mainline in revision 1663.
  • Revision ID: olaf@conradi.org-20060328233002-f6262df0e19c1963
Added testcases for using pull with --remember. Moved remember code to
beginning of cmd_pull. This remembers the location in case of a failure
during pull.

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
 
37
37
import bzrlib
38
38
from bzrlib.osutils import (pumpfile, quotefn, splitpath, joinpath,
39
 
                            appendpath, sha_strings)
 
39
                            pathjoin, sha_strings)
40
40
from bzrlib.trace import mutter
41
41
from bzrlib.errors import (NotVersionedError, InvalidEntryName,
42
42
                           BzrError, BzrCheckError)
79
79
    InventoryDirectory('123', 'src', parent_id='TREE_ROOT')
80
80
    >>> i.add(InventoryFile('2323', 'hello.c', parent_id='123'))
81
81
    InventoryFile('2323', 'hello.c', parent_id='123')
82
 
    >>> for j in i.iter_entries():
83
 
    ...   print j
 
82
    >>> shouldbe = {0: 'src', 1: pathjoin('src','hello.c')}
 
83
    >>> for ix, j in enumerate(i.iter_entries()):
 
84
    ...   print (j[0] == shouldbe[ix], j[1])
84
85
    ... 
85
 
    ('src', InventoryDirectory('123', 'src', parent_id='TREE_ROOT'))
86
 
    ('src/hello.c', InventoryFile('2323', 'hello.c', parent_id='123'))
 
86
    (True, InventoryDirectory('123', 'src', parent_id='TREE_ROOT'))
 
87
    (True, InventoryFile('2323', 'hello.c', parent_id='123'))
87
88
    >>> i.add(InventoryFile('2323', 'bye.c', '123'))
88
89
    Traceback (most recent call last):
89
90
    ...
101
102
    >>> i['2326']
102
103
    InventoryFile('2326', 'wibble.c', parent_id='2325')
103
104
    >>> for path, entry in i.iter_entries():
104
 
    ...     print path.replace('\\\\', '/')     # for win32 os.sep
 
105
    ...     print path
105
106
    ...     assert i.path2id(path)
106
107
    ... 
107
108
    src
109
110
    src/hello.c
110
111
    src/wibble
111
112
    src/wibble/wibble.c
112
 
    >>> i.id2path('2326').replace('\\\\', '/')
 
113
    >>> i.id2path('2326')
113
114
    'src/wibble/wibble.c'
114
115
    """
115
116
    
118
119
                 'revision']
119
120
 
120
121
    def _add_text_to_weave(self, new_lines, parents, weave_store, transaction):
121
 
        weave_store.add_text(self.file_id, self.revision, new_lines, parents,
122
 
                             transaction)
 
122
        versionedfile = weave_store.get_weave(self.file_id, transaction)
 
123
        versionedfile.add_lines(self.revision, parents, new_lines)
123
124
 
124
125
    def detect_changes(self, old_entry):
125
126
        """Return a (text_modified, meta_modified) from this to old_entry.
160
161
        any other. If the file is new, the set will be empty.
161
162
        """
162
163
        def get_ancestors(weave, entry):
163
 
            return set(map(weave.idx_to_name,
164
 
                           weave.inclusions([weave.lookup(entry.revision)])))
 
164
            return set(weave.get_ancestry(entry.revision))
165
165
        heads = {}
166
166
        head_ancestors = {}
167
167
        for inv in previous_inventories:
201
201
 
202
202
    def get_tar_item(self, root, dp, now, tree):
203
203
        """Get a tarfile item and a file stream for its content."""
204
 
        item = tarfile.TarInfo(os.path.join(root, dp))
 
204
        item = tarfile.TarInfo(pathjoin(root, dp))
205
205
        # TODO: would be cool to actually set it to the timestamp of the
206
206
        # revision it was last changed
207
207
        item.mtime = now
266
266
        
267
267
        This is a template method - implement _put_on_disk in subclasses.
268
268
        """
269
 
        fullpath = appendpath(dest, dp)
 
269
        fullpath = pathjoin(dest, dp)
270
270
        self._put_on_disk(fullpath, tree)
271
 
        mutter("  export {%s} kind %s to %s" % (self.file_id, self.kind, fullpath))
 
271
        mutter("  export {%s} kind %s to %s", self.file_id,
 
272
                self.kind, fullpath)
272
273
 
273
274
    def _put_on_disk(self, fullpath, tree):
274
275
        """Put this entry onto disk at fullpath, from tree tree."""
356
357
        """
357
358
        mutter('storing file {%s} in revision {%s}',
358
359
               self.file_id, self.revision)
359
 
        self._add_text_to_weave([], file_parents, weave_store, transaction)
 
360
        self._add_text_to_weave([], file_parents.keys(), weave_store, transaction)
360
361
 
361
362
    def __eq__(self, other):
362
363
        if not isinstance(other, InventoryEntry):
405
406
        # first requested, or preload them if they're already known
406
407
        pass            # nothing to do by default
407
408
 
 
409
    def _forget_tree_state(self):
 
410
        pass
 
411
 
408
412
 
409
413
class RootEntry(InventoryEntry):
410
414
 
416
420
        self.children = {}
417
421
        self.kind = 'root_directory'
418
422
        self.parent_id = None
419
 
        self.name = ''
 
423
        self.name = u''
420
424
 
421
425
    def __eq__(self, other):
422
426
        if not isinstance(other, RootEntry):
480
484
            else:
481
485
                checker.repeated_text_cnt += 1
482
486
                return
 
487
 
 
488
        if self.file_id not in checker.checked_weaves:
 
489
            mutter('check weave {%s}', self.file_id)
 
490
            w = tree.get_weave(self.file_id)
 
491
            # Not passing a progress bar, because it creates a new
 
492
            # progress, which overwrites the current progress,
 
493
            # and doesn't look nice
 
494
            w.check()
 
495
            checker.checked_weaves[self.file_id] = True
 
496
        else:
 
497
            w = tree.get_weave(self.file_id)
 
498
 
483
499
        mutter('check version {%s} of {%s}', rev_id, self.file_id)
484
 
        file_lines = tree.get_file_lines(self.file_id)
485
500
        checker.checked_text_cnt += 1 
486
 
        if self.text_size != sum(map(len, file_lines)):
487
 
            raise BzrCheckError('text {%s} wrong size' % self.text_id)
488
 
        if self.text_sha1 != sha_strings(file_lines):
489
 
            raise BzrCheckError('text {%s} wrong sha1' % self.text_id)
 
501
        # We can't check the length, because Weave doesn't store that
 
502
        # information, and the whole point of looking at the weave's
 
503
        # sha1sum is that we don't have to extract the text.
 
504
        if self.text_sha1 != w.get_sha1(self.revision):
 
505
            raise BzrCheckError('text {%s} version {%s} wrong sha1' 
 
506
                                % (self.file_id, self.revision))
490
507
        checker.checked_texts[t] = self.text_sha1
491
508
 
492
509
    def copy(self):
555
572
        self.text_sha1 = work_tree.get_file_sha1(self.file_id)
556
573
        self.executable = work_tree.is_executable(self.file_id)
557
574
 
 
575
    def _forget_tree_state(self):
 
576
        self.text_sha1 = None
 
577
        self.executable = None
 
578
 
558
579
    def _snapshot_text(self, file_parents, work_tree, weave_store, transaction):
559
580
        """See InventoryEntry._snapshot_text."""
560
581
        mutter('storing file {%s} in revision {%s}',
565
586
            and self.text_sha1 == file_parents.values()[0].text_sha1
566
587
            and self.text_size == file_parents.values()[0].text_size):
567
588
            previous_ie = file_parents.values()[0]
568
 
            weave_store.add_identical_text(
569
 
                self.file_id, previous_ie.revision, 
570
 
                self.revision, file_parents, transaction)
 
589
            versionedfile = weave_store.get_weave(self.file_id, transaction)
 
590
            versionedfile.clone_text(self.revision, previous_ie.revision, file_parents.keys())
571
591
        else:
572
592
            new_lines = work_tree.get_file(self.file_id).readlines()
573
 
            self._add_text_to_weave(new_lines, file_parents, weave_store,
 
593
            self._add_text_to_weave(new_lines, file_parents.keys(), weave_store,
574
594
                                    transaction)
575
595
            self.text_sha1 = sha_strings(new_lines)
576
596
            self.text_size = sum(map(len, new_lines))
646
666
 
647
667
    def _put_in_tar(self, item, tree):
648
668
        """See InventoryEntry._put_in_tar."""
649
 
        iterm.type = tarfile.SYMTYPE
 
669
        item.type = tarfile.SYMTYPE
650
670
        fileobj = None
651
671
        item.size = 0
652
672
        item.mode = 0755
664
684
        """See InventoryEntry._read_tree_state."""
665
685
        self.symlink_target = work_tree.get_symlink_target(self.file_id)
666
686
 
 
687
    def _forget_tree_state(self):
 
688
        self.symlink_target = None
 
689
 
667
690
    def _unchanged(self, previous_ie):
668
691
        """See InventoryEntry._unchanged."""
669
692
        compatible = super(InventoryLink, self)._unchanged(previous_ie)
720
743
        The inventory is created with a default root directory, with
721
744
        an id of None.
722
745
        """
723
 
        # We are letting Branch.initialize() create a unique inventory
 
746
        # We are letting Branch.create() create a unique inventory
724
747
        # root id. Rather than generating a random one here.
725
748
        #if root_id is None:
726
749
        #    root_id = bzrlib.branch.gen_file_id('TREE_ROOT')
762
785
            yield name, ie
763
786
            if ie.kind == 'directory':
764
787
                for cn, cie in self.iter_entries(from_dir=ie.file_id):
765
 
                    yield os.path.join(name, cn), cie
 
788
                    yield pathjoin(name, cn), cie
766
789
 
767
790
 
768
791
    def entries(self):
775
798
            kids = dir_ie.children.items()
776
799
            kids.sort()
777
800
            for name, ie in kids:
778
 
                child_path = os.path.join(dir_path, name)
 
801
                child_path = pathjoin(dir_path, name)
779
802
                accum.append((child_path, ie))
780
803
                if ie.kind == 'directory':
781
804
                    descend(ie, child_path)
782
805
 
783
 
        descend(self.root, '')
 
806
        descend(self.root, u'')
784
807
        return accum
785
808
 
786
809
 
795
818
            kids.sort()
796
819
 
797
820
            for name, child_ie in kids:
798
 
                child_path = os.path.join(parent_path, name)
 
821
                child_path = pathjoin(parent_path, name)
799
822
                descend(child_ie, child_path)
800
 
        descend(self.root, '')
 
823
        descend(self.root, u'')
801
824
        return accum
802
825
        
803
826
 
862
885
 
863
886
        if parent.children.has_key(entry.name):
864
887
            raise BzrError("%s is already versioned" %
865
 
                    appendpath(self.id2path(parent.file_id), entry.name))
 
888
                    pathjoin(self.id2path(parent.file_id), entry.name))
866
889
 
867
890
        self._byid[entry.file_id] = entry
868
891
        parent.children[entry.name] = entry
875
898
        The immediate parent must already be versioned.
876
899
 
877
900
        Returns the new entry object."""
878
 
        from bzrlib.branch import gen_file_id
 
901
        from bzrlib.workingtree import gen_file_id
879
902
        
880
903
        parts = bzrlib.osutils.splitpath(relpath)
881
 
        if len(parts) == 0:
882
 
            raise BzrError("cannot re-add root of inventory")
883
904
 
884
905
        if file_id == None:
885
906
            file_id = gen_file_id(relpath)
886
907
 
887
 
        parent_path = parts[:-1]
888
 
        parent_id = self.path2id(parent_path)
889
 
        if parent_id == None:
890
 
            raise NotVersionedError(path=parent_path)
 
908
        if len(parts) == 0:
 
909
            self.root = RootEntry(file_id)
 
910
            self._byid = {self.root.file_id: self.root}
 
911
            return
 
912
        else:
 
913
            parent_path = parts[:-1]
 
914
            parent_id = self.path2id(parent_path)
 
915
            if parent_id == None:
 
916
                raise NotVersionedError(path=parent_path)
891
917
        if kind == 'directory':
892
918
            ie = InventoryDirectory(file_id, parts[-1], parent_id)
893
919
        elif kind == 'file':
913
939
        """
914
940
        ie = self[file_id]
915
941
 
916
 
        assert self[ie.parent_id].children[ie.name] == ie
 
942
        assert ie.parent_id is None or \
 
943
            self[ie.parent_id].children[ie.name] == ie
917
944
        
918
 
        # TODO: Test deleting all children; maybe hoist to a separate
919
 
        # deltree method?
920
 
        if ie.kind == 'directory':
921
 
            for cie in ie.children.values():
922
 
                del self[cie.file_id]
923
 
            del ie.children
924
 
 
925
945
        del self._byid[file_id]
926
 
        del self[ie.parent_id].children[ie.name]
 
946
        if ie.parent_id is not None:
 
947
            del self[ie.parent_id].children[ie.name]
927
948
 
928
949
 
929
950
    def __eq__(self, other):
985
1006
        >>> i = Inventory()
986
1007
        >>> e = i.add(InventoryDirectory('src-id', 'src', ROOT_ID))
987
1008
        >>> e = i.add(InventoryFile('foo-id', 'foo.c', parent_id='src-id'))
988
 
        >>> print i.id2path('foo-id').replace(os.sep, '/')
 
1009
        >>> print i.id2path('foo-id')
989
1010
        src/foo.c
990
1011
        """
991
1012
        # get all names, skipping root
992
1013
        p = [self._byid[fid].name for fid in self.get_idpath(file_id)[1:]]
993
 
        return os.sep.join(p)
 
1014
        if p:
 
1015
            return pathjoin(*p)
 
1016
        else:
 
1017
            return ''
994
1018
            
995
1019
 
996
1020