~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

(vila) Fix bzrlib.tests.test_gpg.TestVerify.test_verify_revoked_signature
 with recent versions of gpg. (Vincent Ladeuil)

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
21
21
from StringIO import StringIO
22
22
import os
23
23
import stat
24
 
import sys
25
24
import tarfile
 
25
import time
26
26
import zipfile
27
27
 
28
28
 
29
29
from bzrlib import (
30
30
    export,
31
 
    tests,
32
 
    )
33
 
from bzrlib.tests import TestCaseWithTransport
 
31
    )
 
32
from bzrlib.tests import (
 
33
    features,
 
34
    TestCaseWithTransport,
 
35
    )
 
36
from bzrlib.tests.matchers import ContainsNoVfsCalls
34
37
 
35
38
 
36
39
class TestExport(TestCaseWithTransport):
37
40
 
38
 
    def test_tar_export(self):
39
 
        tree = self.make_branch_and_tree('tar')
40
 
        self.build_tree(['tar/a'])
 
41
    # On Windows, if we fail to set the binary bit, and a '\r' or '\n'
 
42
    # ends up in the data stream, we will get corruption. Add a fair amount
 
43
    # of random data, to help ensure there is at least one.
 
44
    _file_content = ('!\r\n\t\n \r'
 
45
        + 'r29trp9i1r8k0e24c2o7mcx2isrlaw7toh1hv2mtst3o1udkl36v9xn2z8kt\n'
 
46
          'tvjn7e3i9cj1qs1rw9gcye9w72cbdueiufw8nky7bs08lwggir59d62knecp\n'
 
47
          '7s0537r8sg3e8hdnidji49rswo47c3j8190nh8emef2b6j1mf5kdq45nt3f5\n'
 
48
          '1sz9u7fuzrm4w8bebre7p62sh5os2nkj2iiyuk9n0w0pjpdulu9k2aajejah\n'
 
49
          'ini90ny40qzs12ajuy0ua6l178n93lvy2atqngnntsmtlmqx7yhp0q9a1xr4\n'
 
50
          '1n69kgbo6qu9osjpqq83446r00jijtcstzybfqwm1lnt9spnri2j07bt7bbh\n'
 
51
          'rf3ejatdxta83te2s0pt9rc4hidgy3d2pc53p4wscdt2b1dfxdj9utf5m17f\n'
 
52
          'f03oofcau950o090vyx6m72vfkywo7gp3ajzi6uk02dwqwtumq4r44xx6ho7\n'
 
53
          'nhynborjdjep5j53f9548msb7gd3x9a1xveb4s8zfo6cbdw2kdngcrbakwu8\n'
 
54
          'ql5a8l94gplkwr7oypw5nt1gj5i3xwadyjfr3lb61tfkz31ba7uda9knb294\n'
 
55
          '1azhfta0q3ry9x36lxyanvhp0g5z0t5a0i4wnoc8p4htexi915y1cnw4nznn\n'
 
56
          'aj70dvp88ifiblv2bsp98hz570teinj8g472ddxni9ydmazfzwtznbf3hrg6\n'
 
57
          '84gigirjt6n2yagf70036m8d73cz0jpcighpjtxsmbgzbxx7nb4ewq6jbgnc\n'
 
58
          'hux1b0qtsdi0zfhj6g1otf5jcldmtdvuon8y1ttszkqw3ograwi25yl921hy\n'
 
59
          'izgscmfha9xdhxxabs07b40secpw22ah9iwpbmsns6qz0yr6fswto3ft2ez5\n'
 
60
          'ngn48pdfxj1pw246drmj1y2ll5af5w7cz849rapzd9ih7qvalw358co0yzrs\n'
 
61
          'xan9291d1ivjku4o5gjrsnmllrqwxwy86pcivinbmlnzasa9v3o22lgv4uyd\n'
 
62
          'q8kw77bge3hr5rr5kzwjxk223bkmo3z9oju0954undsz8axr3kb3730otrcr\n'
 
63
          '9cwhu37htnizdwxmpoc5qmobycfm7ubbykfumv6zgkl6b8zlslwl7a8b81vz\n'
 
64
          '3weqkvv5csfza9xvwypr6lo0t03fwp0ihmci3m1muh0lf2u30ze0hjag691j\n'
 
65
          '27fjtd3e3zbiin5n2hq21iuo09ukbs73r5rt7vaw6axvoilvdciir9ugjh2c\n'
 
66
          'na2b8dr0ptftoyhyxv1iwg661y338e28fhz4xxwgv3hnoe98ydfa1oou45vj\n'
 
67
          'ln74oac2keqt0agbylrqhfscin7ireae2bql7z2le823ksy47ud57z8ctomp\n'
 
68
          '31s1vwbczdjwqp0o2jc7mkrurvzg8mj2zwcn2iily4gcl4sy4fsh4rignlyz\n')
 
