31
31
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
 
32
32
                           ReusingTransform, CantMoveRoot, 
 
33
33
                           PathsNotVersionedError, ExistingLimbo,
 
34
 
                           ImmortalLimbo, LockError)
 
 
34
                           ExistingPendingDeletion, ImmortalLimbo,
 
 
35
                           ImmortalPendingDeletion, LockError)
 
35
36
from bzrlib.osutils import file_kind, has_symlinks, pathjoin
 
36
37
from bzrlib.merge import Merge3Merger
 
37
38
from bzrlib.tests import TestCaseInTempDir, TestSkipped, TestCase
 
38
39
from bzrlib.transform import (TreeTransform, ROOT_PARENT, FinalPaths, 
 
39
40
                              resolve_conflicts, cook_conflicts, 
 
40
41
                              find_interesting, build_tree, get_backup_name,
 
 
42
                              change_entry, _FileMover)
 
44
45
class TestTreeTransform(tests.TestCaseWithTransport):
 
 
64
65
        self.assertRaises(LockError, self.wt.unlock)
 
65
66
        os.rmdir(pathjoin(limbo_name, 'hehe'))
 
66
67
        os.rmdir(limbo_name)
 
 
68
        os.rmdir(deletion_path)
 
67
69
        transform, root = self.get_transform()
 
 
72
    def test_existing_pending_deletion(self):
 
 
73
        transform, root = self.get_transform()
 
 
74
        deletion_path = self._limbodir = urlutils.local_path_from_url(
 
 
75
            transform._tree._control_files.controlfilename('pending-deletion'))
 
 
76
        os.mkdir(pathjoin(deletion_path, 'blocking-directory'))
 
 
77
        self.assertRaises(ImmortalPendingDeletion, transform.apply)
 
 
78
        self.assertRaises(LockError, self.wt.unlock)
 
 
79
        self.assertRaises(ExistingPendingDeletion, self.get_transform)
 
70
81
    def test_build(self):
 
71
82
        transform, root = self.get_transform() 
 
72
83
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
 
 
1338
1349
        self.assertEqual(name, 'name.~1~')
 
1339
1350
        name = get_backup_name(MockEntry(), {'a':['1', '2', '3']}, 'a', tt)
 
1340
1351
        self.assertEqual(name, 'name.~4~')
 
 
1354
class TestFileMover(tests.TestCaseWithTransport):
 
 
1356
    def test_file_mover(self):
 
 
1357
        self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
 
 
1358
        mover = _FileMover()
 
 
1359
        mover.rename('a', 'q')
 
 
1360
        self.failUnlessExists('q')
 
 
1361
        self.failIfExists('a')
 
 
1362
        self.failUnlessExists('q/b')
 
 
1363
        self.failUnlessExists('c')
 
 
1364
        self.failUnlessExists('c/d')
 
 
1366
    def test_pre_delete_rollback(self):
 
 
1367
        self.build_tree(['a/'])
 
 
1368
        mover = _FileMover()
 
 
1369
        mover.pre_delete('a', 'q')
 
 
1370
        self.failUnlessExists('q')
 
 
1371
        self.failIfExists('a')
 
 
1373
        self.failIfExists('q')
 
 
1374
        self.failUnlessExists('a')
 
 
1376
    def test_apply_deletions(self):
 
 
1377
        self.build_tree(['a/', 'b/'])
 
 
1378
        mover = _FileMover()
 
 
1379
        mover.pre_delete('a', 'q')
 
 
1380
        mover.pre_delete('b', 'r')
 
 
1381
        self.failUnlessExists('q')
 
 
1382
        self.failUnlessExists('r')
 
 
1383
        self.failIfExists('a')
 
 
1384
        self.failIfExists('b')
 
 
1385
        mover.apply_deletions()
 
 
1386
        self.failIfExists('q')
 
 
1387
        self.failIfExists('r')
 
 
1388
        self.failIfExists('a')
 
 
1389
        self.failIfExists('b')
 
 
1391
    def test_file_mover_rollback(self):
 
 
1392
        self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
 
 
1393
        mover = _FileMover()
 
 
1394
        mover.rename('c/d', 'c/f')
 
 
1395
        mover.rename('c/e', 'c/d')
 
 
1397
            mover.rename('a', 'c')
 
 
1400
        self.failUnlessExists('a')
 
 
1401
        self.failUnlessExists('c/d')
 
 
1404
class Bogus(Exception):
 
 
1408
class TestTransformRollback(tests.TestCaseWithTransport):
 
 
1410
    class ExceptionFileMover(_FileMover):
 
 
1412
        def __init__(self, bad_source=None, bad_target=None):
 
 
1413
            _FileMover.__init__(self)
 
 
1414
            self.bad_source = bad_source
 
 
1415
            self.bad_target = bad_target
 
 
1417
        def rename(self, source, target):
 
 
1418
            if (self.bad_source is not None and
 
 
1419
                source.endswith(self.bad_source)):
 
 
1421
            elif (self.bad_target is not None and
 
 
1422
                target.endswith(self.bad_target)):
 
 
1425
                _FileMover.rename(self, source, target)
 
 
1427
    def test_rollback_rename(self):
 
 
1428
        tree = self.make_branch_and_tree('.')
 
 
1429
        self.build_tree(['a/', 'a/b'])
 
 
1430
        tt = TreeTransform(tree)
 
 
1431
        self.addCleanup(tt.finalize)
 
 
1432
        a_id = tt.trans_id_tree_path('a')
 
 
1433
        tt.adjust_path('c', tt.root, a_id)
 
 
1434
        tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
 
 
1435
        self.assertRaises(Bogus, tt.apply,
 
 
1436
                          _mover=self.ExceptionFileMover(bad_source='a'))
 
 
1437
        self.failUnlessExists('a')
 
 
1438
        self.failUnlessExists('a/b')
 
 
1440
        self.failUnlessExists('c')
 
 
1441
        self.failUnlessExists('c/d')
 
 
1443
    def test_rollback_rename_into_place(self):
 
 
1444
        tree = self.make_branch_and_tree('.')
 
 
1445
        self.build_tree(['a/', 'a/b'])
 
 
1446
        tt = TreeTransform(tree)
 
 
1447
        self.addCleanup(tt.finalize)
 
 
1448
        a_id = tt.trans_id_tree_path('a')
 
 
1449
        tt.adjust_path('c', tt.root, a_id)
 
 
1450
        tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
 
 
1451
        self.assertRaises(Bogus, tt.apply,
 
 
1452
                          _mover=self.ExceptionFileMover(bad_target='c/d'))
 
 
1453
        self.failUnlessExists('a')
 
 
1454
        self.failUnlessExists('a/b')
 
 
1456
        self.failUnlessExists('c')
 
 
1457
        self.failUnlessExists('c/d')
 
 
1459
    def test_rollback_deletion(self):
 
 
1460
        tree = self.make_branch_and_tree('.')
 
 
1461
        self.build_tree(['a/', 'a/b'])
 
 
1462
        tt = TreeTransform(tree)
 
 
1463
        self.addCleanup(tt.finalize)
 
 
1464
        a_id = tt.trans_id_tree_path('a')
 
 
1465
        tt.delete_contents(a_id)
 
 
1466
        tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
 
 
1467
        self.assertRaises(Bogus, tt.apply,
 
 
1468
                          _mover=self.ExceptionFileMover(bad_target='d'))
 
 
1469
        self.failUnlessExists('a')
 
 
1470
        self.failUnlessExists('a/b')