/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/zip.py

  • Committer: Jelmer Vernooij
  • Date: 2018-05-20 15:54:59 UTC
  • mfrom: (6968.2.10 archive)
  • mto: This revision was merged to the branch mainline in revision 6973.
  • Revision ID: jelmer@jelmer.uk-20180520155459-4u1tpealx8jj3sy3
Merge archive branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
from __future__ import absolute_import
21
21
 
 
22
from contextlib import closing
22
23
import os
23
24
import stat
24
25
import sys
 
26
import tempfile
25
27
import time
26
28
import zipfile
27
29
 
42
44
_DIR_ATTR = stat.S_IFDIR | ZIP_DIRECTORY_BIT | DIR_PERMISSIONS
43
45
 
44
46
 
45
 
def zip_exporter_generator(tree, dest, root, subdir=None,
46
 
    force_mtime=None, fileobj=None):
 
47
def zip_archive_generator(tree, dest, root, subdir=None,
 
48
    force_mtime=None):
47
49
    """ Export this tree to a new zip file.
48
50
 
49
51
    `dest` will be created holding the contents of this tree; if it
50
52
    already exists, it will be overwritten".
51
53
    """
52
 
 
53
54
    compression = zipfile.ZIP_DEFLATED
54
 
    if fileobj is not None:
55
 
        dest = fileobj
56
 
    elif dest == "-":
57
 
        dest = sys.stdout
58
 
    zipf = zipfile.ZipFile(dest, "w", compression)
59
 
    try:
60
 
        for dp, tp, ie in _export_iter_entries(tree, subdir):
61
 
            file_id = ie.file_id
62
 
            mutter("  export {%s} kind %s to %s", file_id, ie.kind, dest)
63
 
 
64
 
            # zipfile.ZipFile switches all paths to forward
65
 
            # slashes anyway, so just stick with that.
66
 
            if force_mtime is not None:
67
 
                mtime = force_mtime
68
 
            else:
69
 
                mtime = tree.get_file_mtime(tp, ie.file_id)
70
 
            date_time = time.localtime(mtime)[:6]
71
 
            filename = osutils.pathjoin(root, dp).encode('utf8')
72
 
            if ie.kind == "file":
73
 
                zinfo = zipfile.ZipInfo(
74
 
                            filename=filename,
75
 
                            date_time=date_time)
76
 
                zinfo.compress_type = compression
77
 
                zinfo.external_attr = _FILE_ATTR
78
 
                content = tree.get_file_text(tp, file_id)
79
 
                zipf.writestr(zinfo, content)
80
 
            elif ie.kind in ("directory", "tree-reference"):
81
 
                # Directories must contain a trailing slash, to indicate
82
 
                # to the zip routine that they are really directories and
83
 
                # not just empty files.
84
 
                zinfo = zipfile.ZipInfo(
85
 
                            filename=filename + '/',
86
 
                            date_time=date_time)
87
 
                zinfo.compress_type = compression
88
 
                zinfo.external_attr = _DIR_ATTR
89
 
                zipf.writestr(zinfo, '')
90
 
            elif ie.kind == "symlink":
91
 
                zinfo = zipfile.ZipInfo(
92
 
                            filename=(filename + '.lnk'),
93
 
                            date_time=date_time)
94
 
                zinfo.compress_type = compression
95
 
                zinfo.external_attr = _FILE_ATTR
96
 
                zipf.writestr(zinfo, tree.get_symlink_target(tp, file_id))
97
 
            yield
98
 
 
99
 
        zipf.close()
100
 
 
101
 
    except UnicodeEncodeError:
102
 
        zipf.close()
103
 
        os.remove(dest)
104
 
        from breezy.errors import BzrError
105
 
        raise BzrError("Can't export non-ascii filenames to zip")
 
55
    with tempfile.SpooledTemporaryFile() as buf:
 
56
        with closing(zipfile.ZipFile(buf, "w", compression)) as zipf, \
 
57
             tree.lock_read():
 
58
            for dp, tp, ie in _export_iter_entries(tree, subdir):
 
59
                file_id = ie.file_id
 
60
                mutter("  export {%s} kind %s to %s", file_id, ie.kind, dest)
 
61
 
 
62
                # zipfile.ZipFile switches all paths to forward
 
63
                # slashes anyway, so just stick with that.
 
64
                if force_mtime is not None:
 
65
                    mtime = force_mtime
 
66
                else:
 
67
                    mtime = tree.get_file_mtime(tp, ie.file_id)
 
68
                date_time = time.localtime(mtime)[:6]
 
69
                filename = osutils.pathjoin(root, dp).encode('utf8')
 
70
                if ie.kind == "file":
 
71
                    zinfo = zipfile.ZipInfo(
 
72
                                filename=filename,
 
73
                                date_time=date_time)
 
74
                    zinfo.compress_type = compression
 
75
                    zinfo.external_attr = _FILE_ATTR
 
76
                    content = tree.get_file_text(tp, file_id)
 
77
                    zipf.writestr(zinfo, content)
 
78
                elif ie.kind in ("directory", "tree-reference"):
 
79
                    # Directories must contain a trailing slash, to indicate
 
80
                    # to the zip routine that they are really directories and
 
81
                    # not just empty files.
 
82
                    zinfo = zipfile.ZipInfo(
 
83
                                filename=filename + '/',
 
84
                                date_time=date_time)
 
85
                    zinfo.compress_type = compression
 
86
                    zinfo.external_attr = _DIR_ATTR
 
87
                    zipf.writestr(zinfo, '')
 
88
                elif ie.kind == "symlink":
 
89
                    zinfo = zipfile.ZipInfo(
 
90
                                filename=(filename + '.lnk'),
 
91
                                date_time=date_time)
 
92
                    zinfo.compress_type = compression
 
93
                    zinfo.external_attr = _FILE_ATTR
 
94
                    zipf.writestr(zinfo, tree.get_symlink_target(tp, file_id))
 
95
        # Urgh, headers are written last since they include e.g. file size.
 
96
        # So we have to buffer it all :(
 
97
        buf.seek(0)
 
98
        for chunk in osutils.file_iterator(buf):
 
99
            yield chunk