/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_export.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-08-23 01:15:41 UTC
  • mfrom: (7520.1.4 merge-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20200823011541-nv0oh7nzaganx2qy
Merge lp:brz/3.1.

Merged from https://code.launchpad.net/~jelmer/brz/merge-3.1/+merge/389690

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009, 2010 Canonical Ltd
 
1
# Copyright (C) 2009, 2010, 2011, 2016 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
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
 
17
"""Tests for breezy.export."""
 
18
 
 
19
import gzip
 
20
from io import BytesIO
17
21
import os
 
22
import tarfile
18
23
import time
 
24
import zipfile
19
25
 
20
 
from bzrlib import (
 
26
from .. import (
21
27
    errors,
22
28
    export,
23
29
    tests,
24
30
    )
25
 
 
26
 
 
27
 
class TestExport(tests.TestCaseWithTransport):
28
 
 
29
 
    def test_dir_export_missing_file(self):
 
31
from ..export import get_root_name
 
32
from ..archive.tar import tarball_generator
 
33
from . import features
 
34
 
 
35
 
 
36
class TestDirExport(tests.TestCaseWithTransport):
 
37
 
 
38
    def test_missing_file(self):
30
39
        self.build_tree(['a/', 'a/b', 'a/c'])
31
40
        wt = self.make_branch_and_tree('.')
32
41
        wt.add(['a', 'a/b', 'a/c'])
33
42
        os.unlink('a/c')
34
43
        export.export(wt, 'target', format="dir")
35
 
        self.failUnlessExists('target/a/b')
36
 
        self.failIfExists('target/a/c')
37
 
 
38
 
    def test_dir_export_symlink(self):
39
 
        self.requireFeature(tests.SymlinkFeature)
 
44
        self.assertPathExists('target/a/b')
 
45
        self.assertPathDoesNotExist('target/a/c')
 
46
 
 
47
    def test_empty(self):
 
48
        wt = self.make_branch_and_tree('.')
 
49
        export.export(wt, 'target', format="dir")
 
50
        self.assertEqual([], os.listdir("target"))
 
51
 
 
52
    def test_symlink(self):
 
53
        self.requireFeature(features.SymlinkFeature)
40
54
        wt = self.make_branch_and_tree('.')
41
55
        os.symlink('source', 'link')
42
56
        wt.add(['link'])
43
57
        export.export(wt, 'target', format="dir")
44
 
        self.failUnlessExists('target/link')
45
 
 
46
 
    def test_dir_export_to_existing_empty_dir_success(self):
47
 
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
48
 
        wt = self.make_branch_and_tree('source')
49
 
        wt.add(['a', 'b', 'b/c'])
50
 
        wt.commit('1')
51
 
        self.build_tree(['target/'])
52
 
        export.export(wt, 'target', format="dir")
53
 
        self.failUnlessExists('target/a')
54
 
        self.failUnlessExists('target/b')
55
 
        self.failUnlessExists('target/b/c')
56
 
 
57
 
    def test_dir_export_to_existing_nonempty_dir_fail(self):
 
58
        self.assertPathExists('target/link')
 
59
 
 
60
    def test_nested_tree(self):
 
61
        wt = self.make_branch_and_tree('.', format='development-subtree')
 
62
        subtree = self.make_branch_and_tree('subtree')
 
63
        self.build_tree(['subtree/file'])
 
64
        subtree.add(['file'])
 
65
        wt.add(['subtree'])
 
66
        export.export(wt, 'target', format="dir")
 
67
        self.assertPathExists('target/subtree')
 
68
        # TODO(jelmer): Once iter_entries_by_dir supports nested tree iteration:
 
69
        # self.assertPathExists('target/subtree/file')
 
70
 
 
71
    def test_to_existing_empty_dir_success(self):
 
72
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
 
73
        wt = self.make_branch_and_tree('source')
 
74
        wt.add(['a', 'b', 'b/c'])
 
75
        wt.commit('1')
 
76
        self.build_tree(['target/'])
 
77
        export.export(wt, 'target', format="dir")
 
78
        self.assertPathExists('target/a')
 
79
        self.assertPathExists('target/b')
 
80
        self.assertPathExists('target/b/c')
 
81
 
 
82
    def test_empty_subdir(self):
 
83
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
 
84
        wt = self.make_branch_and_tree('source')
 
85
        wt.add(['a', 'b', 'b/c'])
 
86
        wt.commit('1')
 
87
        self.build_tree(['target/'])
 
88
        export.export(wt, 'target', format="dir", subdir='')
 
89
        self.assertPathExists('target/a')
 
90
        self.assertPathExists('target/b')
 
91
        self.assertPathExists('target/b/c')
 
92
 
 
93
    def test_to_existing_nonempty_dir_fail(self):
58
94
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
59
95
        wt = self.make_branch_and_tree('source')
60
96
        wt.add(['a', 'b', 'b/c'])
61
97
        wt.commit('1')
62
98
        self.build_tree(['target/', 'target/foo'])
63
 
        self.assertRaises(errors.BzrError, export.export, wt, 'target', format="dir")
 
99
        self.assertRaises(errors.BzrError,
 
100
                          export.export, wt, 'target', format="dir")
64
101
 
65
 
    def test_dir_export_existing_single_file(self):
66
 
        self.build_tree(['dir1/', 'dir1/dir2/', 'dir1/first', 'dir1/dir2/second'])
 
102
    def test_existing_single_file(self):
 
103
        self.build_tree([
 
104
            'dir1/', 'dir1/dir2/', 'dir1/first', 'dir1/dir2/second'])
67
105
        wtree = self.make_branch_and_tree('dir1')
68
106
        wtree.add(['dir2', 'first', 'dir2/second'])
69
107
        wtree.commit('1')
70
108
        export.export(wtree, 'target1', format='dir', subdir='first')
71
 
        self.failUnlessExists('target1/first')
 
109
        self.assertPathExists('target1/first')
72
110
        export.export(wtree, 'target2', format='dir', subdir='dir2/second')
73
 
        self.failUnlessExists('target2/second')
74
 
        
75
 
    def test_dir_export_files_same_timestamp(self):
 
111
        self.assertPathExists('target2/second')
 
112
 
 
113
    def test_files_same_timestamp(self):
76
114
        builder = self.make_branch_builder('source')
77
115
        builder.start_series()
78
 
        builder.build_snapshot(None, None, [
79
 
            ('add', ('', 'root-id', 'directory', '')),
80
 
            ('add', ('a', 'a-id', 'file', 'content\n'))])
81
 
        builder.build_snapshot(None, None, [
82
 
            ('add', ('b', 'b-id', 'file', 'content\n'))])
 
116
        builder.build_snapshot(None, [
 
117
            ('add', ('', b'root-id', 'directory', '')),
 
118
            ('add', ('a', b'a-id', 'file', b'content\n'))])
 
119
        builder.build_snapshot(None, [
 
120
            ('add', ('b', b'b-id', 'file', b'content\n'))])
83
121
        builder.finish_series()
84
122
        b = builder.get_branch()
85
123
        b.lock_read()
86
124
        self.addCleanup(b.unlock)
87
125
        tree = b.basis_tree()
88
126
        orig_iter_files_bytes = tree.iter_files_bytes
 
127
 
89
128
        # Make iter_files_bytes slower, so we provoke mtime skew
90
129
        def iter_files_bytes(to_fetch):
91
130
            for thing in orig_iter_files_bytes(to_fetch):
99
138
        # All files must be given the same mtime.
100
139
        self.assertEqual(st_a.st_mtime, st_b.st_mtime)
101
140
 
102
 
    def test_dir_export_files_per_file_timestamps(self):
 
141
    def test_files_per_file_timestamps(self):
103
142
        builder = self.make_branch_builder('source')
104
143
        builder.start_series()
105
144
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
106
145
        a_time = time.mktime((1999, 12, 12, 0, 0, 0, 0, 0, 0))
107
 
        b_time = time.mktime((1980, 01, 01, 0, 0, 0, 0, 0, 0))
108
 
        builder.build_snapshot(None, None, [
109
 
            ('add', ('', 'root-id', 'directory', '')),
110
 
            ('add', ('a', 'a-id', 'file', 'content\n'))],
 
146
        b_time = time.mktime((1980, 0o1, 0o1, 0, 0, 0, 0, 0, 0))
 
147
        builder.build_snapshot(None, [
 
148
            ('add', ('', b'root-id', 'directory', '')),
 
149
            ('add', ('a', b'a-id', 'file', b'content\n'))],
111
150
            timestamp=a_time)
112
 
        builder.build_snapshot(None, None, [
113
 
            ('add', ('b', 'b-id', 'file', 'content\n'))],
 
151
        builder.build_snapshot(None, [
 
152
            ('add', ('b', b'b-id', 'file', b'content\n'))],
114
153
            timestamp=b_time)
115
154
        builder.finish_series()
116
155
        b = builder.get_branch()
121
160
        t = self.get_transport('target')
122
161
        self.assertEqual(a_time, t.stat('a').st_mtime)
123
162
        self.assertEqual(b_time, t.stat('b').st_mtime)
 
163
 
 
164
    def test_subdir_files_per_timestamps(self):
 
165
        builder = self.make_branch_builder('source')
 
166
        builder.start_series()
 
167
        foo_time = time.mktime((1999, 12, 12, 0, 0, 0, 0, 0, 0))
 
168
        builder.build_snapshot(None, [
 
169
            ('add', ('', b'root-id', 'directory', '')),
 
170
            ('add', ('subdir', b'subdir-id', 'directory', '')),
 
171
            ('add', ('subdir/foo.txt', b'foo-id', 'file', b'content\n'))],
 
172
            timestamp=foo_time)
 
173
        builder.finish_series()
 
174
        b = builder.get_branch()
 
175
        b.lock_read()
 
176
        self.addCleanup(b.unlock)
 
177
        tree = b.basis_tree()
 
178
        export.export(tree, 'target', format='dir', subdir='subdir',
 
179
                      per_file_timestamps=True)
 
180
        t = self.get_transport('target')
 
181
        self.assertEqual(foo_time, t.stat('foo.txt').st_mtime)
 
182
 
 
183
 
 
184
class TarExporterTests(tests.TestCaseWithTransport):
 
185
 
 
186
    def test_xz(self):
 
187
        self.requireFeature(features.lzma)
 
188
        import lzma
 
189
        wt = self.make_branch_and_tree('.')
 
190
        self.build_tree(['a'])
 
191
        wt.add(["a"])
 
192
        wt.commit("1")
 
193
        export.export(wt, 'target.tar.xz', format="txz")
 
194
        tf = tarfile.open(fileobj=lzma.LZMAFile('target.tar.xz'))
 
195
        self.assertEqual(["target/a"], tf.getnames())
 
196
 
 
197
    def test_lzma(self):
 
198
        self.requireFeature(features.lzma)
 
199
        import lzma
 
200
        wt = self.make_branch_and_tree('.')
 
201
        self.build_tree(['a'])
 
202
        wt.add(["a"])
 
203
        wt.commit("1")
 
204
        export.export(wt, 'target.tar.lzma', format="tlzma")
 
205
        tf = tarfile.open(fileobj=lzma.LZMAFile('target.tar.lzma'))
 
206
        self.assertEqual(["target/a"], tf.getnames())
 
207
 
 
208
    def test_tgz(self):
 
209
        wt = self.make_branch_and_tree('.')
 
210
        self.build_tree(['a'])
 
211
        wt.add(["a"])
 
212
        wt.commit("1")
 
213
        export.export(wt, 'target.tar.gz', format="tgz")
 
214
        tf = tarfile.open('target.tar.gz')
 
215
        self.assertEqual(["target/a"], tf.getnames())
 
216
 
 
217
    def test_tgz_consistent_mtime(self):
 
218
        wt = self.make_branch_and_tree('.')
 
219
        self.build_tree(['a'])
 
220
        wt.add(["a"])
 
221
        timestamp = 1547400500
 
222
        revid = wt.commit("1", timestamp=timestamp)
 
223
        revtree = wt.branch.repository.revision_tree(revid)
 
224
        export.export(revtree, 'target.tar.gz', format="tgz")
 
225
        with gzip.GzipFile('target.tar.gz', 'r') as f:
 
226
            f.read()
 
227
            self.assertEqual(int(f.mtime), timestamp)
 
228
 
 
229
    def test_tgz_ignores_dest_path(self):
 
230
        # The target path should not be a part of the target file.
 
231
        # (bug #102234)
 
232
        wt = self.make_branch_and_tree('.')
 
233
        self.build_tree(['a'])
 
234
        wt.add(["a"])
 
235
        wt.commit("1")
 
236
        os.mkdir("testdir1")
 
237
        os.mkdir("testdir2")
 
238
        export.export(wt, 'testdir1/target.tar.gz', format="tgz",
 
239
                      per_file_timestamps=True)
 
240
        export.export(wt, 'testdir2/target.tar.gz', format="tgz",
 
241
                      per_file_timestamps=True)
 
242
        file1 = open('testdir1/target.tar.gz', 'rb')
 
243
        self.addCleanup(file1.close)
 
244
        file2 = open('testdir1/target.tar.gz', 'rb')
 
245
        self.addCleanup(file2.close)
 
246
        content1 = file1.read()
 
247
        content2 = file2.read()
 
248
        self.assertEqualDiff(content1, content2)
 
249
        # the gzip module doesn't have a way to read back to the original
 
250
        # filename, but it's stored as-is in the tarfile.
 
251
        self.assertFalse(b"testdir1" in content1)
 
252
        self.assertFalse(b"target.tar.gz" in content1)
 
253
        self.assertTrue(b"target.tar" in content1)
 
254
 
 
255
    def test_tbz2(self):
 
256
        wt = self.make_branch_and_tree('.')
 
257
        self.build_tree(['a'])
 
258
        wt.add(["a"])
 
259
        wt.commit("1")
 
260
        export.export(wt, 'target.tar.bz2', format="tbz2")
 
261
        tf = tarfile.open('target.tar.bz2')
 
262
        self.assertEqual(["target/a"], tf.getnames())
 
263
 
 
264
    def test_export_tarball_generator(self):
 
265
        wt = self.make_branch_and_tree('.')
 
266
        self.build_tree(['a'])
 
267
        wt.add(["a"])
 
268
        wt.commit("1", timestamp=42)
 
269
        target = BytesIO()
 
270
        with wt.lock_read():
 
271
            target.writelines(tarball_generator(wt, "bar"))
 
272
        # Ball should now be closed.
 
273
        target.seek(0)
 
274
        ball2 = tarfile.open(None, "r", target)
 
275
        self.addCleanup(ball2.close)
 
276
        self.assertEqual(["bar/a"], ball2.getnames())
 
277
 
 
278
 
 
279
class ZipExporterTests(tests.TestCaseWithTransport):
 
280
 
 
281
    def test_per_file_timestamps(self):
 
282
        tree = self.make_branch_and_tree('.')
 
283
        self.build_tree_contents([('har', b'foo')])
 
284
        tree.add('har')
 
285
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
286
        timestamp = 347151600
 
287
        tree.commit('setup', timestamp=timestamp)
 
288
        export.export(tree.basis_tree(), 'test.zip', format='zip',
 
289
                      per_file_timestamps=True)
 
290
        zfile = zipfile.ZipFile('test.zip')
 
291
        info = zfile.getinfo("test/har")
 
292
        self.assertEqual(time.localtime(timestamp)[:6], info.date_time)
 
293
 
 
294
 
 
295
class RootNameTests(tests.TestCase):
 
296
 
 
297
    def test_root_name(self):
 
298
        self.assertEqual('mytest', get_root_name('../mytest.tar'))
 
299
        self.assertEqual('mytar', get_root_name('mytar.tar'))
 
300
        self.assertEqual('mytar', get_root_name('mytar.tar.bz2'))
 
301
        self.assertEqual('tar.tar.tar', get_root_name('tar.tar.tar.tgz'))
 
302
        self.assertEqual('bzr-0.0.5', get_root_name('bzr-0.0.5.tar.gz'))
 
303
        self.assertEqual('bzr-0.0.5', get_root_name('bzr-0.0.5.zip'))
 
304
        self.assertEqual('bzr-0.0.5', get_root_name('bzr-0.0.5'))
 
305
        self.assertEqual('mytar', get_root_name('a/long/path/mytar.tgz'))
 
306
        self.assertEqual('other',
 
307
                         get_root_name('../parent/../dir/other.tbz2'))
 
308
        self.assertEqual('', get_root_name('-'))