~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/dirstate.py

(jameinel) Fix bug #781168,
 and allow WT.update_basis_by_delta to not require the delta makes the basis
 match the current state. (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1326
1326
            raise
1327
1327
        return result
1328
1328
 
 
1329
    def _check_delta_is_valid(self, delta):
 
1330
        return list(inventory._check_delta_unique_ids(
 
1331
                    inventory._check_delta_unique_old_paths(
 
1332
                    inventory._check_delta_unique_new_paths(
 
1333
                    inventory._check_delta_ids_match_entry(
 
1334
                    inventory._check_delta_ids_are_valid(
 
1335
                    inventory._check_delta_new_path_entry_both_or_None(delta)))))))
 
1336
 
1329
1337
    def update_by_delta(self, delta):
1330
1338
        """Apply an inventory delta to the dirstate for tree 0
1331
1339
 
1349
1357
        new_ids = set()
1350
1358
        # This loop transforms the delta to single atomic operations that can
1351
1359
        # be executed and validated.
1352
 
        for old_path, new_path, file_id, inv_entry in sorted(
1353
 
            inventory._check_delta_unique_old_paths(
1354
 
            inventory._check_delta_unique_new_paths(
1355
 
            inventory._check_delta_ids_match_entry(
1356
 
            inventory._check_delta_ids_are_valid(
1357
 
            inventory._check_delta_new_path_entry_both_or_None(delta))))),
1358
 
            reverse=True):
 
1360
        delta = sorted(self._check_delta_is_valid(delta), reverse=True)
 
1361
        for old_path, new_path, file_id, inv_entry in delta:
1359
1362
            if (file_id in insertions) or (file_id in removals):
1360
1363
                raise errors.InconsistentDelta(old_path or new_path, file_id,
1361
1364
                    "repeated file_id")
1475
1478
        Note that an exception during the operation of this method will leave
1476
1479
        the dirstate in a corrupt state where it should not be saved.
1477
1480
 
1478
 
        Finally, we expect all changes to be synchronising the basis tree with
1479
 
        the working tree.
1480
 
 
1481
1481
        :param new_revid: The new revision id for the trees parent.
1482
1482
        :param delta: An inventory delta (see apply_inventory_delta) describing
1483
1483
            the changes from the current left most parent revision to new_revid.
1495
1495
 
1496
1496
        self._parents[0] = new_revid
1497
1497
 
1498
 
        delta = sorted(delta, reverse=True)
 
1498
        delta = sorted(self._check_delta_is_valid(delta), reverse=True)
1499
1499
        adds = []
1500
1500
        changes = []
1501
1501
        deletes = []
1653
1653
        for old_path, new_path, file_id, new_details, real_add in adds:
1654
1654
            # the entry for this file_id must be in tree 0.
1655
1655
            entry = self._get_entry(0, file_id, new_path)
1656
 
            if entry[0] is None or entry[0][2] != file_id:
 
1656
            if entry[0] is None:
 
1657
                # new_path is not versioned in the active WT state,
 
1658
                # but we are adding it to the basis tree state, we
 
1659
                # need to create a new entry record for it.
 
1660
                dirname, basename = osutils.split(new_path)
 
1661
                entry_key = (dirname, basename, file_id)
 
1662
                _, block = self._find_block(entry_key, add_if_missing=True)
 
1663
                index, _ = self._find_entry_index(entry_key, block)
 
1664
                entry = (entry_key, [DirState.NULL_PARENT_DETAILS]*2)
 
1665
                block.insert(index, entry)
 
1666
            elif entry[0][2] != file_id:
1657
1667
                self._changes_aborted = True
1658
1668
                raise errors.InconsistentDelta(new_path, file_id,
1659
1669
                    'working tree does not contain new entry')
1719
1729
                raise errors.InconsistentDelta(old_path, file_id,
1720
1730
                    'mismatched file_id in tree 1')
1721
1731
            if real_delete:
1722
 
                if entry[1][0][0] != 'a':
1723
 
                    self._changes_aborted = True
1724
 
                    raise errors.InconsistentDelta(old_path, file_id,
1725
 
                            'This was marked as a real delete, but the WT state'
1726
 
                            ' claims that it still exists and is versioned.')
1727
 
                del self._dirblocks[block_index][1][entry_index]
 
1732
                if entry[1][0][0] == 'a':
 
1733
                    # The file was marked as deleted in the active
 
1734
                    # state, and it is now deleted in the basis state,
 
1735
                    # so just remove the record entirely
 
1736
                    del self._dirblocks[block_index][1][entry_index]
 
1737
                else:
 
1738
                    # The basis entry needs to be marked deleted
 
1739
                    entry[1][1] = null
 
1740
                # If we are deleting a directory, we need to make sure
 
1741
                # that all of its children are already deleted
 
1742
                block_i, entry_i, d_present, f_present = \
 
1743
                    self._get_block_entry_index(old_path, '', 0)
 
1744
                if d_present:
 
1745
                    # The dir block is still present in the dirstate; this could
 
1746
                    # be due to it being in a parent tree, or a corrupt delta.
 
1747
                    for child_entry in self._dirblocks[block_i][1]:
 
1748
                        if child_entry[1][1][0] not in ('r', 'a'):
 
1749
                            self._changes_aborted = True
 
1750
                            raise errors.InconsistentDelta(old_path, entry[0][2],
 
1751
                                "The file id was deleted but its children were "
 
1752
                                "not deleted.")
1728
1753
            else:
1729
1754
                if entry[1][0][0] == 'a':
1730
1755
                    self._changes_aborted = True
1740
1765
                    del self._dirblocks[block_index][1][entry_index]
1741
1766
                else:
1742
1767
                    # it is being resurrected here, so blank it out temporarily.
 
1768
                    # should be equivalent to entry[1][1] = null
1743
1769
                    self._dirblocks[block_index][1][entry_index][1][1] = null
1744
1770
 
1745
1771
    def _after_delta_check_parents(self, parents, index):