/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/archive/tar.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2008, 2009, 2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2008-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
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
 
"""Export a Tree to a non-versioned directory.
18
 
"""
19
 
 
20
 
import StringIO
 
17
"""Export a tree to a tarball."""
 
18
 
 
19
from __future__ import absolute_import
 
20
 
 
21
from contextlib import closing
 
22
import os
21
23
import sys
22
24
import tarfile
23
 
import time
24
 
 
25
 
from bzrlib import export, osutils
26
 
from bzrlib.export import _export_iter_entries
27
 
from bzrlib.filters import (
28
 
    ContentFilterContext,
29
 
    filtered_output_bytes,
30
 
    )
31
 
from bzrlib.trace import mutter
32
 
 
33
 
 
34
 
def tar_exporter(tree, dest, root, subdir, compression=None, filtered=False,
35
 
                 per_file_timestamps=False):
36
 
    """Export this tree to a new tar file.
37
 
 
38
 
    `dest` will be created holding the contents of this tree; if it
39
 
    already exists, it will be clobbered, like with "tar -c".
40
 
    """
41
 
    mutter('export version %r', tree)
42
 
    now = time.time()
43
 
    compression = str(compression or '')
44
 
    if dest == '-':
45
 
        # XXX: If no root is given, the output tarball will contain files
46
 
        # named '-/foo'; perhaps this is the most reasonable thing.
47
 
        ball = tarfile.open(None, 'w|' + compression, sys.stdout)
48
 
    else:
49
 
        if root is None:
50
 
            root = export.get_root_name(dest)
51
 
 
52
 
        # tarfile.open goes on to do 'os.getcwd() + dest' for opening
53
 
        # the tar file. With dest being unicode, this throws UnicodeDecodeError
54
 
        # unless we encode dest before passing it on. This works around
55
 
        # upstream python bug http://bugs.python.org/issue8396
56
 
        # (fixed in Python 2.6.5 and 2.7b1)
57
 
        ball = tarfile.open(dest.encode(osutils._fs_enc), 'w:' + compression)
58
 
 
59
 
    for dp, ie in _export_iter_entries(tree, subdir):
60
 
        filename = osutils.pathjoin(root, dp).encode('utf8')
61
 
        item = tarfile.TarInfo(filename)
62
 
        if per_file_timestamps:
63
 
            item.mtime = tree.get_file_mtime(ie.file_id, dp)
64
 
        else:
65
 
            item.mtime = now
66
 
        if ie.kind == "file":
67
 
            item.type = tarfile.REGTYPE
68
 
            if tree.is_executable(ie.file_id):
69
 
                item.mode = 0755
70
 
            else:
71
 
                item.mode = 0644
72
 
            if filtered:
73
 
                chunks = tree.get_file_lines(ie.file_id)
74
 
                filters = tree._content_filter_stack(dp)
75
 
                context = ContentFilterContext(dp, tree, ie)
76
 
                contents = filtered_output_bytes(chunks, filters, context)
77
 
                content = ''.join(contents)
78
 
                item.size = len(content)
79
 
                fileobj = StringIO.StringIO(content)
80
 
            else:
81
 
                item.size = ie.text_size
82
 
                fileobj = tree.get_file(ie.file_id)
83
 
        elif ie.kind == "directory":
84
 
            item.type = tarfile.DIRTYPE
85
 
            item.name += '/'
86
 
            item.size = 0
87
 
            item.mode = 0755
88
 
            fileobj = None
89
 
        elif ie.kind == "symlink":
90
 
            item.type = tarfile.SYMTYPE
91
 
            item.size = 0
92
 
            item.mode = 0755
93
 
            item.linkname = ie.symlink_target
94
 
            fileobj = None
95
 
        else:
96
 
            raise BzrError("don't know how to export {%s} of kind %r" %
97
 
                           (ie.file_id, ie.kind))
98
 
        ball.addfile(item, fileobj)
99
 
    ball.close()
100
 
 
101
 
 
102
 
def tgz_exporter(tree, dest, root, subdir, filtered=False,
103
 
                 per_file_timestamps=False):
