~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: Danny van Heumen
  • Date: 2010-03-09 16:38:10 UTC
  • mto: (4634.139.5 2.0)
  • mto: This revision was merged to the branch mainline in revision 5160.
  • Revision ID: danny@dannyvanheumen.nl-20100309163810-ujn8hcx08f75nlf1
Refined test to make use of locking hooks and also validate if lock is truly a checkout-lock.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
 
18
import stat
18
19
from StringIO import StringIO
19
20
import sys
20
 
import time
21
21
 
22
22
from bzrlib import (
23
23
    bencode,
24
24
    errors,
25
 
    filters,
26
25
    generate_ids,
27
26
    osutils,
 
27
    progress,
28
28
    revision as _mod_revision,
29
 
    rules,
 
29
    symbol_versioning,
30
30
    tests,
31
31
    urlutils,
32
32
    )
33
33
from bzrlib.bzrdir import BzrDir
34
 
from bzrlib.conflicts import (
35
 
    DeletingParent,
36
 
    DuplicateEntry,
37
 
    DuplicateID,
38
 
    MissingParent,
39
 
    NonDirectoryParent,
40
 
    ParentLoop,
41
 
    UnversionedParent,
42
 
)
 
34
from bzrlib.conflicts import (DuplicateEntry, DuplicateID, MissingParent,
 
35
                              UnversionedParent, ParentLoop, DeletingParent,
 
36
                              NonDirectoryParent)
43
37
from bzrlib.diff import show_diff_trees
44
 
from bzrlib.errors import (
45
 
    DuplicateKey,
46
 
    ExistingLimbo,
47
 
    ExistingPendingDeletion,
48
 
    ImmortalLimbo,
49
 
    ImmortalPendingDeletion,
50
 
    LockError,
51
 
    MalformedTransform,
52
 
    NoSuchFile,
53
 
    ReusingTransform,
54
 
)
55
 
from bzrlib.osutils import (
56
 
    file_kind,
57
 
    pathjoin,
58
 
)
 
38
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
 
39
                           ReusingTransform, CantMoveRoot,
 
40
                           PathsNotVersionedError, ExistingLimbo,
 
41
                           ExistingPendingDeletion, ImmortalLimbo,
 
42
                           ImmortalPendingDeletion, LockError)
 
43
from bzrlib.osutils import file_kind, pathjoin
59
44
from bzrlib.merge import Merge3Merger, Merger
60
45
from bzrlib.tests import (
61
46
    HardlinkFeature,
63
48
    TestCase,
64
49
    TestCaseInTempDir,
65
50
    TestSkipped,
66
 
)
67
 
from bzrlib.transform import (
68
 
    build_tree,
69
 
    create_from_tree,
70
 
    cook_conflicts,
71
 
    _FileMover,
72
 
    FinalPaths,
73
 
    get_backup_name,
74
 
    resolve_conflicts,
75
 
    resolve_checkout,
76
 
    ROOT_PARENT,
77
 
    TransformPreview,
78
 
    TreeTransform,
79
 
)
 
51
    )
 
52
from bzrlib.transform import (TreeTransform, ROOT_PARENT, FinalPaths,
 
53
                              resolve_conflicts, cook_conflicts,
 
54
                              build_tree, get_backup_name,
 
55
                              _FileMover, resolve_checkout,
 
56
                              TransformPreview, create_from_tree)
80
57
 
81
58
 
82
59
class TestTreeTransform(tests.TestCaseWithTransport):
159
136
        transform.finalize()
160
137
        transform.finalize()
161
138
 
162
 
    def test_create_files_same_timestamp(self):
163
 
        transform, root = self.get_transform()
164
 
        self.wt.lock_tree_write()
165
 
        self.addCleanup(self.wt.unlock)
166
 
        # Roll back the clock, so that we know everything is being set to the
167
 
        # exact time
168
 
        transform._creation_mtime = creation_mtime = time.time() - 20.0
169
 
        transform.create_file('content-one',
170
 
                              transform.create_path('one', root))
