~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_export.py

merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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
23
23
import stat
24
24
import sys
25
25
import tarfile
 
26
import time
26
27
import zipfile
27
28
 
28
29
 
29
30
from bzrlib import (
30
31
    export,
 
32
    osutils,
31
33
    tests,
32
34
    )
33
35
from bzrlib.tests import TestCaseWithTransport
35
37
 
36
38
class TestExport(TestCaseWithTransport):
37
39
 
38
 
    def test_tar_export(self):
39
 
        tree = self.make_branch_and_tree('tar')
40
 
        self.build_tree(['tar/a'])
 
40
    # On Windows, if we fail to set the binary bit, and a '\r' or '\n'
 
41
    # ends up in the data stream, we will get corruption. Add a fair amount
 
42
    # of random data, to help ensure there is at least one.
 
43
    _file_content = ('!\r\n\t\n \r'
 
44
        + 'r29trp9i1r8k0e24c2o7mcx2isrlaw7toh1hv2mtst3o1udkl36v9xn2z8kt\n'
 
45
          'tvjn7e3i9cj1qs1rw9gcye9w72cbdueiufw8nky7bs08lwggir59d62knecp\n'
 
46
          '7s0537r8sg3e8hdnidji49rswo47c3j8190nh8emef2b6j1mf5kdq45nt3f5\n'
 
47
          '1sz9u7fuzrm4w8bebre7p62sh5os2nkj2iiyuk9n0w0pjpdulu9k2aajejah\n'
 
48
          'ini90ny40qzs12ajuy0ua6l178n93lvy2atqngnntsmtlmqx7yhp0q9a1xr4\n'
 
49
          '1n69kgbo6qu9osjpqq83446r00jijtcstzybfqwm1lnt9spnri2j07bt7bbh\n'
 
50
          'rf3ejatdxta83te2s0pt9rc4hidgy3d2pc53p4wscdt2b1dfxdj9utf5m17f\n'
 
51
          'f03oofcau950o090vyx6m72vfkywo7gp3ajzi6uk02dwqwtumq4r44xx6ho7\n'
 
52
          'nhynborjdjep5j53f9548msb7gd3x9a1xveb4s8zfo6cbdw2kdngcrbakwu8\n'
 
53
          'ql5a8l94gplkwr7oypw5nt1gj5i3xwadyjfr3lb61tfkz31ba7uda9knb294\n'
 
54
          '1azhfta0q3ry9x36lxyanvhp0g5z0t5a0i4wnoc8p4htexi915y1cnw4nznn\n'
 
55
          'aj70dvp88ifiblv2bsp98hz570teinj8g472ddxni9ydmazfzwtznbf3hrg6\n'
 
56
          '84gigirjt6n2yagf70036m8d73cz0jpcighpjtxsmbgzbxx7nb4ewq6jbgnc\n'
 
57
          'hux1b0qtsdi0zfhj6g1otf5jcldmtdvuon8y1ttszkqw3ograwi25yl921hy\n'
 
58
          'izgscmfha9xdhxxabs07b40secpw22ah9iwpbmsns6qz0yr6fswto3ft2ez5\n'
 
59
          'ngn48pdfxj1pw246drmj1y2ll5af5w7cz849rapzd9ih7qvalw358co0yzrs\n'
 
60
          'xan9291d1ivjku4o5gjrsnmllrqwxwy86pcivinbmlnzasa9v3o22lgv4uyd\n'
 
61
          'q8kw77bge3hr5rr5kzwjxk223bkmo3z9oju0954undsz8axr3kb3730otrcr\n'
 
62
          '9cwhu37htnizdwxmpoc5qmobycfm7ubbykfumv6zgkl6b8zlslwl7a8b81vz\n'
 
63
          '3weqkvv5csfza9xvwypr6lo0t03fwp0ihmci3m1muh0lf2u30ze0hjag691j\n'
 
64
          '27fjtd3e3zbiin5n2hq21iuo09ukbs73r5rt7vaw6axvoilvdciir9ugjh2c\n'
 
65
          'na2b8dr0ptftoyhyxv1iwg661y338e28fhz4xxwgv3hnoe98ydfa1oou45vj\n'
 
66
          'ln74oac2keqt0agbylrqhfscin7ireae2bql7z2le823ksy47ud57z8ctomp\n'
 
67
          '31s1vwbczdjwqp0o2jc7mkrurvzg8mj2zwcn2iily4gcl4sy4fsh4rignlyz\n')
 
