Rev 2348: Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked. in sftp://bazaar.launchpad.net/%7Ebzr/bzr/dirstate/

Robert Collins robertc at robertcollins.net
Wed Feb 21 01:09:17 GMT 2007


At sftp://bazaar.launchpad.net/%7Ebzr/bzr/dirstate/

------------------------------------------------------------
revno: 2348
revision-id: robertc at robertcollins.net-20070221010813-zn13zy3wzd53i3vz
parent: jw+debian at jameswestby.net-20070220222431-t4esb34p4zxqcqxm
committer: Robert Collins <robertc at robertcollins.net>
branch nick: dirstate
timestamp: Wed 2007-02-21 12:08:13 +1100
message:
  Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
modified:
  bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
=== modified file 'bzrlib/dirstate.py'
--- a/bzrlib/dirstate.py	2007-02-20 22:20:24 +0000
+++ b/bzrlib/dirstate.py	2007-02-21 01:08:13 +0000
@@ -340,6 +340,7 @@
 
     def add_deleted(self, fileid_utf8, parents):
         """Add fileid_utf8 with parents as deleted."""
+        raise Exception, "broken"
         self._read_dirblocks_if_needed()
         new_row = self._make_deleted_row(fileid_utf8, parents)
         block_index = self._find_dirblock_index(new_row[0][0])
