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
from bzrlib.plugins.bzrtools.bzrtools import open_from_url
20
from bzrlib.plugins.bzrtools import errors
20
22
class ZipFileWrapper(object):
109
111
return stat.S_ISDIR(self.mode)
112
def top_directory(path):
114
if stat.S_ISLNK(self.mode):
115
self.linkname = os.readlink(self.fullpath)
113
122
"""Return the top directory given in a path."""
114
dirname = os.path.dirname(path)
115
last_dirname = dirname
117
dirname = os.path.dirname(dirname)
118
if dirname == '' or dirname == last_dirname:
120
last_dirname = dirname
123
components = splitpath(path)
124
if len(components) > 0:
123
130
def common_directory(names):
124
131
"""Determine a single directory prefix from a list of names"""
125
132
possible_prefix = None
126
133
for name in names:
127
name_top = top_directory(name)
134
name_top = top_path(name)
128
135
if name_top == '':
130
137
if possible_prefix is None:
172
183
dir_file = DirWrapper(dir_input)
173
184
import_archive(tree, dir_file)
175
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):
176
197
prefix = common_directory(names_of_files(archive_file))
177
tt = TreeTransform(tree)
180
for path, entry in tree.inventory.iter_entries():
199
for path, entry in tree.iter_entries_by_dir():
181
200
if entry.parent_id is None:
183
202
trans_id = tt.trans_id_tree_path(path)
184
203
tt.delete_contents(trans_id)
185
204
removed.add(path)
188
207
implied_parents = set()
190
209
for member in archive_file.getmembers():
191
210
if member.type == 'g':
192
211
# type 'g' is a header
194
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')
195
217
if prefix is not None:
196
218
relative_path = relative_path[len(prefix)+1:]
197
219
relative_path = relative_path.rstrip('/')
198
220
if relative_path == '':
222
if should_ignore(relative_path):
200
224
add_implied_parents(implied_parents, relative_path)
201
225
trans_id = tt.trans_id_tree_path(relative_path)
202
226
added.add(relative_path.rstrip('/'))
207
231
tt.cancel_creation(trans_id)
208
232
seen.add(member.name)
209
233
if member.isreg():
210
tt.create_file(file_iterator(archive_file.extractfile(member)),
234
tt.create_file(file_iterator(archive_file.extractfile(member)),
212
236
executable = (member.mode & 0111) != 0
213
237
tt.set_executability(executable, trans_id)
257
280
if tree.changes_from(tree.basis_tree()).has_changed():
258
281
raise BzrCommandError("Working tree has uncommitted changes.")
260
if (source.endswith('.tar') or source.endswith('.tar.gz') or
261
source.endswith('.tar.bz2')) or source.endswith('.tgz'):
263
if source.endswith('.bz2'):
264
tar_input = BZ2File(source, 'r')
265
tar_input = StringIO(tar_input.read())
267
tar_input = file(source, 'rb')
269
if e.errno == errno.ENOENT:
270
raise NoSuchFile(source)
272
import_tar(tree, tar_input)
275
elif source.endswith('.zip'):
276
import_zip(tree, open(source, 'rb'))
277
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')
282
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