~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/export/__init__.py

  • Committer: Vincent Ladeuil
  • Date: 2017-01-17 13:48:10 UTC
  • mfrom: (6615.3.6 merges)
  • mto: This revision was merged to the branch mainline in revision 6620.
  • Revision ID: v.ladeuil+lp@free.fr-20170117134810-j9p3lidfy6pfyfsc
Merge 2.7, resolving conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-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 functionality, which can take a Tree and create a different representation.
18
 
 
19
 
Such as non-controlled directories, tarfiles, zipfiles, etc.
 
17
"""Export trees to tarballs, non-controlled directories, zipfiles, etc.
20
18
"""
21
19
 
 
20
from __future__ import absolute_import
 
21
 
22
22
import os
23
 
import bzrlib.errors as errors
 
23
import time
 
24
import warnings
 
25
 
 
26
from bzrlib import (
 
27
    errors,
 
28
    pyutils,
 
29
    trace,
 
30
    )
24
31
 
25
32
# Maps format name => export function
26
33
_exporters = {}
27
34
# Maps filename extensions => export format name
28
35
_exporter_extensions = {}
29
36
 
 
37
 
30
38
def register_exporter(format, extensions, func, override=False):
31
39
    """Register an exporter.
32
40
 
54
62
 
55
63
    When requesting a specific type of export, load the respective path.
56
64
    """
57
 
    def _loader(tree, dest, root, subdir, filtered, per_file_timestamps):
58
 
        mod = __import__(module, globals(), locals(), [funcname])
59
 
        func = getattr(mod, funcname)
60
 
        return func(tree, dest, root, subdir, filtered=filtered,
61
 
                    per_file_timestamps=per_file_timestamps)
 
65
    def _loader(tree, dest, root, subdir, force_mtime, fileobj):
 
66
        func = pyutils.get_named_object(module, funcname)
 
67
        return func(tree, dest, root, subdir, force_mtime=force_mtime,
 
68
            fileobj=fileobj)
 
69
 
62
70
    register_exporter(scheme, extensions, _loader)
63
71
 
64
72
 
65
 
def export(tree, dest, format=None, root=None, subdir=None, filtered=False,
66
 
           per_file_timestamps=False):
67
 
    """Export the given Tree to the specific destination.
 
73
def get_export_generator(tree, dest=None, format=None, root=None, subdir=None,
 
74
                         filtered=False, per_file_timestamps=False,
 
75
                         fileobj=None):
 
76
    """Returns a generator that exports the given tree.
 
77
 
 
78
    The generator is expected to yield None while exporting the tree while the
 
79
    actual export is written to ``fileobj``.
68
80
 
69
81
    :param tree: A Tree (such as RevisionTree) to export
70
 
    :param dest: The destination where the files,etc should be put
 
82
 
 
83
    :param dest: The destination where the files, etc should be put
 
84
 
71
85
    :param format: The format (dir, zip, etc), if None, it will check the
72
 
                   extension on dest, looking for a match
73
 
    :param root: The root location inside the format.
74
 
                 It is common practise to have zipfiles and tarballs
75
 
                 extract into a subdirectory, rather than into the
76
 
                 current working directory.
77
 
                 If root is None, the default root will be
78
 
                 selected as the destination without its
79
 
                 extension.
 
86
        extension on dest, looking for a match
 
87
 
 
88
    :param root: The root location inside the format.  It is common practise to
 
89
        have zipfiles and tarballs extract into a subdirectory, rather than
 
90
        into the current working directory.  If root is None, the default root
 
91
        will be selected as the destination without its extension.
 
92
 
80
93
    :param subdir: A starting directory within the tree. None means to export
81
94
        the entire tree, and anything else should specify the relative path to
82
95
        a directory to start exporting from.
83
 
    :param filtered: If True, content filtering is applied to the
84
 
                     files exported.
85
 
    :param per_file_timestamps: Whether to use the timestamp stored in the 
86
 
        tree rather than now(). This will do a revision lookup 
87
 
        for every file so will be significantly slower.
 
96
 
 
97
    :param filtered: If True, content filtering is applied to the exported
 
98
        files.  Deprecated in favour of passing a ContentFilterTree
 
99
        as the source.
 
100
 
 
101
    :param per_file_timestamps: Whether to use the timestamp stored in the tree
 
102
        rather than now(). This will do a revision lookup for every file so
 
103
        will be significantly slower.
 
104
 
 
105
    :param fileobj: Optional file object to use
