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 trees to tarballs, non-controlled directories, zipfiles, etc.
17
"""Export functionality, which can take a Tree and create a different representation.
19
Such as non-controlled directories, tarfiles, zipfiles, etc.
20
from __future__ import absolute_import
23
import bzrlib.errors as errors
32
25
# Maps format name => export function
34
27
# Maps filename extensions => export format name
35
28
_exporter_extensions = {}
38
30
def register_exporter(format, extensions, func, override=False):
39
31
"""Register an exporter.
63
55
When requesting a specific type of export, load the respective path.
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,
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)
70
62
register_exporter(scheme, extensions, _loader)
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``.
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.
81
69
:param tree: A Tree (such as RevisionTree) to export
83
:param dest: The destination where the files, etc should be put
70
:param dest: The destination where the files,etc should be put
85
71
:param format: The format (dir, zip, etc), if None, it will check the
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.
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
93
80
:param subdir: A starting directory within the tree. None means to export
94
81
the entire tree, and anything else should specify the relative path to
95
82
a directory to start exporting from.
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
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.
107
89
global _exporters, _exporter_extensions
109
if format is None and dest is not None:
110
92
for ext in _exporter_extensions:
111
93
if dest.endswith(ext):
112
94
format = _exporter_extensions[ext]
120
102
if format not in _exporters:
121
103
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.
141
for _ in _exporters[format](
142
tree, dest, root, subdir,
143
force_mtime=force_mtime, fileobj=fileobj):
106
return _exporters[format](tree, dest, root, subdir, filtered=filtered,
107
per_file_timestamps=per_file_timestamps)
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):
179
112
def get_root_name(dest):
180
113
"""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')
183
134
global _exporter_extensions
185
# Exporting to -/foo doesn't make sense so use relative paths.
187
135
dest = os.path.basename(dest)
188
136
for ext in _exporter_extensions:
189
137
if dest.endswith(ext):
194
def _export_iter_entries(tree, subdir, skip_special=True):
142
def _export_iter_entries(tree, subdir):
195
143
"""Iter the entries for tree suitable for exporting.
197
145
:param tree: A tree object.
198
146
: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
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:
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:
210
166
# The .bzr* namespace is reserved for "magic" files like
211
167
# .bzrignore and .bzrrules - do not export these
212
if skip_special and path.startswith(".bzr"):
168
if entry[0].startswith(".bzr"):
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:]
171
if not tree.has_filename(entry[0]):
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')
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')