171
 
        time.sleep(1) # *ugly*
172
 
        transform.create_file('content-two',
173
 
                              transform.create_path('two', root))
174
 
        transform.apply()
175
 
        fo, st1 = self.wt.get_file_with_stat(None, path='one', filtered=False)
176
 
        fo.close()
177
 
        fo, st2 = self.wt.get_file_with_stat(None, path='two', filtered=False)
178
 
        fo.close()
179
 
        # We only guarantee 2s resolution
180
 
        self.assertTrue(abs(creation_mtime - st1.st_mtime) < 2.0,
181
 
            "%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
182
 
        # But if we have more than that, all files should get the same result
183
 
        self.assertEqual(st1.st_mtime, st2.st_mtime)
184
 
 
185
139
    def test_change_root_id(self):
186
140
        transform, root = self.get_transform()
187
141
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
445
399
        self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
446
400
        self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
447
401
 
448
 
    def test_adjust_path_updates_child_limbo_names(self):
449
 
        tree = self.make_branch_and_tree('tree')
450
 
        transform = TreeTransform(tree)
451
 
        self.addCleanup(transform.finalize)
452
 
        foo_id = transform.new_directory('foo', transform.root)
453
 
        bar_id = transform.new_directory('bar', foo_id)
454
 
        baz_id = transform.new_directory('baz', bar_id)
455
 
        qux_id = transform.new_directory('qux', baz_id)
456
 
        transform.adjust_path('quxx', foo_id, bar_id)
457
 
        self.assertStartsWith(transform._limbo_name(qux_id),
458
 
                              transform._limbo_name(bar_id))
459
 
 
460
402
    def test_add_del(self):
461
403
        start, root = self.get_transform()
462
404
        start.new_directory('a', root, 'a')
757
699
                                         ' versioned, but has versioned'
758
700
                                         ' children.  Versioned directory.')
759
701
        self.assertEqual(conflicts_s[6], 'Conflict moving oz/emeraldcity into'
760
 
                                         ' oz/emeraldcity. Cancelled move.')
 
702
                                         ' oz/emeraldcity.  Cancelled move.')
761
703
 
762
704
    def prepare_wrong_parent_kind(self):
763
705
        tt, root = self.get_transform()
852
794
        rename.set_executability(True, myfile)
853
795
        rename.apply()
854
796
 
855
 
    def test_rename_fails(self):
856
 
        # see https://bugs.launchpad.net/bzr/+bug/491763
857
 
        create, root_id = self.get_transform()
858
 
        first_dir = create.new_directory('first-dir', root_id, 'first-id')
859
 
        myfile = create.new_file('myfile', root_id, 'myfile-text',
860
 
                                 'myfile-id')
861
 
        create.apply()
862
 
        if os.name == "posix" and sys.platform != "cygwin":
863
 
            # posix filesystems fail on renaming if the readonly bit is set
864
 
            osutils.make_readonly(self.wt.abspath('first-dir'))
865
 
        elif os.name == "nt":
866
 
            # windows filesystems fail on renaming open files
867
 
            self.addCleanup(file(self.wt.abspath('myfile')).close)
868
 
        else:
869
 
            self.skip("Don't know how to force a permissions error on rename")
870
 
        # now transform to rename
871
 
        rename_transform, root_id = self.get_transform()
872
 
        file_trans_id = rename_transform.trans_id_file_id('myfile-id')
873
 
        dir_id = rename_transform.trans_id_file_id('first-id')
874
 
        rename_transform.adjust_path('newname', dir_id, file_trans_id)
875
 
        e = self.assertRaises(errors.TransformRenameFailed,
876
 
            rename_transform.apply)
877
 
        # On nix looks like: 
878
 
        # "Failed to rename .../work/.bzr/checkout/limbo/new-1
879
 
        # to .../first-dir/newname: [Errno 13] Permission denied"
880
 
        # On windows looks like:
881
 
        # "Failed to rename .../work/myfile to 
