~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: John Arbash Meinel
  • Date: 2010-05-11 10:45:26 UTC
  • mto: This revision was merged to the branch mainline in revision 5225.
  • Revision ID: john@arbash-meinel.com-20100511104526-zxnstcxta22hzw2n
Implement a compiled extension for parsing the text key out of a CHKInventory value.

Related to bug #562666. This seems to shave 5-10% out of the time spent doing a complete
branch of bzr.dev/launchpad/etc.

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)
2146
2264
    def create_tree(self):
2147
2265
        tree = self.make_branch_and_tree('.')
2148
2266
        self.build_tree_contents([('a', 'content 1')])
 
2267
        tree.set_root_id('TREE_ROOT')
2149
2268
        tree.add('a', 'a-id')
2150
2269
        tree.commit('rev1', rev_id='rev1')
2151
2270
        return tree.branch.repository.revision_tree('rev1')
2252
2371
    def test_ignore_pb(self):
2253
2372
        # pb could be supported, but TT.iter_changes doesn't support it.
2254
2373
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2255
 
        preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
 
2374
        preview_tree.iter_changes(revision_tree)
2256
2375
 
2257
2376
    def test_kind(self):
2258
2377
        revision_tree = self.create_tree()
2273
2392
        self.assertEqual(os.stat(limbo_path).st_mtime,
2274
2393
                         preview_tree.get_file_mtime('file-id'))
2275
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
 
2276
2407
    def test_get_file(self):
2277
2408
        preview = self.get_empty_preview()
2278
2409
        preview.new_file('file', preview.root, 'contents', 'file-id')
2426
2557
        self.assertEqual(('missing', None, None, None), summary)
2427
2558
 
2428
2559
    def test_file_content_summary_executable(self):
2429
 
        if not osutils.supports_executable():
2430
 
            raise TestNotApplicable()
2431
2560
        preview = self.get_empty_preview()
2432
2561
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2433
2562
        preview.set_executability(True, path_id)
2442
2571
        self.assertIs(None, summary[3])
2443
2572
 
2444
2573
    def test_change_executability(self):
2445
 
        if not osutils.supports_executable():
2446
 
            raise TestNotApplicable()
2447
2574
        tree = self.make_branch_and_tree('tree')
2448
2575
        self.build_tree(['tree/path'])
2449
2576
        tree.add('path')
2463
2590
        # size must be known
2464
2591
        self.assertEqual(len('contents'), summary[1])
2465
2592
        # not executable
2466
 
        if osutils.supports_executable():
2467
 
            self.assertEqual(False, summary[2])
2468
 
        else:
2469
 
            self.assertEqual(None, summary[2])
 
2593
        self.assertEqual(False, summary[2])
2470
2594
        # will not have hash (not cheap to determine)
2471
2595
        self.assertIs(None, summary[3])
2472
2596
 
2613
2737
 
2614
2738
    def test_walkdirs(self):
2615
2739
        preview = self.get_empty_preview()
2616
 
        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()
2617
2743
        preview_tree = preview.get_preview_tree()
2618
2744
        file_trans_id = preview.new_file('a', preview.root, 'contents',
2619
2745
                                         'a-id')
2650
2776
        self.addCleanup(work_tree.unlock)
2651
2777
        preview = TransformPreview(work_tree)
2652
2778
        self.addCleanup(preview.finalize)
2653
 
        preview_tree = preview.get_preview_tree()
2654
2779
        file_trans_id = preview.trans_id_file_id('file-id')
2655
2780
        preview.delete_contents(file_trans_id)
2656
2781
        preview.create_file('a\nb\n', file_trans_id)
2657
 
        pb = progress.DummyProgress()
2658
 
        merger = Merger.from_revision_ids(pb, preview_tree,
 
2782
        preview_tree = preview.get_preview_tree()
 
2783
        merger = Merger.from_revision_ids(None, preview_tree,
2659
2784
                                          child_tree.branch.last_revision(),
2660
2785
                                          other_branch=child_tree.branch,
2661
2786
                                          tree_branch=work_tree.branch)
2667
2792
 
2668
2793
    def test_merge_preview_into_workingtree(self):
2669
2794
        tree = self.make_branch_and_tree('tree')
 
2795
        tree.set_root_id('TREE_ROOT')
2670
2796
        tt = TransformPreview(tree)
2671
2797
        self.addCleanup(tt.finalize)
2672
2798
        tt.new_file('name', tt.root, 'content', 'file-id')
2673
2799
        tree2 = self.make_branch_and_tree('tree2')
2674
 
        pb = progress.DummyProgress()
 
2800
        tree2.set_root_id('TREE_ROOT')
2675
2801
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2676
 
                                         pb, tree.basis_tree())
 
2802
                                         None, tree.basis_tree())
2677
2803
        merger.merge_type = Merge3Merger
2678
2804
        merger.do_merge()
2679
2805
 
2689
2815
        tt.create_file('baz', trans_id)
2690
2816
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2691
2817
        self.build_tree_contents([('tree2/foo', 'qux')])
2692
 
        pb = progress.DummyProgress()
 
2818
        pb = None
2693
2819
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2694
2820
                                         pb, tree.basis_tree())
2695
2821
        merger.merge_type = Merge3Merger
2722
2848
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
2723
2849
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
2724
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
 
2725
2862
 
2726
2863
class FakeSerializer(object):
2727
2864
    """Serializer implementation that simply returns the input.