69
 
 
70
    def make_basic_tree(self):
 
71
        tree = self.make_branch_and_tree('tree')
 
72
        self.build_tree_contents([('tree/a', self._file_content)])
41
73
        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
74
        tree.commit('1')
50
 
 
51
 
        self.failUnless(tree.has_filename('.bzrignore'))
52
 
        self.failUnless(tree.has_filename('.bzrrules'))
53
 
        self.failUnless(tree.has_filename('.bzr-adir'))
54
 
        self.failUnless(tree.has_filename('.bzr-adir/afile'))
55
 
        self.run_bzr('export test.tar.gz')
 
75
        return tree
 
76
 
 
77
    def make_tree_with_extra_bzr_files(self):
 
78
        tree = self.make_basic_tree()
 
79
        self.build_tree_contents([('tree/.bzrrules', '')])
 
80
        self.build_tree(['tree/.bzr-adir/', 'tree/.bzr-adir/afile'])
 
81
        tree.add(['.bzrrules', '.bzr-adir/', '.bzr-adir/afile'])
 
82
 
 
83
        self.run_bzr('ignore something -d tree')
 
84
        tree.commit('2')
 
85
        return tree
 
86
 
 
87
    def test_tar_export_ignores_bzr(self):
 
88
        tree = self.make_tree_with_extra_bzr_files()
 
89
 
 
90
        self.assertTrue(tree.has_filename('.bzrignore'))
 
91
        self.assertTrue(tree.has_filename('.bzrrules'))
 
92
        self.assertTrue(tree.has_filename('.bzr-adir'))
 
93
        self.assertTrue(tree.has_filename('.bzr-adir/afile'))
 
94
        self.run_bzr('export test.tar.gz -d tree')
56
95
        ball = tarfile.open('test.tar.gz')
57
96
        # Make sure the tarball contains 'a', but does not contain
58
97
        # '.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):
 
98
        self.assertEqual(['test/a'],
 
99
                         sorted(ball.getnames()))
 
100
 
 
101
    def test_tar_export_unicode_filename(self):
 
102
        self.requireFeature(features.UnicodeFilenameFeature)
69
103
        tree = self.make_branch_and_tree('tar')
70
104
        # FIXME: using fname = u'\xe5.txt' below triggers a bug revealed since
71
105
        # bzr.dev revno 4216 but more related to OSX/working trees/unicode than
72
106
        # export itself --vila 20090406
73
107
        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,))
 
108
        self.build_tree(['tar/' + fname])
78
109
        tree.add([fname])
79
110
        tree.commit('first')
80
111
 
81
 
        os.chdir('tar')
82
 
        self.run_bzr('export test.tar')
 
112
        self.run_bzr('export test.tar -d tar')
83
113
        ball = tarfile.open('test.tar')
84
114
        # all paths are prefixed with the base name of the tarball