104
 
    tar_exporter(tree, dest, root, subdir, compression='gz',
105
 
                 filtered=filtered, per_file_timestamps=per_file_timestamps)
106
 
 
107
 
 
108
 
def tbz_exporter(tree, dest, root, subdir, filtered=False,
109
 
                 per_file_timestamps=False):
110
 
    tar_exporter(tree, dest, root, subdir, compression='bz2',
111
 
                 filtered=filtered, per_file_timestamps=per_file_timestamps)
 
25
 
 
26
from .. import (
 
27
    errors,
 
28
    osutils,
 
29
    )
 
30
from ..export import _export_iter_entries
 
31
from ..sixish import (
 
32
    BytesIO,
 
33
    )
 
34
 
 
35
 
 
36
def prepare_tarball_item(tree, root, final_path, tree_path, entry, force_mtime=None):
 
37
    """Prepare a tarball item for exporting
 
38
 
 
39
    :param tree: Tree to export
 
40
    :param final_path: Final path to place item
 
41
    :param tree_path: Path for the entry in the tree
 
42
    :param entry: Entry to export
 
43
    :param force_mtime: Option mtime to force, instead of using tree
 
44
        timestamps.
 
45
 
 
46
    Returns a (tarinfo, fileobj) tuple
 
47
    """
 
48
    file_id = getattr(entry, 'file_id', None)
 
49
    filename = osutils.pathjoin(root, final_path)
 
50
    item = tarfile.TarInfo(filename)
 
51
    if force_mtime is not None:
 
52
        item.mtime = force_mtime
 
53
    else:
 
54
        item.mtime = tree.get_file_mtime(tree_path)
 
55
    if entry.kind == "file":
 
56
        item.type = tarfile.REGTYPE
 
57
        if tree.is_executable(tree_path):
 
58
            item.mode = 0o755
 
59
        else:
 
60
            item.mode = 0o644
 
61
        # This brings the whole file into memory, but that's almost needed for
 
62
        # the tarfile contract, which wants the size of the file up front.  We
 
63
        # want to make sure it doesn't change, and we need to read it in one
 
64
        # go for content filtering.
 
65
        content = tree.get_file_text(tree_path)
 
66
        item.size = len(content)
 
67
        fileobj = BytesIO(content)
 
68
    elif entry.kind in ("directory", "tree-reference"):
 
69
        item.type = tarfile.DIRTYPE
 
70
        item.name += '/'
 
71
        item.size = 0
 
72
        item.mode = 0o755
 
73
        fileobj = None
 
74
    elif entry.kind == "symlink":
 
75
        item.type = tarfile.SYMTYPE
 
76
        item.size = 0
 
77
        item.mode = 0o755
 
78
        item.linkname = tree.get_symlink_target(tree_path)
 
79
        fileobj = None
 
80
    else:
 
81
        raise errors.BzrError("don't know how to export {%s} of kind %r"
 
82
                              % (file_id, entry.kind))
 
83
    return (item, fileobj)
 
84
 
 
85
 
 
86
def tarball_generator(tree, root, subdir=None, force_mtime=None, format=''):
 
87
    """Export tree contents to a tarball.
 
88
 
 
89
    :returns: A generator that will produce file content chunks.
 
90
 
 
91
    :param tree: Tree to export
 
92
 
 
93
    :param subdir: Sub directory to export
 
94
 
 
95
    :param force_mtime: Option mtime to force, instead of using tree
 
96
        timestamps.
 
97
    """
 
98
    buf = BytesIO()
 
99
    with closing(tarfile.open(None, "w:%s" % format, buf)) as ball, tree.lock_read():
 
100
        for final_path, tree_path, entry in _export_iter_entries(tree, subdir):
 
101
            (item, fileobj) = prepare_tarball_item(
 
102
                tree, root, final_path, tree_path, entry, force_mtime)
 
103
            ball.addfile(item, fileobj)
 
104
            # Yield the data that was written so far, rinse, repeat.
 
105
            yield buf.getvalue()
 
106
            buf.truncate(0)
 
107
            buf.seek(0)
 
108
    yield buf.getvalue()
 
