1
# Copyright (C) 2009, 2010 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Tests for bzrlib.export."""
19
from cStringIO import StringIO
30
from bzrlib.export import get_root_name
31
from bzrlib.export.tar_exporter import export_tarball
32
from bzrlib.tests import features
35
class TestDirExport(tests.TestCaseWithTransport):
37
def test_missing_file(self):
38
self.build_tree(['a/', 'a/b', 'a/c'])
39
wt = self.make_branch_and_tree('.')
40
wt.add(['a', 'a/b', 'a/c'])
42
export.export(wt, 'target', format="dir")
43
self.assertPathExists('target/a/b')
44
self.assertPathDoesNotExist('target/a/c')
47
wt = self.make_branch_and_tree('.')
48
export.export(wt, 'target', format="dir")
49
self.assertEquals([], os.listdir("target"))
51
def test_symlink(self):
52
self.requireFeature(tests.SymlinkFeature)
53
wt = self.make_branch_and_tree('.')
54
os.symlink('source', 'link')
56
export.export(wt, 'target', format="dir")
57
self.assertPathExists('target/link')
59
def test_to_existing_empty_dir_success(self):
60
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
61
wt = self.make_branch_and_tree('source')
62
wt.add(['a', 'b', 'b/c'])
64
self.build_tree(['target/'])
65
export.export(wt, 'target', format="dir")
66
self.assertPathExists('target/a')
67
self.assertPathExists('target/b')
68
self.assertPathExists('target/b/c')
70
def test_empty_subdir(self):
71
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
72
wt = self.make_branch_and_tree('source')
73
wt.add(['a', 'b', 'b/c'])
75
self.build_tree(['target/'])
76
export.export(wt, 'target', format="dir", subdir='')
77
self.assertPathExists('target/a')
78
self.assertPathExists('target/b')
79
self.assertPathExists('target/b/c')
81
def test_to_existing_nonempty_dir_fail(self):
82
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
83
wt = self.make_branch_and_tree('source')
84
wt.add(['a', 'b', 'b/c'])
86
self.build_tree(['target/', 'target/foo'])
87
self.assertRaises(errors.BzrError, export.export, wt, 'target', format="dir")
89
def test_existing_single_file(self):
90
self.build_tree(['dir1/', 'dir1/dir2/', 'dir1/first', 'dir1/dir2/second'])
91
wtree = self.make_branch_and_tree('dir1')
92
wtree.add(['dir2', 'first', 'dir2/second'])
94
export.export(wtree, 'target1', format='dir', subdir='first')
95
self.assertPathExists('target1/first')
96
export.export(wtree, 'target2', format='dir', subdir='dir2/second')
97
self.assertPathExists('target2/second')
99
def test_files_same_timestamp(self):
100
builder = self.make_branch_builder('source')
101
builder.start_series()
102
builder.build_snapshot(None, None, [
103
('add', ('', 'root-id', 'directory', '')),
104
('add', ('a', 'a-id', 'file', 'content\n'))])
105
builder.build_snapshot(None, None, [
106
('add', ('b', 'b-id', 'file', 'content\n'))])
107
builder.finish_series()
108
b = builder.get_branch()
110
self.addCleanup(b.unlock)
111
tree = b.basis_tree()
112
orig_iter_files_bytes = tree.iter_files_bytes
113
# Make iter_files_bytes slower, so we provoke mtime skew
114
def iter_files_bytes(to_fetch):
115
for thing in orig_iter_files_bytes(to_fetch):
118
tree.iter_files_bytes = iter_files_bytes
119
export.export(tree, 'target', format='dir')
120
t = self.get_transport('target')
123
# All files must be given the same mtime.
124
self.assertEqual(st_a.st_mtime, st_b.st_mtime)
126
def test_files_per_file_timestamps(self):
127
builder = self.make_branch_builder('source')
128
builder.start_series()
129
# Earliest allowable date on FAT32 filesystems is 1980-01-01
130
a_time = time.mktime((1999, 12, 12, 0, 0, 0, 0, 0, 0))
131
b_time = time.mktime((1980, 01, 01, 0, 0, 0, 0, 0, 0))
132
builder.build_snapshot(None, None, [
133
('add', ('', 'root-id', 'directory', '')),
134
('add', ('a', 'a-id', 'file', 'content\n'))],
136
builder.build_snapshot(None, None, [
137
('add', ('b', 'b-id', 'file', 'content\n'))],
139
builder.finish_series()
140
b = builder.get_branch()
142
self.addCleanup(b.unlock)
143
tree = b.basis_tree()
144
export.export(tree, 'target', format='dir', per_file_timestamps=True)
145
t = self.get_transport('target')
146
self.assertEqual(a_time, t.stat('a').st_mtime)
147
self.assertEqual(b_time, t.stat('b').st_mtime)
150
class TarExporterTests(tests.TestCaseWithTransport):
153
self.requireFeature(features.lzma)
155
wt = self.make_branch_and_tree('.')
156
self.build_tree(['a'])
159
export.export(wt, 'target.tar.xz', format="txz")
160
tf = tarfile.open(fileobj=lzma.LZMAFile('target.tar.xz'))
161
self.assertEquals(["target/a"], tf.getnames())
164
self.requireFeature(features.lzma)
166
wt = self.make_branch_and_tree('.')
167
self.build_tree(['a'])
170
export.export(wt, 'target.tar.lzma', format="tlzma")
171
tf = tarfile.open(fileobj=lzma.LZMAFile('target.tar.lzma'))
172
self.assertEquals(["target/a"], tf.getnames())
175
wt = self.make_branch_and_tree('.')
176
self.build_tree(['a'])
179
export.export(wt, 'target.tar.gz', format="tgz")
180
tf = tarfile.open('target.tar.gz')
181
self.assertEquals(["target/a"], tf.getnames())
183
def test_tgz_ignores_dest_path(self):
184
# The target path should not be a part of the target file.
186
wt = self.make_branch_and_tree('.')
187
self.build_tree(['a'])
192
export.export(wt, 'testdir1/target.tar.gz', format="tgz",
193
per_file_timestamps=True)
194
export.export(wt, 'testdir2/target.tar.gz', format="tgz",
195
per_file_timestamps=True)
196
file1 = open('testdir1/target.tar.gz', 'r')
197
self.addCleanup(file1.close)
198
file2 = open('testdir1/target.tar.gz', 'r')
199
self.addCleanup(file2.close)
200
content1 = file1.read()
201
content2 = file2.read()
202
self.assertEqualDiff(content1, content2)
203
# the gzip module doesn't have a way to read back to the original
204
# filename, but it's stored as-is in the tarfile.
205
self.assertFalse("testdir1" in content1)
206
self.assertFalse("target.tar.gz" in content1)
207
self.assertTrue("target.tar" in content1)
210
wt = self.make_branch_and_tree('.')
211
self.build_tree(['a'])
214
export.export(wt, 'target.tar.bz2', format="tbz2")
215
tf = tarfile.open('target.tar.bz2')
216
self.assertEquals(["target/a"], tf.getnames())
218
def test_xz_stdout(self):
219
wt = self.make_branch_and_tree('.')
220
self.assertRaises(errors.BzrError, export.export, wt, '-',
223
def test_export_tarball(self):
224
wt = self.make_branch_and_tree('.')
225
self.build_tree(['a'])
227
wt.commit("1", timestamp=42)
229
ball = tarfile.open(None, "w|", target)
232
export_tarball(wt, ball, "bar")
235
self.assertEquals(["bar/a"], ball.getnames())
239
class ZipExporterTests(tests.TestCaseWithTransport):
241
def test_per_file_timestamps(self):
242
tree = self.make_branch_and_tree('.')
243
self.build_tree_contents([('har', 'foo')])
245
# Earliest allowable date on FAT32 filesystems is 1980-01-01
246
timestamp = 347151600
247
tree.commit('setup', timestamp=timestamp)
248
export.export(tree.basis_tree(), 'test.zip', format='zip',
249
per_file_timestamps=True)
250
zfile = zipfile.ZipFile('test.zip')
251
info = zfile.getinfo("test/har")
252
self.assertEquals(time.localtime(timestamp)[:6], info.date_time)
255
class RootNameTests(tests.TestCase):
257
def test_root_name(self):
258
self.assertEquals('mytest', get_root_name('../mytest.tar'))
259
self.assertEquals('mytar', get_root_name('mytar.tar'))
260
self.assertEquals('mytar', get_root_name('mytar.tar.bz2'))
261
self.assertEquals('tar.tar.tar', get_root_name('tar.tar.tar.tgz'))
262
self.assertEquals('bzr-0.0.5', get_root_name('bzr-0.0.5.tar.gz'))
263
self.assertEquals('bzr-0.0.5', get_root_name('bzr-0.0.5.zip'))
264
self.assertEquals('bzr-0.0.5', get_root_name('bzr-0.0.5'))
265
self.assertEquals('mytar', get_root_name('a/long/path/mytar.tgz'))
266
self.assertEquals('other',
267
get_root_name('../parent/../dir/other.tbz2'))
268
self.assertEquals('', get_root_name('-'))