21
21
from StringIO import StringIO
29
29
from bzrlib import (
33
from bzrlib.tests import TestCaseWithTransport
32
from bzrlib.tests import (
34
TestCaseWithTransport,
36
from bzrlib.tests.matchers import ContainsNoVfsCalls
36
39
class TestExport(TestCaseWithTransport):
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')
70
def make_basic_tree(self):
71
tree = self.make_branch_and_tree('tree')
72
self.build_tree_contents([('tree/a', self._file_content)])
42
self.build_tree_contents([('tar/.bzrrules', '')])
44
self.build_tree(['tar/.bzr-adir/', 'tar/.bzr-adir/afile'])
45
tree.add(['.bzr-adir/', '.bzr-adir/afile'])
48
self.run_bzr('ignore something')
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')
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'])
83
self.run_bzr('ignore something -d tree')
87
def test_tar_export_ignores_bzr(self):
88
tree = self.make_tree_with_extra_bzr_files()
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
59
self.assertEqual(['test/a'], sorted(ball.getnames()))
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()))
68
def test_tar_export_unicode(self):
98
self.assertEqual(['test/a'],
99
sorted(ball.getnames()))
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'
75
self.build_tree(['tar/' + fname])
77
raise tests.TestSkipped('Unable to represent path %r' % (fname,))
108
self.build_tree(['tar/' + fname])
79
110
tree.commit('first')
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')],
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}'
93
self.run_bzr(['init', 'branch'])
95
self.run_bzr(['export', '--format', 'tgz', u'test.tar.gz'])
97
def test_zip_export(self):
98
tree = self.make_branch_and_tree('zip')
99
self.build_tree(['zip/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'])
107
self.run_bzr('ignore something')
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',
127
def test_zip_export_ignores_bzr(self):
128
tree = self.make_tree_with_extra_bzr_files()
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')
116
136
zfile = zipfile.ZipFile('test.zip')
117
137
# Make sure the zipfile contains 'a', but does not contain
119
139
self.assertEqual(['test/a'], sorted(zfile.namelist()))
141
# TODO: This really looks like something that should be using permutation
142
# testing. Though the actual setup and teardown functions are pretty
144
def assertZipANameAndContent(self, zfile, root=''):
145
"""The file should only contain name 'a' and _file_content"""
147
self.assertEqual([fname], sorted(zfile.namelist()))
149
self.assertEqualDiff(self._file_content, zfile.read(fname))
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)))
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'),
162
def assertTarANameAndContent(self, ball, root=''):
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())
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='')
186
def test_tar_export(self):
187
self.run_tar_export_disk_and_stdout('tar', '')
189
def test_tgz_export(self):
190
self.run_tar_export_disk_and_stdout('tgz', 'gz')
192
def test_tbz2_export(self):
193
self.run_tar_export_disk_and_stdout('tbz2', 'bz2')
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'
125
self.build_tree(['zip/' + fname])
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')
313
386
har_st = os.stat('t/har')
314
387
self.assertEquals(315532800, har_st.st_mtime)
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)
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')
406
def test_export_uncommitted(self):
407
"""Test --uncommitted option"""
408
self.example_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')
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()
420
['bzr: ERROR: --uncommitted requires a working tree'],
421
'export --uncommitted latest')
423
def test_zip_export_per_file_timestamps(self):
424
tree = self.example_branch()
425
self.build_tree_contents([('branch/har', 'foo')])
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)
436
class TestSmartServerExport(TestCaseWithTransport):
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')])
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)