109
 
 
110
 
 
111
def tgz_generator(tree, dest, root, subdir, force_mtime=None):
 
112
    """Export this tree to a new tar file.
 
113
 
 
114
    `dest` will be created holding the contents of this tree; if it
 
115
    already exists, it will be clobbered, like with "tar -c".
 
116
    """
 
117
    with tree.lock_read():
 
118
        import gzip
 
119
        if force_mtime is not None:
 
120
            root_mtime = force_mtime
 
121
        elif (getattr(tree, "repository", None) and
 
122
              getattr(tree, "get_revision_id", None)):
 
123
            # If this is a revision tree, use the revisions' timestamp
 
124
            rev = tree.repository.get_revision(tree.get_revision_id())
 
125
            root_mtime = rev.timestamp
 
126
        elif tree.is_versioned(u''):
 
127
            root_mtime = tree.get_file_mtime('')
 
128
        else:
 
129
            root_mtime = None
 
130
 
 
131
        is_stdout = False
 
132
        basename = None
 
133
        # gzip file is used with an explicit fileobj so that
 
134
        # the basename can be stored in the gzip file rather than
 
135
        # dest. (bug 102234)
 
136
        basename = os.path.basename(dest)
 
137
        buf = BytesIO()
 
138
        zipstream = gzip.GzipFile(basename, 'w', fileobj=buf,
 
139
                                  mtime=root_mtime)
 
140
        for chunk in tarball_generator(tree, root, subdir, force_mtime):
 
141
            zipstream.write(chunk)
 
142
            # Yield the data that was written so far, rinse, repeat.
 
143
            yield buf.getvalue()
 
144
            buf.truncate(0)
 
145
            buf.seek(0)
 
146
        # Closing zipstream may trigger writes to stream
 
147
        zipstream.close()
 
148
        yield buf.getvalue()
 
149
 
 
150
 
 
151
def tbz_generator(tree, dest, root, subdir, force_mtime=None):
 
152
    """Export this tree to a new tar file.
 
153
 
 
154
    `dest` will be created holding the contents of this tree; if it
 
155
    already exists, it will be clobbered, like with "tar -c".
 
156
    """
 
157
    return tarball_generator(
 
158
        tree, root, subdir, force_mtime, format='bz2')
 
159
 
 
160
 
 
161
def plain_tar_generator(tree, dest, root, subdir,
 
162
                        force_mtime=None):
 
163
    """Export this tree to a new tar file.
 
164
 
 
165
    `dest` will be created holding the contents of this tree; if it
 
166
    already exists, it will be clobbered, like with "tar -c".
 
167
    """
 
168
    return tarball_generator(
 
169
        tree, root, subdir, force_mtime, format='')
 
170
 
 
171
 
 
172
def tar_xz_generator(tree, dest, root, subdir, force_mtime=None):
 
173
    return tar_lzma_generator(tree, dest, root, subdir, force_mtime, "xz")
 
174
 
 
175
 
 
176
def tar_lzma_generator(tree, dest, root, subdir, force_mtime=None,
 
177
                       compression_format="alone"):
 
178
    """Export this tree to a new .tar.lzma file.
 
179
 
 
180
    `dest` will be created holding the contents of this tree; if it
 
181
    already exists, it will be clobbered, like with "tar -c".
 
182
    """
 
183
    try:
 
184
        import lzma
 
185
    except ImportError as e:
 
186
        raise errors.DependencyNotPresent('lzma', e)
 
187
 
 
188
    if sys.version_info[0] == 2:
 
189
        compressor = lzma.LZMACompressor(
 
190
            options={"format": compression_format})
 
191
    else:
 
192
        compressor = lzma.LZMACompressor(
 
193
            format={
 
194
                'xz': lzma.FORMAT_XZ,
 
195
                'raw': lzma.FORMAT_RAW,
 
196
                'alone': lzma.FORMAT_ALONE,
 
197
                }[compression_format])
 
198
 
 
199
    for chunk in tarball_generator(
 
200
            tree, root, subdir, force_mtime=force_mtime):
 
201
        yield compressor.compress(chunk)
 
202
 
 
203
    yield compressor.flush()