85
115
        self.assertEqual(['test/' + fname.encode('utf8')],
87
117
 
88
118
    def test_tar_export_unicode_basedir(self):
89
119
        """Test for bug #413406"""
 
120
        self.requireFeature(features.UnicodeFilenameFeature)
90
121
        basedir = u'\N{euro sign}'
91
122
        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')
109
 
 
110
 
        self.failUnless(tree.has_filename('.bzrignore'))
111
 
        self.failUnless(tree.has_filename('.bzrrules'))
112
 
        self.failUnless(tree.has_filename('.bzr-adir'))
113
 
        self.failUnless(tree.has_filename('.bzr-adir/afile'))
114
 
        self.run_bzr('export test.zip')
 
123
        self.run_bzr(['init', basedir])
 
124
        self.run_bzr(['export', '--format', 'tgz', u'test.tar.gz',
 
125
                      '-d', basedir])
 
126
 
 
127
    def test_zip_export_ignores_bzr(self):
 
128
        tree = self.make_tree_with_extra_bzr_files()
 
129
 
 
130
        self.assertTrue(tree.has_filename('.bzrignore'))
 
131
        self.assertTrue(tree.has_filename('.bzrrules'))
 
132
        self.assertTrue(tree.has_filename('.bzr-adir'))
 
133
        self.assertTrue(tree.has_filename('.bzr-adir/afile'))
 
134
        self.run_bzr('export test.zip -d tree')
115
135
 
116
136
        zfile = zipfile.ZipFile('test.zip')
117
137
        # Make sure the zipfile contains 'a', but does not contain
118
138
        # '.bzrignore'.
119
139
        self.assertEqual(['test/a'], sorted(zfile.namelist()))
120
140
 
 
141
    # TODO: This really looks like something that should be using permutation
 
142
    #       testing. Though the actual setup and teardown functions are pretty
 
143
    #       different for each
 
144
    def assertZipANameAndContent(self, zfile, root=''):
 
145
        """The file should only contain name 'a' and _file_content"""
 
146
        fname = root + 'a'
 
147
        self.assertEqual([fname], sorted(zfile.namelist()))
 
148
        zfile.testzip()
 
149
        self.assertEqualDiff(self._file_content, zfile.read(fname))
 
150
 
 
151
    def test_zip_export_stdout(self):
 
152
        tree = self.make_basic_tree()
 
153
        contents = self.run_bzr('export -d tree --format=zip -')[0]
 
154
        self.assertZipANameAndContent(zipfile.ZipFile(StringIO(contents)))
 
155
 
 
156
    def test_zip_export_file(self):
 
157
        tree = self.make_basic_tree()
 
158
        self.run_bzr('export -d tree test.zip')
 
159
        self.assertZipANameAndContent(zipfile.ZipFile('test.zip'),
 
160
                                      root='test/')
 
161
 
 
162
    def assertTarANameAndContent(self, ball, root=''):
 
163
        fname = root + 'a'
 
164
        tar_info = ball.next()
 
165
        self.assertEqual(fname, tar_info.name)
 
166
        self.assertEqual(tarfile.REGTYPE, tar_info.type)
 
167
        self.assertEqual(len(self._file_content), tar_info.size)
 
168
        f = ball.extractfile(tar_info)
 
169
        if self._file_content != f.read():
 
170
            self.fail('File content has been corrupted.'
 
171
                      ' Check that all streams are handled in binary mode.')
 
172
        # There should be no other files in the tarball
 
173
        self.assertIs(None, ball.next())
 
174
 
 
175
    def run_tar_export_disk_and_stdout(self, extension, tarfile_flags):
 
176
        tree = self.make_basic_tree()
 
177
        fname = 'test.%s' % (extension,)
 
178
        self.run_bzr('export -d tree %s' % (fname,))
 
179
        mode = 'r|%s' % (tarfile_flags,)
 
180
        ball = tarfile.open(fname, mode=mode)
 
181
        self.assertTarANameAndContent(ball, root='test/')
 
182
        content = self.run_bzr('export -d tree --format=%s -' % (extension,))[0]
 
183
        ball = tarfile.open(mode=mode, fileobj=StringIO(content))
 
184
        self.assertTarANameAndContent(ball, root='')
 
185
 
 
186
    def test_tar_export(self):
 
187
        self.run_tar_export_disk_and_stdout('tar', '')
 
188
 
 
189
    def test_tgz_export(self):
 
190
        self.run_tar_export_disk_and_stdout('tgz', 'gz')
 
191
 
 
192
    def test_tbz2_export(self):
 
193
        self.run_tar_export_disk_and_stdout('tbz2', 'bz2')
 
194
 
121
195
    def test_zip_export_unicode(self):
 
196
        self.requireFeature(features.UnicodeFilenameFeature)
122
197
        tree = self.make_branch_and_tree('zip')
123
198
        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,))
 
