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
17
"""Export functionality, which can take a Tree and create a different representation.
19
Such as non-controlled directories, tarfiles, zipfiles, etc.
17
"""Export trees to tarballs, non-controlled directories, zipfiles, etc.
20
from __future__ import absolute_import
23
import bzrlib.errors as errors
25
32
# Maps format name => export function
27
34
# Maps filename extensions => export format name
28
35
_exporter_extensions = {}
30
38
def register_exporter(format, extensions, func, override=False):
31
39
"""Register an exporter.
55
63
When requesting a specific type of export, load the respective path.
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,
62
70
register_exporter(scheme, extensions, _loader)
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,
76
"""Returns a generator that exports the given tree.
78
The generator is expected to yield None while exporting the tree while the
79
actual export is written to ``fileobj``.
69
81
:param tree: A Tree (such as RevisionTree) to export
70
:param dest: The destination where the files,etc should be put
83
:param dest: The destination where the files, etc should be put
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
86
extension on dest, looking for a match
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.
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
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.
97
:param filtered: If True, content filtering is applied to the exported
98
files. Deprecated in favour of passing a ContentFilterTree
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.
105
:param fileobj: Optional file object to use
89
107
global _exporters, _exporter_extensions
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]
102
120
if format not in _exporters:
103
121
raise errors.NoSuchExportFormat(format)
123
if not per_file_timestamps:
124
force_mtime = time.time()
128
trace.mutter('export version %r', tree)
131
from bzrlib.filter_tree import ContentFilterTree
133
"passing filtered=True to export is deprecated in bzr 2.4",
135
tree = ContentFilterTree(tree, tree._content_filter_stack)
136
# We don't want things re-filtered by the specific exporter.
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):
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.
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
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
174
for _ in get_export_generator(tree, dest, format, root, subdir, filtered,
175
per_file_timestamps, fileobj):
112
179
def get_root_name(dest):
113
180
"""Get just the root name for an export.
115
>>> get_root_name('../mytest.tar')
117
>>> get_root_name('mytar.tar')
119
>>> get_root_name('mytar.tar.bz2')
121
>>> get_root_name('tar.tar.tar.tgz')
123
>>> get_root_name('bzr-0.0.5.tar.gz')
125
>>> get_root_name('bzr-0.0.5.zip')
127
>>> get_root_name('bzr-0.0.5')
129
>>> get_root_name('a/long/path/mytar.tgz')
131
>>> get_root_name('../parent/../dir/other.tbz2')
134
183
global _exporter_extensions
185
# Exporting to -/foo doesn't make sense so use relative paths.
135
187
dest = os.path.basename(dest)
136
188
for ext in _exporter_extensions:
137
189
if dest.endswith(ext):
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.
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
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
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
162
entries = inv.iter_entries(subdir_object)
164
entries.next() # skip root
165
for entry in entries:
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"):
171
if not tree.has_filename(entry[0]):
215
if entry.kind == 'directory':
217
final_path = entry.name
218
elif subdir is not None:
219
if path.startswith(subdir + '/'):
220
final_path = path[len(subdir) + 1:]
174
if not tree.has_filename(os.path.join(subdir, entry[0])):
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')
225
if not tree.has_filename(path):
228
yield final_path, path, entry
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')