88
106
    """
89
107
    global _exporters, _exporter_extensions
90
108
 
91
 
    if format is None:
 
109
    if format is None and dest is not None:
92
110
        for ext in _exporter_extensions:
93
111
            if dest.endswith(ext):
94
112
                format = _exporter_extensions[ext]
101
119
 
102
120
    if format not in _exporters:
103
121
        raise errors.NoSuchExportFormat(format)
 
122
 
 
123
    if not per_file_timestamps:
 
124
        force_mtime = time.time()
 
125
    else:
 
126
        force_mtime = None
 
127
 
 
128
    trace.mutter('export version %r', tree)
 
129
 
 
130
    if filtered:
 
131
        from bzrlib.filter_tree import ContentFilterTree
 
132
        warnings.warn(
 
133
            "passing filtered=True to export is deprecated in bzr 2.4",
 
134
            stacklevel=2)
 
135
        tree = ContentFilterTree(tree, tree._content_filter_stack)
 
136
        # We don't want things re-filtered by the specific exporter.
 
137
        filtered = False
 
138
 
104
139
    tree.lock_read()
105
140
    try:
106
 
        return _exporters[format](tree, dest, root, subdir, filtered=filtered,
107
 
                                  per_file_timestamps=per_file_timestamps)
 
141
        for _ in _exporters[format](
 
142
            tree, dest, root, subdir,
 
143
            force_mtime=force_mtime, fileobj=fileobj):
 
144
            yield
108
145
    finally:
109
146
        tree.unlock()
110
147
 
111
148
 
 
149
def export(tree, dest, format=None, root=None, subdir=None, filtered=False,
 
150
           per_file_timestamps=False, fileobj=None):
 
151
    """Export the given Tree to the specific destination.
 
152
 
 
153
    :param tree: A Tree (such as RevisionTree) to export
 
154
    :param dest: The destination where the files,etc should be put
 
155
    :param format: The format (dir, zip, etc), if None, it will check the
 
156
                   extension on dest, looking for a match
 
157
    :param root: The root location inside the format.
 
158
                 It is common practise to have zipfiles and tarballs
 
159
                 extract into a subdirectory, rather than into the
 
160
                 current working directory.
 
161
                 If root is None, the default root will be
 
162
                 selected as the destination without its
 
163
                 extension.
 
164
    :param subdir: A starting directory within the tree. None means to export
 
165
        the entire tree, and anything else should specify the relative path to
 
166
        a directory to start exporting from.
 
167
    :param filtered: If True, content filtering is applied to the
 
168
        files exported.  Deprecated in favor of passing an ContentFilterTree.
 
169
    :param per_file_timestamps: Whether to use the timestamp stored in the
 
170
        tree rather than now(). This will do a revision lookup
 
171
        for every file so will be significantly slower.
 
172
    :param fileobj: Optional file object to use
 
173
    """
 
174
    for _ in get_export_generator(tree, dest, format, root, subdir, filtered,
 
175
                                  per_file_timestamps, fileobj):
 
176
        pass
 
177
 
 
178
 
112
179
def get_root_name(dest):
113
180
    """Get just the root name for an export.
114
181
 
115
 
    >>> get_root_name('../mytest.tar')
116
 
    'mytest'
117
 
    >>> get_root_name('mytar.tar')
118
 
    'mytar'
119
 
    >>> get_root_name('mytar.tar.bz2')
120
 
    'mytar'
121
 
    >>> get_root_name('tar.tar.tar.tgz')
122
 
    'tar.tar.tar'
123
 
    >>> get_root_name('bzr-0.0.5.tar.gz')
124
 
    'bzr-0.0.5'
125
 
    >>> get_root_name('bzr-0.0.5.zip')
126
 
    'bzr-0.0.5'
127
 
    >>> get_root_name('bzr-0.0.5')
128
 
    'bzr-0.0.5'
129
 
    >>> get_root_name('a/long/path/mytar.tgz')
130
 
    'mytar'
131
 
    >>> get_root_name('../parent/../dir/other.tbz2')
132
 
    'other'
133
182
    """
134
183
    global _exporter_extensions
 
184
    if dest == '-':
 
185
        # Exporting to -/foo doesn't make sense so use relative paths.
 
186
        return ''
135
187
    dest = os.path.basename(dest)
136
188
    for ext in _exporter_extensions:
137
189
        if dest.endswith(ext):
139
191
    return dest
140
192
 
141
193
 
142
 
def _export_iter_entries(tree, subdir):
 
194
def _export_iter_entries(tree, subdir, skip_special=True):
143
195
    """Iter the entries for tree suitable for exporting.
