~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/dirstate.py

Dirstate: Fix setting of parent trees to record data about entries not in
the current tree, and fix serialisation and deserialisation to correctly
save and retrieve all entries and parents.

Show diffs side-by-side

added added

removed removed

Lines of Context:
245
245
        to_yesno = DirState._to_yesno
246
246
 
247
247
        st = os.lstat(tree.basedir)
248
 
        root_info = [
 
248
        root_info = (
249
249
            '', '' # No path
250
250
            , 'directory', tree.inventory.root.file_id.encode('utf8')
251
251
            , 0 # no point having a size for dirs.
252
252
            , pack_stat(st)
253
253
            , '' # No sha
254
 
            ]
 
254
            )
255
255
        root_parents = []
256
256
        for parent_tree in parent_trees:
257
257
            root_parents.append((
294
294
                parent_info = []
295
295
                for count in xrange(num_parents):
296
296
                    parent_info.append(
297
 
                        self._parent_info(parent_trees[count], fileid))
 
297
                        result._parent_info(parent_trees[count], fileid))
298
298
                row_data = (dirname.encode('utf8'), basename.encode('utf8'),
299
299
                    kind, fileid.encode('utf8'), st.st_size, pack_stat(st),
300
300
                    s)
478
478
 
479
479
            assert len(entries) == self._num_entries, '%s != %s entries' % (len(entries),
480
480
                self._num_entries)
481
 
            entry_iter = iter(entries)
482
 
            self._root_row = entry_iter.next()
483
 
            # convert the minikind to kind
484
 
            self._root_row[0][2] = self._minikind_to_kind[self._root_row[0][2]]
485
 
            # convert the size to an int
486
 
            self._root_row[0][4] = int(self._root_row[0][4])
487
 
            # TODO parent converion
488
 
            # TODO dirblock population
489
 
            for entry in entry_iter:
490
 
                # do something here
491
 
                pass
 
481
 
 
482
            def _line_to_row(line):
 
483
                """Convert a freshly read line's size and minikind for use."""
 
484
                # convert the minikind to kind
 
485
                line[0][2] = self._minikind_to_kind[line[0][2]]
 
486
                # convert the size to an int
 
487
                line[0][4] = int(line[0][4])
 
488
                for parent in line[1]:
 
489
                    parent[1] = self._minikind_to_kind[parent[1]]
 
490
                    parent[4] = int(parent[4])
 
491
                    parent[5] = parent[5] == 'y'
 
492
                return tuple(line[0]), map(tuple, line[1])
 
493
            new_rows = map(_line_to_row, entries)
 
494
            self._rows_to_current_state(new_rows)
492
495
        self._dirblock_state = DirState.IN_MEMORY_UNMODIFIED
493
496
 
494
497
    def _read_header(self):
557
560
        entire_row[4] = str(entire_row[4])
558
561
        # minikind of parents
559
562
        return '\0'.join(entire_row)
 
563
 
 
564
    def _rows_to_current_state(self, new_rows):
 
565
        """Load new_rows into self._root_row and self.dirblocks.
 
566
 
 
567
        Process new_rows into the current state object, making them the active
 
568
        state.
 
569
 
 
570
        :param new_rows: A sorted list of rows. This function does not sort
 
571
            to prevent unneeded overhead when callers have a sorted list
 
572
            already.
 
573
        :return: Nothing.
 
574
        """
 
575
        assert new_rows[0][0][0:2] == ('', ''), \
 
576
            "Incorrect root row %r" % new_rows[0][0]
 
577
        self._root_row = new_rows[0]
 
578
        self._dirblocks = [('', [])]
 
579
        for row in new_rows[1:]:
 
580
            if row[0] != self._dirblocks[-1][0]:
 
581
                # new block
 
582
                self._dirblocks.append((row[0][0], []))
 
583
            # append the row to the current block
 
584
            self._dirblocks[-1][1].append(row)
560
585
    
561
586
    def save(self):
562
587
        """Save any pending changes created during this session."""
634
659
        # skip ghost trees, as they dont get represented.
635
660
        parent_trees = [tree for rev_id, tree in trees if rev_id not in ghosts]
636
661
        parent_tree_count = len(parent_trees)
 
662
        # loop over existing entries in the dirstate.
 
663
        checked_ids = set()
637
664
        for entry, old_parents in self._iter_rows():
638
665
            file_id = entry[3]
639
 
            new_parents = [None] * parent_tree_count
640
 
            for position, parent_tree in enumerate(parent_trees):
641
 
                # revision_utf8, KIND, dirname, basename, size, executable, sha
642
 
                new_parents[position] = self._parent_info(parent_tree, file_id)
643
 
            assert None not in new_parents
644
 
            new_rows.append((entry, new_parents))
645
 
        self._root_row = new_rows[0]
646
 
        self._dirblocks = []
647
 
         
 
666
            checked_ids.add(file_id)
 
667
            new_parents = [None] * parent_tree_count
 
668
            for position, parent_tree in enumerate(parent_trees):
 
669
                # revision_utf8, KIND, dirname, basename, size, executable, sha
 
670
                new_parents[position] = self._parent_info(parent_tree, file_id)
 
671
            assert None not in new_parents
 
672
            new_rows.append((entry, new_parents))
 
673
        # get additional ids that are present in parents and not in this tree.
 
674
        deleted_ids = set()
 
675
        for tree in parent_trees:
 
676
            deleted_ids.update(set(tree.inventory._byid).difference(checked_ids))
 
677
        # add the deleted ids to the dirstate. deleted files are represented as
 
678
        # a file with dirname '', basename ''
 
679
        for file_id in deleted_ids:
 
680
            # add these ids to the deleted block
 
681
            checked_ids.add(file_id)
 
682
            # deleted items have a synthetic entry.
 
683
            entry = ('/', 'RECYCLED.BIN', 'file', file_id.encode('utf8'), 0,
 
684
                DirState.NULLSTAT, '')
 
685
            new_parents = [None] * parent_tree_count
 
686
            for position, parent_tree in enumerate(parent_trees):
 
687
                # revision_utf8, KIND, dirname, basename, size, executable, sha
 
688
                new_parents[position] = self._parent_info(parent_tree, file_id)
 
689
            assert None not in new_parents
 
690
            new_rows.append((entry, new_parents))
 
691
 
 
692
        # sort all the rows
 
693
        new_rows = sorted(new_rows)
 
694
        self._rows_to_current_state(new_rows)
648
695
        self._parents = [rev_id for rev_id, tree in trees]
649
696
        self._ghosts = list(ghosts)
650
697
        self._header_state = DirState.IN_MEMORY_MODIFIED