Rev 5634: Basically works in the case where the dirstate isn't corrupted. in http://bazaar.launchpad.net/~jameinel/bzr/2.4-reset-checkout

John Arbash Meinel john at arbash-meinel.com
Mon Jan 24 22:57:16 UTC 2011


At http://bazaar.launchpad.net/~jameinel/bzr/2.4-reset-checkout

------------------------------------------------------------
revno: 5634
revision-id: john at arbash-meinel.com-20110124225704-h2zdtk0a82q6bgwy
parent: john at arbash-meinel.com-20110124220048-lngdrej3cm8t9eje
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.4-reset-checkout
timestamp: Mon 2011-01-24 16:57:04 -0600
message:
  Basically works in the case where the dirstate isn't corrupted.
-------------- next part --------------
=== modified file 'bzrlib/tests/blackbox/__init__.py'
--- a/bzrlib/tests/blackbox/__init__.py	2010-11-07 16:09:43 +0000
+++ b/bzrlib/tests/blackbox/__init__.py	2011-01-24 22:57:04 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005-2010 Canonical Ltd
+# Copyright (C) 2005-2011 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -99,6 +99,7 @@
                      'test_remove',
                      'test_re_sign',
                      'test_remove_tree',
+                     'test_reset_workingtree',
                      'test_resolve',
                      'test_revert',
                      'test_revno',

=== modified file 'bzrlib/tests/blackbox/test_reset_workingtree.py'
--- a/bzrlib/tests/blackbox/test_reset_workingtree.py	2011-01-24 21:49:59 +0000
+++ b/bzrlib/tests/blackbox/test_reset_workingtree.py	2011-01-24 22:57:04 +0000
@@ -15,10 +15,21 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 
-import os
-
+from bzrlib import (
+    workingtree,
+    )
 from bzrlib.tests import TestCaseWithTransport
-from bzrlib.workingtree import WorkingTree
+
+
+def _get_dirstate_path(tree):
+    """Get the path to the dirstate file."""
+    # This is a bit ugly, but the alternative was hard-coding the path
+    tree.lock_read()
+    try:
+        ds = tree.current_dirstate()
+        return ds._filename
+    finally:
+        tree.unlock()
 
 
 class TestResetWorkingTree(TestCaseWithTransport):
@@ -30,3 +41,19 @@
         tree.commit('first')
         self.run_bzr('reset-workingtree')
 
+    def test_reset_broken_dirstate(self):
+        tree = self.make_branch_and_tree('tree')
+        # This test assumes that the format uses a DirState file, which we then
+        # manually corrupt. If we change the way to get at that dirstate file,
+        # then we can update how this is done
+        self.assertIsNot(None, getattr(tree, 'current_dirstate', None))
+        path = _get_dirstate_path(tree)
+        f = open(path, 'ab')
+        try:
+            f.write('broken-trailing-garbage\n')
+        finally:
+            f.close()
+        self.run_bzr('reset-workingtree')
+        tree = workingtree.WorkingTree.open('tree')
+        # At this point, check should be happy
+        tree.check_state()

=== modified file 'bzrlib/tests/per_workingtree/test_check_state.py'
--- a/bzrlib/tests/per_workingtree/test_check_state.py	2011-01-24 22:00:48 +0000
+++ b/bzrlib/tests/per_workingtree/test_check_state.py	2011-01-24 22:57:04 +0000
@@ -17,15 +17,68 @@
 """Tests for WorkingTree.check_state."""
 
 from bzrlib import (
+    errors,
     tests,
     )
 from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
 
 
-class TestCheckState(TestCaseWithWorkingTree):
+class TestCaseWithState(TestCaseWithWorkingTree):
+
+    def make_tree_with_broken_dirstate(self, path):
+        tree = self.make_branch_and_tree(path)
+        if getattr(tree, 'current_dirstate', None) is None:
+            raise tests.TestNotApplicable(
+                'Only applies to dirstate-based trees')
+        self.break_dirstate(tree)
+        return tree
+
+    def break_dirstate(self, tree):
+        """Write garbage into the dirstate file."""
+        tree.lock_read()
+        try:
+            dirstate = tree.current_dirstate()
+            dirstate_path = dirstate._filename
+            self.failUnlessExists(dirstate_path)
+        finally:
+            tree.unlock()
+        # We have to have the tree unlocked at this point, so we can safely
+        # mutate the state file on all platforms.
+        f = open(dirstate_path, 'ab')
+        try:
+            f.write('garbage-at-end-of-file\n')
+        finally:
+            f.close()
+
+
+class TestCheckState(TestCaseWithState):
 
     def test_check_state(self):
         tree = self.make_branch_and_tree('tree')
         # Everything should be fine with an unmodified tree, no exception
         # should be raised.
         tree.check_state()
+
+    def test_check_broken_dirstate(self):
+        tree = self.make_tree_with_broken_dirstate('tree')
+        self.assertRaises(errors.BzrError, tree.check_state)
+
+
+class TestResetState(TestCaseWithState):
+
+    def test_reset_state_forgets_changes(self):
+        tree = self.make_branch_and_tree('tree')
+        self.build_tree(['tree/foo', 'tree/dir/', 'tree/dir/bar'])
+        tree.add(['foo', 'dir', 'dir/bar'])
+        tree.commit('initial')
+        foo_id = tree.path2id('foo')
+        tree.rename_one('foo', 'baz')
+        self.assertEqual(None, tree.path2id('foo'))
+        self.assertEqual(foo_id, tree.path2id('baz'))
+        tree.reset_state()
+        # After reset, we should have forgotten about the rename, but we won't
+        # have
+        self.assertEqual(foo_id, tree.path2id('foo'))
+        self.assertEqual(None, tree.path2id('baz'))
+        self.failIfExists('tree/foo')
+        self.failUnlessExists('tree/baz')

=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py	2011-01-24 22:00:48 +0000
+++ b/bzrlib/workingtree.py	2011-01-24 22:57:04 +0000
@@ -2675,9 +2675,33 @@
         """
         return
 
-    @needs_tree_write_lock
+    @needs_read_lock
     def check_state(self):
         """Check that the working state is/isn't valid."""
+        check_refs = self._get_check_refs()
+        refs = {}
+        for ref in check_refs:
+            kind, value = ref
+            if kind == 'trees':
+                refs[ref] = self.branch.repository.revision_tree(value)
+        self._check(refs)
+
+    @needs_tree_write_lock
+    def reset_state(self, revision_ids=None):
+        """Reset the state of the working tree.
+
+        This does a hard-reset to a last-known-good state. This is a way to
+        fix if something got corrupted (like the .bzr/checkout/dirstate file)
+        """
+        if revision_ids is None:
+            revision_ids = self.get_parent_ids()
+        if not revision_ids:
+            rt = self.branch.repository.revision_tree(
+                _mod_revision.NULL_REVISION)
+        else:
+            rt = self.branch.repository.revision_tree(revision_ids[0])
+        self._write_inventory(rt.inventory)
+        self.set_parent_ids(revision_ids)
 
     def _get_rules_searcher(self, default_searcher):
         """See Tree._get_rules_searcher."""



More information about the bazaar-commits mailing list