144
196
 
145
197
    :param tree: A tree object.
146
198
    :param subdir: None or the path of an entry to start exporting from.
 
199
    :param skip_special: Whether to skip .bzr files.
 
200
    :return: iterator over tuples with final path, tree path and inventory
 
201
        entry for each entry to export
147
202
    """
148
 
    inv = tree.inventory
149
 
    if subdir is None:
150
 
        subdir_object = None
151
 
    else:
152
 
        subdir_id = inv.path2id(subdir)
153
 
        if subdir_id is not None:
154
 
            subdir_object = inv[subdir_id]
155
 
        # XXX: subdir is path not an id, so NoSuchId isn't proper error
156
 
        else:
157
 
            raise errors.NoSuchId(tree, subdir)
158
 
    if subdir_object is not None and subdir_object.kind != 'directory':
159
 
        yield subdir_object.name, subdir_object
160
 
        return
161
 
    else:
162
 
        entries = inv.iter_entries(subdir_object)
163
 
    if subdir is None:
164
 
        entries.next() # skip root
165
 
    for entry in entries:
 
203
    if subdir == '':
 
204
        subdir = None
 
205
    if subdir is not None:
 
206
        subdir = subdir.rstrip('/')
 
207
    entries = tree.iter_entries_by_dir()
 
208
    entries.next()  # skip root
 
209
    for path, entry in entries:
166
210
        # The .bzr* namespace is reserved for "magic" files like
167
211
        # .bzrignore and .bzrrules - do not export these
168
 
        if entry[0].startswith(".bzr"):
 
212
        if skip_special and path.startswith(".bzr"):
169
213
            continue
170
 
        if subdir is None:
171
 
            if not tree.has_filename(entry[0]):
 
214
        if path == subdir:
 
215
            if entry.kind == 'directory':
 
216
                continue
 
217
            final_path = entry.name
 
218
        elif subdir is not None:
 
219
            if path.startswith(subdir + '/'):
 
220
                final_path = path[len(subdir) + 1:]
 
221
            else:
172
222
                continue
173
223
        else:
174
 
            if not tree.has_filename(os.path.join(subdir, entry[0])):
175
 
                continue
176
 
        yield entry
177
 
 
178
 
 
179
 
register_lazy_exporter(None, [], 'bzrlib.export.dir_exporter', 'dir_exporter')
180
 
register_lazy_exporter('dir', [], 'bzrlib.export.dir_exporter', 'dir_exporter')
181
 
register_lazy_exporter('tar', ['.tar'], 'bzrlib.export.tar_exporter', 'tar_exporter')
182
 
register_lazy_exporter('tgz', ['.tar.gz', '.tgz'], 'bzrlib.export.tar_exporter', 'tgz_exporter')
183
 
register_lazy_exporter('tbz2', ['.tar.bz2', '.tbz2'], 'bzrlib.export.tar_exporter', 'tbz_exporter')
184
 
register_lazy_exporter('zip', ['.zip'], 'bzrlib.export.zip_exporter', 'zip_exporter')
185
 
 
 
224
            final_path = path
 
225
        if not tree.has_filename(path):
 
226
            continue
 
227
 
 
228
        yield final_path, path, entry
 
229
 
 
230
 
 
231
register_lazy_exporter(None, [], 'bzrlib.export.dir_exporter',
 
232
                       'dir_exporter_generator')
 
233
register_lazy_exporter('dir', [], 'bzrlib.export.dir_exporter',
 
234
                       'dir_exporter_generator')
 
235
register_lazy_exporter('tar', ['.tar'], 'bzrlib.export.tar_exporter',
 
236
                       'plain_tar_exporter_generator')
 
237
register_lazy_exporter('tgz', ['.tar.gz', '.tgz'],
 
238
                       'bzrlib.export.tar_exporter',
 
239
                       'tgz_exporter_generator')
 
240
register_lazy_exporter('tbz2', ['.tar.bz2', '.tbz2'],
 
241
                       'bzrlib.export.tar_exporter', 'tbz_exporter_generator')
 
242
register_lazy_exporter('tlzma', ['.tar.lzma'], 'bzrlib.export.tar_exporter',
 
243
                       'tar_lzma_exporter_generator')
 
244
register_lazy_exporter('txz', ['.tar.xz'], 'bzrlib.export.tar_exporter',
 
245
                       'tar_xz_exporter_generator')
 
246
register_lazy_exporter('zip', ['.zip'], 'bzrlib.export.zip_exporter',
 
247
                       'zip_exporter_generator')