@@ -443,7 +444,7 @@
         :return: The block tuple.
         """
         if key[0:2] == ('', ''):
-            return self._root_entries
+            return ('', self._root_entries)
         else:
             block_index, present = self._find_block_index_from_key(key)
             if not present:
@@ -1221,7 +1222,7 @@
                 current_new = advance(new_iterator)
             elif not current_new:
                 # new is finished
-                self._make_absent(num_present_parents, current_old, id_index)
+                self._make_absent(current_old, id_index)
                 current_old = advance(old_iterator)
             elif new_entry_key == current_old[0]:
                 # same -  common case
@@ -1246,47 +1247,58 @@
                 current_new = advance(new_iterator)
             else:
                 # old comes before:
-                self._make_absent(num_present_parents, current_old, id_index)
+                self._make_absent(current_old, id_index)
                 current_old = advance(old_iterator)
         self._dirblock_state = DirState.IN_MEMORY_MODIFIED
 
-    def _make_absent(self, num_present_parents, current_old, id_index):
-        # remove old from the state, advance old
-        # to remove old, we have two conditions:
-        # either its the last reference to this path that we are
-        # removing, or its not. If its the last reference, we remove
-        # the entire row and remove the path from the id mapping. If
-        # its not the last reference, we just set it to absent.
-        last_reference = True
-        for lookup_index in xrange(1, num_present_parents + 1):
-            if current_old[1][lookup_index] not in ('absent', 'relocated'):
-                last_reference = False
-                break
-        if not last_reference:
-            # common case, theres a parent at this path
-            current_old[1][0] = DirState.NULL_PARENT_DETAILS
-        else:
-            # there are no more references at this path
-            id_index[current_old[0][2]].remove(current_old[0])
-            # are there others (which will need to be changed
-            # from relocated to absent for index 0)?
-            for update_key in id_index[current_old[0][2]]:
-                # update the entry for 0 to say absent: there is a parent at
-                # that path, but nothing in this tree for that file id anymore.
-                update_block_index, present = \
-                    self._find_block_index_from_key(update_key)
-                assert present
-                update_entry_index, present = \
-                    self._find_entry_index(update_key, self._dirblocks[update_block_index][1])
-                assert present
-                update_tree_details = self._dirblocks[update_block_index][1][update_entry_index][1]
-                # it must currently be relocated
-                assert update_tree_details[0][0] == 'relocated'
-                update_tree_details[0] = DirState.NULL_PARENT_DETAILS
+    def _make_absent(self, current_old, id_index=None):
+        """Mark current_old - an entry - as absent for tree 0.
+
+        :param id_index: An index from fileid_utf8 to sets of keys, used by
+            some functions. If provided it will be updated if needed.
+        :return: True if this was the last details entry for they entry key:
+            that is, if the underlying block has had the entry removed, thus
+            shrinking in legnth.
+        """
+        # build up paths that this id will be left at after the change is made,
+        # so we can update their cross references in tree 0
+        all_remaining_keys = set()
+        # Dont check the working tree, because its going.
+        for details in current_old[1][1:]:
+            if details[0] not in ('absent', 'relocated'):
+                all_remaining_keys.add(current_old[0])
+            elif details[0] == 'relocated':
+                # record the key for the real path.
+                all_remaining_keys.add(tuple(os.path.split(details[1])) + tuple(current_old[0][2]))
+            # absent rows are not present at any path.
+        last_reference = current_old[0] not in all_remaining_keys
+        if last_reference:
+            # the current row consists entire of the current item (being marked
+            # absent), and relocated or absent entries for the other trees:
+            # Remove it, its meaningless.
             block = self._find_block(current_old[0])
             entry_index, present = self._find_entry_index(current_old[0], block[1])
             assert present
             block[1].pop(entry_index)
+            # if we have an id_index in use, remove this key from it for this id.
+            if id_index is not None:
+                id_index[current_old[0][2]].remove(current_old[0])
+        # update all remaining keys for this id to record it as absent. The
+        # existing details may either be the record we are making as deleted
+        # (if there were other trees with the id present at this path), or may
+        # be relocations.
+        for update_key in all_remaining_keys:
+            update_block_index, present = \
+                self._find_block_index_from_key(update_key)
+            assert present
+            update_entry_index, present = \
+                self._find_entry_index(update_key, self._dirblocks[update_block_index][1])
+            assert present
+            update_tree_details = self._dirblocks[update_block_index][1][update_entry_index][1]
+            # it must not be absent at the moment
+            assert update_tree_details[0][0] != 'absent'
+            update_tree_details[0] = DirState.NULL_PARENT_DETAILS
+        return last_reference
 
     def update_minimal(self, key, kind, num_present_parents, executable=False,
         fingerprint='', packed_stat=None, size=0, id_index=None,

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-02-20 22:24:31 +0000
+++ b/bzrlib/workingtree_4.py	2007-02-21 01:08:13 +0000
@@ -660,51 +660,60 @@
         paths_to_unversion = set()
         # sketch:
         # check if the root is to be unversioned, if so, assert for now.
-        # make a copy of the _dirblocks data
-        # during the copy,
-        #  skip paths in paths_to_unversion
-        #  skip ids in ids_to_unversion, and add their paths to
-        #  paths_to_unversion if they are a directory
+        # walk the state marking unversioned things as absent.
         # if there are any un-unversioned ids at the end, raise
-        if state._root_row[0][3] in ids_to_unversion:
-            # I haven't written the code to unversion / yet - it should be
-            # supported.
-            raise errors.BzrError('Unversioning the / is not currently supported')
-        new_blocks = []
-        deleted_rows = []
-        for block in state._dirblocks:
+        for key, details in state._root_entries:
+            if (details[0][0] not in ('absent', 'relocated') and
+                key[2] in ids_to_unversion):
+                # I haven't written the code to unversion / yet - it should be
+                # supported.
+                raise errors.BzrError('Unversioning the / is not currently supported')
+        details_length = len(state._root_entries[0][1])
+        block_index = 0
+        while block_index < len(state._dirblocks):
+            # process one directory at a time.
+            block = state._dirblocks[block_index]
             # first check: is the path one to remove - it or its children
             delete_block = False
             for path in paths_to_unversion:
                 if (block[0].startswith(path) and
                     (len(block[0]) == len(path) or
                      block[0][len(path)] == '/')):
-                    # this path should be deleted
+                    # this entire block should be deleted - its the block for a
+                    # path to unversion; or the child of one
                     delete_block = True
                     break
             # TODO: trim paths_to_unversion as we pass by paths
             if delete_block:
-                # this block is to be deleted. skip it.
+                # this block is to be deleted: process it.
+                # TODO: we can special case the no-parents case and
+                # just forget the whole block.
+                entry_index = 0
+                while entry_index < len(block[1]):
+                    if not state._make_absent(block[1][entry_index]):
+                        entry_index += 1
+                # go to the next block. (At the moment we dont delete empty
+                # dirblocks)
+                block_index += 1
                 continue
-            # copy undeleted rows from within the the block
-            new_blocks.append((block[0], []))
-            new_row = new_blocks[-1][1]
-            for row, row_parents in block[1]:
-                if row[3] not in ids_to_unversion:
-                    new_row.append((row, row_parents))
-                else:
-                    # skip the row, and if its a dir mark its path to be removed
-                    if row[2] == 'directory':
-                        paths_to_unversion.add((row[0] + '/' + row[1]).strip('/'))
-                    if row_parents:
-                        deleted_rows.append((row[3], row_parents))
-                    ids_to_unversion.remove(row[3])
+            entry_index = 0
+            while entry_index < len(block[1]):
+                entry = block[1][entry_index]
+                if (entry[1][0][0] in ('absent', 'relocated') or
+                    # ^ some parent row.
+                    entry[0][2] not in ids_to_unversion):
+                    # ^ not an id to unversion
+                    entry_index += 1
+                    continue
+                if entry[1][0][0] == 'directory':
+                    paths_to_unversion.add(os.path.join(*entry[0][0:2]))
+                if not state._make_absent(entry):
+                    entry_index += 1
+                # we have unversioned this id
+                ids_to_unversion.remove(entry[0][2])
+            block_index += 1
         if ids_to_unversion:
             raise errors.NoSuchId(self, iter(ids_to_unversion).next())
-        state._dirblocks = new_blocks
-        for fileid_utf8, parents in deleted_rows:
-            state.add_deleted(fileid_utf8, parents)
-        state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
         self._dirty = True
         # have to change the legacy inventory too.
         if self._inventory is not None:
@@ -869,6 +878,10 @@
                     inv_entry.text_sha1 = link_or_sha1
                 elif kind == 'directory':
                     parent_ids[(dirname + '/' + name).strip('/')] = file_id
+                elif kind == 'symlink':
+                    inv_entry.executable = False
+                    inv_entry.text_size = size
+                    inv_entry.symlink_target = link_or_sha1.decode('utf8')
                 else:
                     raise Exception, kind
                 inv.add(inv_entry)



More information about the bazaar-commits mailing list