68
 
 
69
    def make_basic_tree(self):
 
70
        tree = self.make_branch_and_tree('tree')
 
71
        self.build_tree_contents([('tree/a', self._file_content)])
41
72
        tree.add('a')
42
 
        self.build_tree_contents([('tar/.bzrrules', '')])
43
 
        tree.add('.bzrrules')
44
 
        self.build_tree(['tar/.bzr-adir/', 'tar/.bzr-adir/afile'])
45
 
        tree.add(['.bzr-adir/', '.bzr-adir/afile'])
46
 
 
47
 
        os.chdir('tar')
48
 
        self.run_bzr('ignore something')
49
73
        tree.commit('1')
 
74
        return tree
 
75
 
 
76
    def make_tree_with_extra_bzr_files(self):
 
77
        tree = self.make_basic_tree()
 
78
        self.build_tree_contents([('tree/.bzrrules', '')])
 
79
        self.build_tree(['tree/.bzr-adir/', 'tree/.bzr-adir/afile'])
 
80
        tree.add(['.bzrrules', '.bzr-adir/', '.bzr-adir/afile'])
 
81
 
 
82
        self.run_bzr('ignore something -d tree')
 
83
        tree.commit('2')
 
84
        return tree
 
85
 
 
86
    def test_tar_export_ignores_bzr(self):
 
87
        tree = self.make_tree_with_extra_bzr_files()
50
88
 
51
89
        self.failUnless(tree.has_filename('.bzrignore'))
52
90
        self.failUnless(tree.has_filename('.bzrrules'))
53
91
        self.failUnless(tree.has_filename('.bzr-adir'))
54
92
        self.failUnless(tree.has_filename('.bzr-adir/afile'))
55
 
        self.run_bzr('export test.tar.gz')
 
93
        self.run_bzr('export test.tar.gz -d tree')
56
94
        ball = tarfile.open('test.tar.gz')
57
95
        # Make sure the tarball contains 'a', but does not contain
58
96
        # '.bzrignore'.
59
 
        self.assertEqual(['test/a'], sorted(ball.getnames()))
60
 
 
61
 
        if sys.version_info < (2, 5, 2) and sys.platform == 'darwin':
62
 
            raise tests.KnownFailure('python %r has a tar related bug, upgrade'
63
 
                                     % (sys.version_info,))
64
 
        out, err = self.run_bzr('export --format=tgz --root=test -')
65
 
        ball = tarfile.open('', fileobj=StringIO(out))
66
 
        self.assertEqual(['test/a'], sorted(ball.getnames()))
67
 
 
68
 
    def test_tar_export_unicode(self):
 
97
        self.assertEqual(['test/a'],
 
98
                         sorted(ball.getnames()))
 
99
 
 
100
    def test_tar_export_unicode_filename(self):
 
101
        self.requireFeature(tests.UnicodeFilenameFeature)
69
102
        tree = self.make_branch_and_tree('tar')
70
103
        # FIXME: using fname = u'\xe5.txt' below triggers a bug revealed since
71
104
        # bzr.dev revno 4216 but more related to OSX/working trees/unicode than
72
105
        # export itself --vila 20090406
73
106
        fname = u'\N{Euro Sign}.txt'
74
 
        try:
75
 
            self.build_tree(['tar/' + fname])
76
 
        except UnicodeError:
77
 
            raise tests.TestSkipped('Unable to represent path %r' % (fname,))
 