199
        self.build_tree(['zip/' + fname])
128
200
        tree.add([fname])
129
201
        tree.commit('first')
130
202
 
151
223
        self.assertEqual(['test/a', 'test/b/', 'test/b/c', 'test/d/'], names)
152
224
 
153
225
        file_attr = stat.S_IFREG | export.zip_exporter.FILE_PERMISSIONS
154
 
        dir_attr = stat.S_IFDIR | export.zip_exporter.ZIP_DIRECTORY_BIT
 
226
        dir_attr = (stat.S_IFDIR | export.zip_exporter.ZIP_DIRECTORY_BIT |
 
227
                    export.zip_exporter.DIR_PERMISSIONS)
155
228
 
156
229
        a_info = zfile.getinfo(names[0])
157
230
        self.assertEqual(file_attr, a_info.external_attr)
178
251
        self.run_bzr('ignore something')
179
252
        tree.commit('1')
180
253
 
181
 
        self.failUnless(tree.has_filename('.bzrignore'))
182
 
        self.failUnless(tree.has_filename('.bzrrules'))
183
 
        self.failUnless(tree.has_filename('.bzr-adir'))
184
 
        self.failUnless(tree.has_filename('.bzr-adir/afile'))
 
254
        self.assertTrue(tree.has_filename('.bzrignore'))
 
255
        self.assertTrue(tree.has_filename('.bzrrules'))
 
256
        self.assertTrue(tree.has_filename('.bzr-adir'))
 
257
        self.assertTrue(tree.has_filename('.bzr-adir/afile'))
185
258
        self.run_bzr('export direxport')
186
259
 
187
260
        files = sorted(os.listdir('direxport'))
224
297
        os.chdir('branch')
225
298
 
226
299
        self.run_bzr('export ../first.tar -r 1')
227
 
        self.failUnless(os.path.isfile('../first.tar'))
 
300
        self.assertTrue(os.path.isfile('../first.tar'))
228
301
        tf = tarfile.open('../first.tar')
229
302
        try:
230
303
            self.assertEqual(['first/hello'], sorted(tf.getnames()))
233
306
            tf.close()
234
307
 
235
308
        self.run_bzr('export ../first.tar.gz -r 1')
236
 
        self.failUnless(os.path.isfile('../first.tar.gz'))
 
309
        self.assertTrue(os.path.isfile('../first.tar.gz'))
237
310
        self.run_bzr('export ../first.tbz2 -r 1')
238
 
        self.failUnless(os.path.isfile('../first.tbz2'))
 
311
        self.assertTrue(os.path.isfile('../first.tbz2'))
239
312
        self.run_bzr('export ../first.tar.bz2 -r 1')
240
 
        self.failUnless(os.path.isfile('../first.tar.bz2'))
 
313
        self.assertTrue(os.path.isfile('../first.tar.bz2'))
241
314
        self.run_bzr('export ../first.tar.tbz2 -r 1')
242
 
        self.failUnless(os.path.isfile('../first.tar.tbz2'))
 
315
        self.assertTrue(os.path.isfile('../first.tar.tbz2'))
243
316
 
244
317
        tf = tarfile.open('../first.tar.tbz2', 'r:bz2')
245
318
        try:
260
333
        os.chdir('branch')
