12
12
from bzrlib.bzrdir import BzrDir
13
13
from bzrlib.errors import NoSuchFile, BzrCommandError, NotBranchError
14
14
from bzrlib.osutils import (pathjoin, isdir, file_iterator, basename,
16
16
from bzrlib.trace import warning
17
17
from bzrlib.transform import TreeTransform, resolve_conflicts, cook_conflicts
18
18
from bzrlib.workingtree import WorkingTree
19
19
from bzrlib.plugins.bzrtools.bzrtools import open_from_url
20
from bzrlib.plugins.bzrtools import errors
21
22
class ZipFileWrapper(object):
120
def top_directory(path):
121
122
"""Return the top directory given in a path."""
122
dirname = os.path.dirname(path)
123
last_dirname = dirname
125
dirname = os.path.dirname(dirname)
126
if dirname == '' or dirname == last_dirname:
128
last_dirname = dirname
123
components = splitpath(path)
124
if len(components) > 0:
131
130
def common_directory(names):
132
131
"""Determine a single directory prefix from a list of names"""
133
132
possible_prefix = None
134
133
for name in names:
135
name_top = top_directory(name)
134
name_top = top_path(name)
136
135
if name_top == '':
138
137
if possible_prefix is None:
165
164
yield member.name
167
def should_ignore(relative_path):
168
return top_path(relative_path) == '.bzr'
168
171
def import_tar(tree, tar_input):
169
172
"""Replace the contents of a working directory with tarfile contents.
170
173
The tarfile may be a gzipped stream. File ids will be updated.
180
183
dir_file = DirWrapper(dir_input)
181
184
import_archive(tree, dir_file)
183
187
def import_archive(tree, archive_file):
188
tt = TreeTransform(tree)
190
import_archive_to_transform(tree, archive_file, tt)
196
def import_archive_to_transform(tree, archive_file, tt):
184
197
prefix = common_directory(names_of_files(archive_file))
185
tt = TreeTransform(tree)
188
for path, entry in tree.inventory.iter_entries():
199
for path, entry in tree.iter_entries_by_dir():
189
200
if entry.parent_id is None:
191
202
trans_id = tt.trans_id_tree_path(path)
199
210
if member.type == 'g':
200
211
# type 'g' is a header
202
relative_path = member.name
213
# Inverse functionality in bzr uses utf-8. We could also
214
# interpret relative to fs encoding, which would match native
216
relative_path = member.name.decode('utf-8')
203
217
if prefix is not None:
204
218
relative_path = relative_path[len(prefix)+1:]
205
219
relative_path = relative_path.rstrip('/')
206
220
if relative_path == '':
222
if should_ignore(relative_path):
208
224
add_implied_parents(implied_parents, relative_path)
209
225
trans_id = tt.trans_id_tree_path(relative_path)
210
226
added.add(relative_path.rstrip('/'))
265
280
if tree.changes_from(tree.basis_tree()).has_changed():
266
281
raise BzrCommandError("Working tree has uncommitted changes.")
268
if (source.endswith('.tar') or source.endswith('.tar.gz') or
269
source.endswith('.tar.bz2')) or source.endswith('.tgz'):
271
tar_input = open_from_url(source)
272
if source.endswith('.bz2'):
273
tar_input = StringIO(tar_input.read().decode('bz2'))
275
if e.errno == errno.ENOENT:
276
raise NoSuchFile(source)
278
import_tar(tree, tar_input)
281
elif source.endswith('.zip'):
282
import_zip(tree, open_from_url(source))
283
elif file_kind(source) == 'directory':
284
archive, external_compressor = get_archive_type(source)
285
except errors.NotArchiveType:
286
if file_kind(source) == 'directory':
291
raise BzrCommandError('Unhandled import source')
288
raise BzrCommandError('Unhandled import source')
294
import_zip(tree, open_from_url(source))
295
elif archive == 'tar':
297
tar_input = open_from_url(source)
298
if external_compressor == 'bz2':
300
tar_input = StringIO(bz2.decompress(tar_input.read()))
301
elif external_compressor == 'lzma':
303
tar_input = StringIO(lzma.decompress(tar_input.read()))
305
if e.errno == errno.ENOENT:
306
raise NoSuchFile(source)
308
import_tar(tree, tar_input)
315
def get_archive_type(path):
316
"""Return the type of archive and compressor indicated by path name.
318
Only external compressors are returned, so zip files are only
319
('zip', None). .tgz is treated as ('tar', 'gz') and '.tar.xz' is treated
322
matches = re.match(r'.*\.(zip|tgz|tar(.(gz|bz2|lzma|xz))?)$', path)
324
raise errors.NotArchiveType(path)
325
external_compressor = None
326
if matches.group(3) is not None:
328
external_compressor = matches.group(3)
329
if external_compressor == 'xz':
330
external_compressor = 'lzma'
331
elif matches.group(1) == 'tgz':
334
archive = matches.group(1)
335
return archive, external_compressor