882
 
        # .../work/.bzr/checkout/limbo/new-1: [Errno 13] Permission denied"
883
 
        # The strerror will vary per OS and language so it's not checked here
884
 
        self.assertContainsRe(str(e),
885
 
            "Failed to rename .*(first-dir.newname:|myfile)")
886
 
 
887
797
    def test_set_executability_order(self):
888
798
        """Ensure that executability behaves the same, no matter what order.
889
799
 
1976
1886
        self.assertEqual([], list(target.iter_changes(revision_tree)))
1977
1887
        self.assertTrue(source.is_executable('file1-id'))
1978
1888
 
1979
 
    def install_rot13_content_filter(self, pattern):
1980
 
        # We could use
1981
 
        # self.addCleanup(filters._reset_registry, filters._reset_registry())
1982
 
        # below, but that looks a bit... hard to read even if it's exactly
1983
 
        # the same thing.
1984
 
        original_registry = filters._reset_registry()
1985
 
        def restore_registry():
1986
 
            filters._reset_registry(original_registry)
1987
 
        self.addCleanup(restore_registry)
1988
 
        def rot13(chunks, context=None):
1989
 
            return [''.join(chunks).encode('rot13')]
1990
 
        rot13filter = filters.ContentFilter(rot13, rot13)
1991
 
        filters.register_filter_stack_map('rot13', {'yes': [rot13filter]}.get)
1992
 
        os.mkdir(self.test_home_dir + '/.bazaar')
1993
 
        rules_filename = self.test_home_dir + '/.bazaar/rules'
1994
 
        f = open(rules_filename, 'wb')
1995
 
        f.write('[name %s]\nrot13=yes\n' % (pattern,))
1996
 
        f.close()
1997
 
        def uninstall_rules():
1998
 
            os.remove(rules_filename)
1999
 
            rules.reset_rules()
2000
 
        self.addCleanup(uninstall_rules)
2001
 
        rules.reset_rules()
2002
 
 
2003
 
    def test_build_tree_content_filtered_files_are_not_hardlinked(self):
2004
 
        """build_tree will not hardlink files that have content filtering rules
2005
 
        applied to them (but will still hardlink other files from the same tree
2006
 
        if it can).