261
334
 
262
335
        self.run_bzr('export ../first.zip -r 1')
263
 
        self.failUnlessExists('../first.zip')
 
336
        self.assertPathExists('../first.zip')
264
337
        zf = zipfile.ZipFile('../first.zip')
265
338
        try:
266
339
            self.assertEqual(['first/hello'], sorted(zf.namelist()))
313
386
        har_st = os.stat('t/har')
314
387
        self.assertEquals(315532800, har_st.st_mtime)
315
388
 
 
389
    def test_dir_export_partial_tree_per_file_timestamps(self):
 
390
        tree = self.example_branch()
 
391
        self.build_tree(['branch/subdir/', 'branch/subdir/foo.txt'])
 
392
        tree.smart_add(['branch'])
 
393
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
394
        tree.commit('setup', timestamp=315532800)
 
395
        self.run_bzr('export --per-file-timestamps tpart branch/subdir')
 
396
        foo_st = os.stat('tpart/foo.txt')
 
397
        self.assertEquals(315532800, foo_st.st_mtime)
 
398
 
316
399
    def test_export_directory(self):
317
400
        """Test --directory option"""
318
401
        self.example_branch()
319
402
        self.run_bzr(['export', '--directory=branch', 'latest'])
320
403
        self.assertEqual(['goodbye', 'hello'], sorted(os.listdir('latest')))
321
404
        self.check_file_contents('latest/goodbye', 'baz')
 
405
 
 
406
    def test_export_uncommitted(self):
 
407
        """Test --uncommitted option"""
 
408
        self.example_branch()
 
409
        os.chdir('branch')
 
410
        self.build_tree_contents([('goodbye', 'uncommitted data')])
 
411
        self.run_bzr(['export', '--uncommitted', 'latest'])
 
412
        self.check_file_contents('latest/goodbye', 'uncommitted data')
 
413
 
 
414
    def test_export_uncommitted_no_tree(self):
 
415
        """Test --uncommitted option only works with a working tree."""
 
416
        tree = self.example_branch()
 
417
        tree.bzrdir.destroy_workingtree()
 
418
        os.chdir('branch')
 
419
        self.run_bzr_error(
 
420
            ['bzr: ERROR: --uncommitted requires a working tree'],
 
421
            'export --uncommitted latest')
 
422
 
 
423
    def test_zip_export_per_file_timestamps(self):
 
424
        tree = self.example_branch()
 
425
        self.build_tree_contents([('branch/har', 'foo')])
 
426
        tree.add('har')
 
427
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
428
        timestamp = 347151600
 
429
        tree.commit('setup', timestamp=timestamp)
 
430
        self.run_bzr('export --per-file-timestamps test.zip branch')
 
431
        zfile = zipfile.ZipFile('test.zip')
 
432
        info = zfile.getinfo("test/har")
 
433
        self.assertEquals(time.localtime(timestamp)[:6], info.date_time)
 
434
 
 
435
 
 
436
class TestSmartServerExport(TestCaseWithTransport):
 
437
 
 
438
    def test_simple_export(self):
 
439
        self.setup_smart_server_with_call_log()
 
440
        t = self.make_branch_and_tree('branch')
 
441
        self.build_tree_contents([('branch/foo', 'thecontents')])
 
442
        t.add("foo")
 
443
        t.commit("message")
 
444
        self.reset_smart_call_log()
 
445
        out, err = self.run_bzr(['export', "foo.tar.gz", self.get_url('branch')])
 
446
        # This figure represent the amount of work to perform this use case. It
 
447
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
448
        # being too low. If rpc_count increases, more network roundtrips have
 
449
        # become necessary for this use case. Please do not adjust this number
 
450
        # upwards without agreement from bzr's network support maintainers.
 
451
        self.assertLength(7, self.hpss_calls)
 
452
        self.assertLength(1, self.hpss_connections)
 
453
        self.assertThat(self.hpss_calls, ContainsNoVfsCalls)