~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: Martin Pool
  • Date: 2010-04-01 04:41:18 UTC
  • mto: This revision was merged to the branch mainline in revision 5128.
  • Revision ID: mbp@sourcefrog.net-20100401044118-shyctqc02ob08ngz
ignore .testrepository

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
import stat
19
18
from StringIO import StringIO
20
19
import sys
 
20
import time
21
21
 
22
22
from bzrlib import (
23
23
    bencode,
24
24
    errors,
 
25
    filters,
25
26
    generate_ids,
26
27
    osutils,
27
28
    progress,
28
29
    revision as _mod_revision,
29
 
    symbol_versioning,
 
30
    rules,
30
31
    tests,
31
32
    urlutils,
32
33
    )
136
137
        transform.finalize()
137
138
        transform.finalize()
138
139
 
 
140
    def test_create_files_same_timestamp(self):
 
141
        transform, root = self.get_transform()
 
142
        self.wt.lock_tree_write()
 
143
        self.addCleanup(self.wt.unlock)
 
144
        # Roll back the clock, so that we know everything is being set to the
 
145
        # exact time
 
146
        transform._creation_mtime = creation_mtime = time.time() - 20.0
 
147
        transform.create_file('content-one',
 
148
                              transform.create_path('one', root))
 
149
        time.sleep(1) # *ugly*
 
150
        transform.create_file('content-two',
 
151
                              transform.create_path('two', root))
 
152
        transform.apply()
 
153
        fo, st1 = self.wt.get_file_with_stat(None, path='one', filtered=False)
 
154
        fo.close()
 
155
        fo, st2 = self.wt.get_file_with_stat(None, path='two', filtered=False)
 
156
        fo.close()
 
157
        # We only guarantee 2s resolution
 
158
        self.assertTrue(abs(creation_mtime - st1.st_mtime) < 2.0,
 
159
            "%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
 
160
        # But if we have more than that, all files should get the same result
 
161
        self.assertEqual(st1.st_mtime, st2.st_mtime)
 
162
 
 
163
    def test_change_root_id(self):
 
164
        transform, root = self.get_transform()
 
165
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
 
166
        transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
167
        transform.delete_contents(root)
 
168
        transform.unversion_file(root)
 
169
        transform.fixup_new_roots()
 
170
        transform.apply()
 
171
        self.assertEqual('new-root-id', self.wt.get_root_id())
 
172
 
 
173
    def test_change_root_id_add_files(self):
 
174
        transform, root = self.get_transform()
 
175
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
 
176
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
177
        transform.new_file('file', new_trans_id, ['new-contents\n'],
 
178
                           'new-file-id')
 
179
        transform.delete_contents(root)
 
180
        transform.unversion_file(root)
 
181
        transform.fixup_new_roots()
 
182
        transform.apply()
 
183
        self.assertEqual('new-root-id', self.wt.get_root_id())
 
184
        self.assertEqual('new-file-id', self.wt.path2id('file'))
 
185
        self.assertFileEqual('new-contents\n', self.wt.abspath('file'))
 
186
 
 
187
    def test_add_two_roots(self):
 
188
        transform, root = self.get_transform()
 
189
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
190
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'alt-root-id')
 
191
        self.assertRaises(ValueError, transform.fixup_new_roots)
 
192
 
139
193
    def test_hardlink(self):
140
194
        self.requireFeature(HardlinkFeature)
141
195
        transform, root = self.get_transform()
369
423
        self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
370
424
        self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
371
425
 
 
426
    def test_adjust_path_updates_child_limbo_names(self):
 
427
        tree = self.make_branch_and_tree('tree')
 
428
        transform = TreeTransform(tree)
 
429
        self.addCleanup(transform.finalize)
 
430
        foo_id = transform.new_directory('foo', transform.root)
 
431
        bar_id = transform.new_directory('bar', foo_id)
 
432
        baz_id = transform.new_directory('baz', bar_id)
 
433
        qux_id = transform.new_directory('qux', baz_id)
 