2007
 
        """
2008
 
        self.requireFeature(HardlinkFeature)
2009
 
        self.install_rot13_content_filter('file1')
2010
 
        source = self.create_ab_tree()
2011
 
        target = self.make_branch_and_tree('target')
2012
 
        revision_tree = source.basis_tree()
2013
 
        revision_tree.lock_read()
2014
 
        self.addCleanup(revision_tree.unlock)
2015
 
        build_tree(revision_tree, target, source, hardlink=True)
2016
 
        target.lock_read()
2017
 
        self.addCleanup(target.unlock)
2018
 
        self.assertEqual([], list(target.iter_changes(revision_tree)))
2019
 
        source_stat = os.stat('source/file1')
2020
 
        target_stat = os.stat('target/file1')
2021
 
        self.assertNotEqual(source_stat, target_stat)
2022
 
        source_stat = os.stat('source/file2')
2023
 
        target_stat = os.stat('target/file2')
2024
 
        self.assertEqualStat(source_stat, target_stat)
2025
 
 
2026
1889
    def test_case_insensitive_build_tree_inventory(self):
2027
1890
        if (tests.CaseInsensitiveFilesystemFeature.available()
2028
1891
            or tests.CaseInsCasePresFilenameFeature.available()):
2083
1946
        branch.lock_write()
2084
1947
        self.addCleanup(branch.unlock)
2085
1948
        tt = TransformPreview(branch.basis_tree())
2086
 
        self.addCleanup(tt.finalize)
2087
1949
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
2088
1950
        rev = tt.commit(branch, 'my message')
2089
1951
        self.assertEqual([], branch.basis_tree().get_parent_ids())
2095
1957
        branch.lock_write()
2096
1958
        self.addCleanup(branch.unlock)
2097
1959
        tt = TransformPreview(branch.basis_tree())
2098
 
        self.addCleanup(tt.finalize)
2099
1960
        e = self.assertRaises(ValueError, tt.commit, branch,
2100
1961
                          'my message', ['rev1b-id'])
2101
1962
        self.assertEqual('Cannot supply merge parents for first commit.',
2106
1967
        branch, tt = self.get_branch_and_transform()
2107
1968
        tt.new_file('file', tt.root, 'contents', 'file-id')
2108
1969
        trans_id = tt.new_directory('dir', tt.root, 'dir-id')
2109
 
        if SymlinkFeature.available():
2110
 
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
 
1970
        tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
2111
1971
        rev = tt.commit(branch, 'message')
2112
1972
        tree = branch.basis_tree()
2113
1973
        self.assertEqual('file', tree.id2path('file-id'))
2114
1974
        self.assertEqual('contents', tree.get_file_text('file-id'))
2115
1975
        self.assertEqual('dir', tree.id2path('dir-id'))
2116
 
        if SymlinkFeature.available():
2117
 
            self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
2118
 
            self.assertEqual('target', tree.get_symlink_target('symlink-id'))
 
1976
        self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
 
1977
        self.assertEqual('target', tree.get_symlink_target('symlink-id'))
2119
1978
 
2120
1979
    def test_add_unversioned(self):
2121
1980
        branch, tt = self.get_branch_and_transform()
2128
1987
        tt.new_file('file', tt.root, 'contents', 'file-id')
2129
1988
        tt.commit(branch, 'message', strict=True)
2130
1989
        tt = TransformPreview(branch.basis_tree())
2131
 
        self.addCleanup(tt.finalize)
2132
1990
        trans_id = tt.trans_id_file_id('file-id')
2133
1991
        tt.delete_contents(trans_id)
2134
1992
        tt.create_file('contents', trans_id)
2145
2003
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
2146
2004
                          'message')
2147
2005
 
2148
 
    def test_commit_rich_revision_data(self):
2149
 
        branch, tt = self.get_branch_and_transform()
2150
 
        rev_id = tt.commit(branch, 'message', timestamp=1, timezone=43201,
2151
 
                           committer='me <me@example.com>',
2152
 
                           revprops={'foo': 'bar'}, revision_id='revid-1',
2153
 
                           authors=['Author1 <author1@example.com>',
2154
 
                              'Author2 <author2@example.com>',
2155
 
                               ])
2156
 
        self.assertEqual('revid-1', rev_id)
2157
 
        revision = branch.repository.get_revision(rev_id)
2158
 
        self.assertEqual(1, revision.timestamp)
2159
 
        self.assertEqual(43201, revision.timezone)
2160
 
        self.assertEqual('me <me@example.com>', revision.committer)
2161
 
        self.assertEqual(['Author1 <author1@example.com>',
2162
 
                          'Author2 <author2@example.com>'],
2163
 
                         revision.get_apparent_authors())
2164
 
        del revision.properties['authors']
2165
 
        self.assertEqual({'foo': 'bar',
2166
 
                          'branch-nick': 'tree'},
2167
 
                         revision.properties)
2168
 
 
2169
 
    def test_no_explicit_revprops(self):
2170
 
        branch, tt = self.get_branch_and_transform()
2171
 
        rev_id = tt.commit(branch, 'message', authors=[
2172
 
            'Author1 <author1@example.com>',
2173
 
            'Author2 <author2@example.com>', ])
2174
 
        revision = branch.repository.get_revision(rev_id)
2175
 
        self.assertEqual(['Author1 <author1@example.com>',
2176
 
                          'Author2 <author2@example.com>'],
2177
 
                         revision.get_apparent_authors())
2178
 
        self.assertEqual('tree', revision.properties['branch-nick'])
2179
 
 
2180
2006
 
2181
2007
class MockTransform(object):
2182
2008
 
2457
2283
    def test_ignore_pb(self):
2458
2284
        # pb could be supported, but TT.iter_changes doesn't support it.
2459
2285
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2460
 
        preview_tree.iter_changes(revision_tree)
 
2286
        preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
2461
2287
 
2462
2288
    def test_kind(self):
2463
2289
        revision_tree = self.create_tree()
2478
2304
        self.assertEqual(os.stat(limbo_path).st_mtime,
2479
2305
                         preview_tree.get_file_mtime('file-id'))
2480
2306
 
2481
 
    def test_get_file_mtime_renamed(self):
2482
 
        work_tree = self.make_branch_and_tree('tree')
2483
 
        self.build_tree(['tree/file'])
2484
 
        work_tree.add('file', 'file-id')
2485
 
        preview = TransformPreview(work_tree)
2486
 
        self.addCleanup(preview.finalize)
2487
 
        file_trans_id = preview.trans_id_tree_file_id('file-id')
2488
 
        preview.adjust_path('renamed', preview.root, file_trans_id)
2489
 
        preview_tree = preview.get_preview_tree()
2490
 
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
2491
 
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
2492
 
 
2493
2307
    def test_get_file(self):
2494
2308
        preview = self.get_empty_preview()
2495
2309
        preview.new_file('file', preview.root, 'contents', 'file-id')
2643
2457
        self.assertEqual(('missing', None, None, None), summary)
2644
2458
 
2645
2459
    def test_file_content_summary_executable(self):
 
2460
        if not osutils.supports_executable():
 
2461
            raise tests.TestNotApplicable()
2646
2462
        preview = self.get_empty_preview()
2647
2463
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2648
2464
        preview.set_executability(True, path_id)
2676
2492
        # size must be known
2677
2493
        self.assertEqual(len('contents'), summary[1])
2678
2494
        # not executable
2679
 
        self.assertEqual(False, summary[2])
 
2495
        if osutils.supports_executable():
 
2496
            self.assertEqual(False, summary[2])
 
2497
        else:
 
2498
            self.assertEqual(None, summary[2])
2680
2499
        # will not have hash (not cheap to determine)
2681
2500
        self.assertIs(None, summary[3])
2682
2501
 
2865
2684
        file_trans_id = preview.trans_id_file_id('file-id')
2866
2685
        preview.delete_contents(file_trans_id)
2867
2686
        preview.create_file('a\nb\n', file_trans_id)
 
2687
        pb = progress.DummyProgress()
2868
2688
        preview_tree = preview.get_preview_tree()
2869
 
        merger = Merger.from_revision_ids(None, preview_tree,
 
2689
        merger = Merger.from_revision_ids(pb, preview_tree,
2870
2690
                                          child_tree.branch.last_revision(),
2871
2691
                                          other_branch=child_tree.branch,
2872
2692
                                          tree_branch=work_tree.branch)
2884
2704
        tt.new_file('name', tt.root, 'content', 'file-id')
2885
2705
        tree2 = self.make_branch_and_tree('tree2')
2886
2706
        tree2.set_root_id('TREE_ROOT')
 
2707
        pb = progress.DummyProgress()
2887
2708
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2888
 
                                         None, tree.basis_tree())
 
2709
                                         pb, tree.basis_tree())
2889
2710
        merger.merge_type = Merge3Merger
2890
2711
        merger.do_merge()
2891
2712
 
2901
2722
        tt.create_file('baz', trans_id)
2902
2723
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2903
2724
        self.build_tree_contents([('tree2/foo', 'qux')])
2904
 
        pb = None
 
2725
        pb = progress.DummyProgress()
2905
2726
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2906
2727
                                         pb, tree.basis_tree())
2907
2728
        merger.merge_type = Merge3Merger
2939
2760
        branch = self.make_branch('any')
2940
2761
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
2941
2762
        tt = TransformPreview(tree)
2942
 
        self.addCleanup(tt.finalize)
2943
2763
        foo_id = tt.new_directory('', ROOT_PARENT)
2944
2764
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
2945
2765
        limbo_path = tt._limbo_name(bar_id)