/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: Jelmer Vernooij
  • Date: 2020-05-24 00:39:50 UTC
  • mto: This revision was merged to the branch mainline in revision 7504.
  • Revision ID: jelmer@jelmer.uk-20200524003950-bbc545r76vc5yajg
Add github action.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2009, 2010, 2011, 2016 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
 
 
17
"""Tests for breezy.export."""
 
18
 
 
19
import gzip
 
20
from io import BytesIO
 
21
import os
 
22
import tarfile
 
23
import time
 
24
import zipfile
 
25
 
 
26
from .. import (
 
27
    errors,
 
28
    export,
 
29
    tests,
 
30
    )
 
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):
 
39
        self.build_tree(['a/', 'a/b', 'a/c'])
 
40
        wt = self.make_branch_and_tree('.')
 
41
        wt.add(['a', 'a/b', 'a/c'])
 
42
        os.unlink('a/c')
 
43
        export.export(wt, 'target', format="dir")
 
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)
 
54
        wt = self.make_branch_and_tree('.')
 
55
        os.symlink('source', 'link')
 
56
        wt.add(['link'])
 
57
        export.export(wt, 'target', format="dir")
 
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):
 
94
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
 
95
        wt = self.make_branch_and_tree('source')
 
96
        wt.add(['a', 'b', 'b/c'])
 
97
        wt.commit('1')
 
98
        self.build_tree(['target/', 'target/foo'])
 
99
        self.assertRaises(errors.BzrError,
 
100
                          export.export, wt, 'target', format="dir")
 
101
 
 
102
    def test_existing_single_file(self):
 
103
        self.build_tree([
 
104
            'dir1/', 'dir1/dir2/', 'dir1/first', 'dir1/dir2/second'])
 
105
        wtree = self.make_branch_and_tree('dir1')
 
106
        wtree.add(['dir2', 'first', 'dir2/second'])
 
107
        wtree.commit('1')
 
108
        export.export(wtree, 'target1', format='dir', subdir='first')
 
109
        self.assertPathExists('target1/first')
 
110
        export.export(wtree, 'target2', format='dir', subdir='dir2/second')
 
111
        self.assertPathExists('target2/second')
 
112
 
 
113
    def test_files_same_timestamp(self):
 
114
        builder = self.make_branch_builder('source')
 
115
        builder.start_series()
 
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'))])
 
121
        builder.finish_series()
 
122
        b = builder.get_branch()
 
123
        b.lock_read()
 
124
        self.addCleanup(b.unlock)
 
125
        tree = b.basis_tree()
 
126
        orig_iter_files_bytes = tree.iter_files_bytes
 
127
 
 
128
        # Make iter_files_bytes slower, so we provoke mtime skew
 
129
        def iter_files_bytes(to_fetch):
 
130
            for thing in orig_iter_files_bytes(to_fetch):
 
131
                yield thing
 
132
                time.sleep(1)
 
133
        tree.iter_files_bytes = iter_files_bytes
 
134
        export.export(tree, 'target', format='dir')
 
135
        t = self.get_transport('target')
 
136
        st_a = t.stat('a')
 
137
        st_b = t.stat('b')
 
138
        # All files must be given the same mtime.
 
139
        self.assertEqual(st_a.st_mtime, st_b.st_mtime)
 
140
 
 
141
    def test_files_per_file_timestamps(self):
 
142
        builder = self.make_branch_builder('source')
 
143
        builder.start_series()
 
144
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
145
        a_time = time.mktime((1999, 12, 12, 0, 0, 0, 0, 0, 0))
 
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'))],
 
150
            timestamp=a_time)
 
151
        builder.build_snapshot(None, [
 
152
            ('add', ('b', b'b-id', 'file', b'content\n'))],
 
153
            timestamp=b_time)
 
154
        builder.finish_series()
 
155
        b = builder.get_branch()
 
156
        b.lock_read()
 
157
        self.addCleanup(b.unlock)
 
158
        tree = b.basis_tree()
 
159
        export.export(tree, 'target', format='dir', per_file_timestamps=True)
 
160
        t = self.get_transport('target')
 
161
        self.assertEqual(a_time, t.stat('a').st_mtime)
 
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('-'))