/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: Robert Collins
  • Date: 2005-10-19 10:11:57 UTC
  • mfrom: (1185.16.78)
  • mto: This revision was merged to the branch mainline in revision 1470.
  • Revision ID: robertc@robertcollins.net-20051019101157-17438d311e746b4f
mergeĀ fromĀ upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2008-2011 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
 
"""Export a tree to a tarball."""
18
 
 
19
 
from __future__ import absolute_import
20
 
 
21
 
from contextlib import closing
22
 
import os
23
 
import sys
24
 
import tarfile
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()