434
        transform.adjust_path('quxx', foo_id, bar_id)
 
435
        self.assertStartsWith(transform._limbo_name(qux_id),
 
436
                              transform._limbo_name(bar_id))
 
437
 
372
438
    def test_add_del(self):
373
439
        start, root = self.get_transform()
374
440
        start.new_directory('a', root, 'a')
669
735
                                         ' versioned, but has versioned'
670
736
                                         ' children.  Versioned directory.')
671
737
        self.assertEqual(conflicts_s[6], 'Conflict moving oz/emeraldcity into'
672
 
                                         ' oz/emeraldcity.  Cancelled move.')
 
738
                                         ' oz/emeraldcity. Cancelled move.')
673
739
 
674
740
    def prepare_wrong_parent_kind(self):
675
741
        tt, root = self.get_transform()
746
812
        create.apply()
747
813
        transform, root = self.get_transform()
748
814
        transform.adjust_root_path('oldroot', fun)
749
 
        new_root=transform.trans_id_tree_path('')
 
815
        new_root = transform.trans_id_tree_path('')
750
816
        transform.version_file('new-root', new_root)
751
817
        transform.apply()
752
818
 
1856
1922
        self.assertEqual([], list(target.iter_changes(revision_tree)))
1857
1923
        self.assertTrue(source.is_executable('file1-id'))
1858
1924
 
 
1925
    def install_rot13_content_filter(self, pattern):
 
1926
        # We could use
 
1927
        # self.addCleanup(filters._reset_registry, filters._reset_registry())
 
1928
        # below, but that looks a bit... hard to read even if it's exactly
 
1929
        # the same thing.
 
1930
        original_registry = filters._reset_registry()
 
1931
        def restore_registry():
 
1932
            filters._reset_registry(original_registry)
 
1933
        self.addCleanup(restore_registry)
 
1934
        def rot13(chunks, context=None):
 
1935
            return [''.join(chunks).encode('rot13')]
 
1936
        rot13filter = filters.ContentFilter(rot13, rot13)
 
1937
        filters.register_filter_stack_map('rot13', {'yes': [rot13filter]}.get)
 
1938
        os.mkdir(self.test_home_dir + '/.bazaar')
 
1939
        rules_filename = self.test_home_dir + '/.bazaar/rules'
 
1940
        f = open(rules_filename, 'wb')
 
1941
        f.write('[name %s]\nrot13=yes\n' % (pattern,))
 
1942
        f.close()
 
1943
        def uninstall_rules():
 
1944
            os.remove(rules_filename)
 
1945
            rules.reset_rules()
 
1946
        self.addCleanup(uninstall_rules)
 
1947
        rules.reset_rules()
 
1948
 
 
1949
    def test_build_tree_content_filtered_files_are_not_hardlinked(self):
 
1950
        """build_tree will not hardlink files that have content filtering rules
 
1951
        applied to them (but will still hardlink other files from the same tree
 
1952
        if it can).
 
1953
        """
 
1954
        self.requireFeature(HardlinkFeature)
 
1955
        self.install_rot13_content_filter('file1')
 
1956
        source = self.create_ab_tree()
 
1957
        target = self.make_branch_and_tree('target')
 
1958
        revision_tree = source.basis_tree()
 
1959
        revision_tree.lock_read()
 
1960
        self.addCleanup(revision_tree.unlock)
 
1961
        build_tree(revision_tree, target, source, hardlink=True)
 
1962
        target.lock_read()
 
1963
        self.addCleanup(target.unlock)
 
1964
        self.assertEqual([], list(target.iter_changes(revision_tree)))
 
1965
        source_stat = os.stat('source/file1')
 
1966
        target_stat = os.stat('target/file1')
 
1967
        self.assertNotEqual(source_stat, target_stat)
 
1968
        source_stat = os.stat('source/file2')
 
1969
        target_stat = os.stat('target/file2')
 
1970
        self.assertEqualStat(source_stat, target_stat)
 
1971
 
1859
1972
    def test_case_insensitive_build_tree_inventory(self):