107
        self.build_tree(['tar/' + fname])
78
108
        tree.add([fname])
79
109
        tree.commit('first')
80
110
 
81
 
        os.chdir('tar')
82
 
        self.run_bzr('export test.tar')
 
111
        self.run_bzr('export test.tar -d tar')
83
112
        ball = tarfile.open('test.tar')
84
113
        # all paths are prefixed with the base name of the tarball
85
114
        self.assertEqual(['test/' + fname.encode('utf8')],
87
116
 
88
117
    def test_tar_export_unicode_basedir(self):
89
118
        """Test for bug #413406"""
 
119
        self.requireFeature(tests.UnicodeFilenameFeature)
90
120
        basedir = u'\N{euro sign}'
91
121
        os.mkdir(basedir)
92
 
        os.chdir(basedir)
93
 
        self.run_bzr(['init', 'branch'])
94
 
        os.chdir('branch')
95
 
        self.run_bzr(['export', '--format', 'tgz', u'test.tar.gz'])
96
 
 
97
 
    def test_zip_export(self):
98
 
        tree = self.make_branch_and_tree('zip')
99
 
        self.build_tree(['zip/a'])
100
 
        tree.add('a')
101
 
        self.build_tree_contents([('zip/.bzrrules', '')])
102
 
        tree.add('.bzrrules')
103
 
        self.build_tree(['zip/.bzr-adir/', 'zip/.bzr-adir/afile'])
104
 
        tree.add(['.bzr-adir/', '.bzr-adir/afile'])
105
 
 
106
 
        os.chdir('zip')
107
 
        self.run_bzr('ignore something')
108
 
        tree.commit('1')
 
122
        self.run_bzr(['init', basedir])
 
123
        self.run_bzr(['export', '--format', 'tgz', u'test.tar.gz',
 
124
                      '-d', basedir])
 
125
 
 
126
    def test_zip_export_ignores_bzr(self):
 
127
        tree = self.make_tree_with_extra_bzr_files()
109
128
 
110
129
        self.failUnless(tree.has_filename('.bzrignore'))
111
130
        self.failUnless(tree.has_filename('.bzrrules'))
112
131
        self.failUnless(tree.has_filename('.bzr-adir'))
113
132
        self.failUnless(tree.has_filename('.bzr-adir/afile'))
114
 
        self.run_bzr('export test.zip')
 
133
        self.run_bzr('export test.zip -d tree')
115
134
 
116
135
        zfile = zipfile.ZipFile('test.zip')
117
136
        # Make sure the zipfile contains 'a', but does not contain
118
137
        # '.bzrignore'.
119
138
        self.assertEqual(['test/a'], sorted(zfile.namelist()))
120
139
 
 
140
    # TODO: This really looks like something that should be using permutation
 
141
    #       testing. Though the actual setup and teardown functions are pretty
 
142
    #       different for each
 
143
    def assertZipANameAndContent(self, zfile, root=''):
 
144
        """The file should only contain name 'a' and _file_content"""
 
145
        fname = root + 'a'
 
146
        self.assertEqual([fname], sorted(zfile.namelist()))
 
147
        zfile.testzip()
 
148
        self.assertEqualDiff(self._file_content, zfile.read(fname))
 
149
 
 
150
    def test_zip_export_stdout(self):
 
151
        tree = self.make_basic_tree()
 
152
        contents = self.run_bzr('export -d tree --format=zip -')[0]
 
153
        self.assertZipANameAndContent(zipfile.ZipFile(StringIO(contents)))
 
154
 
 
155
    def test_zip_export_file(self):
 
156
        tree = self.make_basic_tree()
 
157
        self.run_bzr('export -d tree test.zip')
 
158
        self.assertZipANameAndContent(zipfile.ZipFile('test.zip'),
 
159
                                      root='test/')
 
160
 
 
161
    def assertTarANameAndContent(self, ball, root=''):
 
162
        fname = root + 'a'
 
163
        tar_info = ball.next()
 
164
        self.assertEqual(fname, tar_info.name)
 
165
        self.assertEqual(tarfile.REGTYPE, tar_info.type)
 
166
        self.assertEqual(len(self._file_content), tar_info.size)
 
167
        f = ball.extractfile(tar_info)
 
168
        if self._file_content != f.read():
 
169
            self.fail('File content has been corrupted.'
 
170
                      ' Check that all streams are handled in binary mode.')
 
171
        # There should be no other files in the tarball
 
172
        self.assertIs(None, ball.next())
 
173
 
 
174
    def run_tar_export_disk_and_stdout(self, extension, tarfile_flags):
 
175
        tree = self.make_basic_tree()
 
176
        fname = 'test.%s' % (extension,)
 
177
        mode = 'r|%s' % (tarfile_flags,)
 
178
        self.run_bzr('export -d tree %s' % (fname,))
 
179
        ball = tarfile.open(fname, mode=mode)
 
180
        self.assertTarANameAndContent(ball, root='test/')
 
181
        content = self.run_bzr('export -d tree --format=%s -' % (extension,))[0]
 
182
        ball = tarfile.open(mode=mode, fileobj=StringIO(content))
 
183
        self.assertTarANameAndContent(ball, root='')
 
184
 
 
185
    def test_tar_export(self):
 
186
        self.run_tar_export_disk_and_stdout('tar', '')
 
187
 
 
188
    def test_tgz_export(self):
 
189
        self.run_tar_export_disk_and_stdout('tgz', 'gz')
 
190
 
 
191
    def test_tbz2_export(self):
 
192
        self.run_tar_export_disk_and_stdout('tbz2', 'bz2')
 
193
 
 
194
    # TODO: test_xz_export, I don't have pylzma working here to test it.
 
195
 
121
196
    def test_zip_export_unicode(self):
 
197
        self.requireFeature(tests.UnicodeFilenameFeature)
122
198
        tree = self.make_branch_and_tree('zip')
123
199
        fname = u'\N{Euro Sign}.txt'
124
 
        try:
125
 
            self.build_tree(['zip/' + fname])
126
 
        except UnicodeError:
127
 
            raise tests.TestSkipped('Unable to represent path %r' % (fname,))
 
200
        self.build_tree(['zip/' + fname])
128
201
        tree.add([fname])
129
202
        tree.commit('first')
130
203
 
151
224
        self.assertEqual(['test/a', 'test/b/', 'test/b/c', 'test/d/'], names)
152
225
 
153
226
        file_attr = stat.S_IFREG | export.zip_exporter.FILE_PERMISSIONS
154
 
        dir_attr = stat.S_IFDIR | export.zip_exporter.ZIP_DIRECTORY_BIT
 
227
        dir_attr = (stat.S_IFDIR | export.zip_exporter.ZIP_DIRECTORY_BIT |
 
228
                    export.zip_exporter.DIR_PERMISSIONS)
155
229
 
156
230
        a_info = zfile.getinfo(names[0])
157
231
        self.assertEqual(file_attr, a_info.external_attr)
319
393
        self.run_bzr(['export', '--directory=branch', 'latest'])
320
394
        self.assertEqual(['goodbye', 'hello'], sorted(os.listdir('latest')))
321
395
        self.check_file_contents('latest/goodbye', 'baz')
 
396
 
 
397
    def test_zip_export_per_file_timestamps(self):
 
398
        tree = self.example_branch()
 
399
        self.build_tree_contents([('branch/har', 'foo')])
 
400
        tree.add('har')
 
401
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
402
        timestamp = 347151600
 
403
        tree.commit('setup', timestamp=timestamp)
 
404
        self.run_bzr('export --per-file-timestamps test.zip branch')
 
405
        zfile = zipfile.ZipFile('test.zip')
 
406
        info = zfile.getinfo("test/har")
 
407
        self.assertEquals(time.localtime(timestamp)[:6], info.date_time)