1860
1973
        if (tests.CaseInsensitiveFilesystemFeature.available()
1861
1974
            or tests.CaseInsCasePresFilenameFeature.available()):
1916
2029
        branch.lock_write()
1917
2030
        self.addCleanup(branch.unlock)
1918
2031
        tt = TransformPreview(branch.basis_tree())
 
2032
        self.addCleanup(tt.finalize)
1919
2033
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
1920
2034
        rev = tt.commit(branch, 'my message')
1921
2035
        self.assertEqual([], branch.basis_tree().get_parent_ids())
1927
2041
        branch.lock_write()
1928
2042
        self.addCleanup(branch.unlock)
1929
2043
        tt = TransformPreview(branch.basis_tree())
 
2044
        self.addCleanup(tt.finalize)
1930
2045
        e = self.assertRaises(ValueError, tt.commit, branch,
1931
2046
                          'my message', ['rev1b-id'])
1932
2047
        self.assertEqual('Cannot supply merge parents for first commit.',
1937
2052
        branch, tt = self.get_branch_and_transform()
1938
2053
        tt.new_file('file', tt.root, 'contents', 'file-id')
1939
2054
        trans_id = tt.new_directory('dir', tt.root, 'dir-id')
1940
 
        tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
 
2055
        if SymlinkFeature.available():
 
2056
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
1941
2057
        rev = tt.commit(branch, 'message')
1942
2058
        tree = branch.basis_tree()
1943
2059
        self.assertEqual('file', tree.id2path('file-id'))
1944
2060
        self.assertEqual('contents', tree.get_file_text('file-id'))
1945
2061
        self.assertEqual('dir', tree.id2path('dir-id'))
1946
 
        self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
1947
 
        self.assertEqual('target', tree.get_symlink_target('symlink-id'))
 
2062
        if SymlinkFeature.available():
 
2063
            self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
 
2064
            self.assertEqual('target', tree.get_symlink_target('symlink-id'))
1948
2065
 
1949
2066
    def test_add_unversioned(self):
1950
2067
        branch, tt = self.get_branch_and_transform()
1957
2074
        tt.new_file('file', tt.root, 'contents', 'file-id')
1958
2075
        tt.commit(branch, 'message', strict=True)
1959
2076
        tt = TransformPreview(branch.basis_tree())
 
2077
        self.addCleanup(tt.finalize)
1960
2078
        trans_id = tt.trans_id_file_id('file-id')
1961
2079
        tt.delete_contents(trans_id)
1962
2080
        tt.create_file('contents', trans_id)
2253
2371
    def test_ignore_pb(self):
2254
2372
        # pb could be supported, but TT.iter_changes doesn't support it.
2255
2373
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2256
 
        preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
 
2374
        preview_tree.iter_changes(revision_tree)
2257
2375
 
2258
2376
    def test_kind(self):
2259
2377
        revision_tree = self.create_tree()
2274
2392
        self.assertEqual(os.stat(limbo_path).st_mtime,
2275
2393
                         preview_tree.get_file_mtime('file-id'))
2276
2394
 
 
2395
    def test_get_file_mtime_renamed(self):
 
2396
        work_tree = self.make_branch_and_tree('tree')
 
2397
        self.build_tree(['tree/file'])
 
2398
        work_tree.add('file', 'file-id')
 
2399
        preview = TransformPreview(work_tree)
 
2400
        self.addCleanup(preview.finalize)
 
2401
        file_trans_id = preview.trans_id_tree_file_id('file-id')
 
2402
        preview.adjust_path('renamed', preview.root, file_trans_id)
 
2403
        preview_tree = preview.get_preview_tree()
 
2404
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
 
2405
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
 
2406
 
2277
2407
    def test_get_file(self):
2278
2408
        preview = self.get_empty_preview()
2279
2409
        preview.new_file('file', preview.root, 'contents', 'file-id')
2427
2557
        self.assertEqual(('missing', None, None, None), summary)
2428
2558
 
2429
2559
    def test_file_content_summary_executable(self):
2430
 
        if not osutils.supports_executable():
2431
 
            raise TestNotApplicable()
2432
2560
        preview = self.get_empty_preview()
2433
2561
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2434
2562
        preview.set_executability(True, path_id)
2443
2571
        self.assertIs(None, summary[3])
2444
2572
 
2445
2573
    def test_change_executability(self):
2446
 
        if not osutils.supports_executable():
2447
 
            raise TestNotApplicable()
2448
2574
        tree = self.make_branch_and_tree('tree')
2449
2575
        self.build_tree(['tree/path'])
2450
2576
        tree.add('path')
2464
2590
        # size must be known
2465
2591
        self.assertEqual(len('contents'), summary[1])
2466
2592
        # not executable
2467
 
        if osutils.supports_executable():
2468
 
            self.assertEqual(False, summary[2])
2469
 
        else:
2470
 
            self.assertEqual(None, summary[2])
 
2593
        self.assertEqual(False, summary[2])
2471
2594
        # will not have hash (not cheap to determine)
2472
2595
        self.assertIs(None, summary[3])
2473
2596
 
2614
2737
 
2615
2738
    def test_walkdirs(self):
2616
2739
        preview = self.get_empty_preview()
2617
 
        preview.version_file('tree-root', preview.root)
 
2740
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
 
2741
        # FIXME: new_directory should mark root.
 
2742
        preview.fixup_new_roots()
2618
2743
        preview_tree = preview.get_preview_tree()
2619
2744
        file_trans_id = preview.new_file('a', preview.root, 'contents',
2620
2745
                                         'a-id')
2651
2776
        self.addCleanup(work_tree.unlock)
2652
2777
        preview = TransformPreview(work_tree)
2653
2778
        self.addCleanup(preview.finalize)
2654
 
        preview_tree = preview.get_preview_tree()
2655
2779
        file_trans_id = preview.trans_id_file_id('file-id')
2656
2780
        preview.delete_contents(file_trans_id)
2657
2781
        preview.create_file('a\nb\n', file_trans_id)
2658
 
        pb = progress.DummyProgress()
2659
 
        merger = Merger.from_revision_ids(pb, preview_tree,
 
2782
        preview_tree = preview.get_preview_tree()
 
2783
        merger = Merger.from_revision_ids(None, preview_tree,
2660
2784
                                          child_tree.branch.last_revision(),
2661
2785
                                          other_branch=child_tree.branch,
2662
2786
                                          tree_branch=work_tree.branch)
2674
2798
        tt.new_file('name', tt.root, 'content', 'file-id')
2675
2799
        tree2 = self.make_branch_and_tree('tree2')
2676
2800
        tree2.set_root_id('TREE_ROOT')
2677
 
        pb = progress.DummyProgress()
2678
2801
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2679
 
                                         pb, tree.basis_tree())
 
2802
                                         None, tree.basis_tree())
2680
2803
        merger.merge_type = Merge3Merger
2681
2804
        merger.do_merge()
2682
2805
 
2692
2815
        tt.create_file('baz', trans_id)
2693
2816
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2694
2817
        self.build_tree_contents([('tree2/foo', 'qux')])
2695
 
        pb = progress.DummyProgress()
 
2818
        pb = None
2696
2819
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2697
2820
                                         pb, tree.basis_tree())
2698
2821
        merger.merge_type = Merge3Merger
2725
2848
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
2726
2849
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
2727
2850
 
 
2851
    def test_ascii_limbo_paths(self):
 
2852
        self.requireFeature(tests.UnicodeFilenameFeature)
 
2853
        branch = self.make_branch('any')
 
2854
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
 
2855
        tt = TransformPreview(tree)
 
2856
        self.addCleanup(tt.finalize)
 
2857
        foo_id = tt.new_directory('', ROOT_PARENT)
 
2858
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
 
2859
        limbo_path = tt._limbo_name(bar_id)
 
2860
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
 
2861
 
2728
2862
 
2729
2863
class FakeSerializer(object):
2730
2864
    """Serializer implementation that simply returns the input.