~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to upstream_import.py

  • Committer: Aaron Bentley
  • Date: 2013-08-20 03:02:43 UTC
  • Revision ID: aaron@aaronbentley.com-20130820030243-r8v1xfbcnd8f10p4
Fix zap command for 2.6/7

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
"""Import upstream source into a branch"""
2
2
 
3
 
from bz2 import BZ2File
4
3
import errno
5
4
import os
 
5
import re
6
6
from StringIO import StringIO
7
7
import stat
8
8
import tarfile
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,
15
 
                            file_kind)
 
15
                            file_kind, splitpath)
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
19
21
 
20
22
class ZipFileWrapper(object):
21
23
 
40
42
 
41
43
 
42
44
class ZipInfoWrapper(object):
43
 
    
 
45
 
44
46
    def __init__(self, zipfile, info):
45
47
        self.info = info
46
48
        self.type = None
108
110
    def isdir(self):
109
111
        return stat.S_ISDIR(self.mode)
110
112
 
111
 
        
112
 
def top_directory(path):
 
113
    def issym(self):
 
114
        if stat.S_ISLNK(self.mode):
 
115
            self.linkname = os.readlink(self.fullpath)
 
116
            return True
 
117
        else:
 
118
            return False
 
119
 
 
120
 
 
121
def top_path(path):
113
122
    """Return the top directory given in a path."""
114
 
    dirname = os.path.dirname(path)
115
 
    last_dirname = dirname
116
 
    while True:
117
 
        dirname = os.path.dirname(dirname)
118
 
        if dirname == '' or dirname == last_dirname:
119
 
            return last_dirname
120
 
        last_dirname = dirname
 
123
    components = splitpath(path)
 
124
    if len(components) > 0:
 
125
        return components[0]
 
126
    else:
 
127
        return ''
121
128
 
122
129
 
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 == '':
129
136
            return None
130
137
        if possible_prefix is None:
157
164
            yield member.name
158
165
 
159
166
 
 
167
def should_ignore(relative_path):
 
168
    return top_path(relative_path) == '.bzr'
 
169
 
 
170
 
160
171
def import_tar(tree, tar_input):
161
172
    """Replace the contents of a working directory with tarfile contents.
162
173
    The tarfile may be a gzipped stream.  File ids will be updated.
172
183
    dir_file = DirWrapper(dir_input)
173
184
    import_archive(tree, dir_file)
174
185
 
 
186
 
175
187
def import_archive(tree, archive_file):
 
188
    tt = TreeTransform(tree)
 
189
    try:
 
190
        import_archive_to_transform(tree, archive_file, tt)
 
191
        tt.apply()
 
192
    finally:
 
193
        tt.finalize()
 
194
 
 
195
 
 
196
def import_archive_to_transform(tree, archive_file, tt):
176
197
    prefix = common_directory(names_of_files(archive_file))
177
 
    tt = TreeTransform(tree)
178
 
 
179
198
    removed = set()
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:
182
201
            continue
183
202
        trans_id = tt.trans_id_tree_path(path)
184
203
        tt.delete_contents(trans_id)
185
204
        removed.add(path)
186
205
 
187
 
    added = set() 
 
206
    added = set()
188
207
    implied_parents = set()
189
208
    seen = set()
190
209
    for member in archive_file.getmembers():
191
210
        if member.type == 'g':
192
211
            # type 'g' is a header
193
212
            continue
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
 
215
        # behaviour better.
 
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 == '':
199
221
            continue
 
222
        if should_ignore(relative_path):
 
223
            continue
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)),
211
235
                           trans_id)
212
236
            executable = (member.mode & 0111) != 0
213
237
            tt.set_executability(executable, trans_id)
237
261
 
238
262
    for conflict in cook_conflicts(resolve_conflicts(tt), tt):
239
263
        warning(conflict)
240
 
    tt.apply()
241
264
 
242
265
 
243
266
def do_import(source, tree_directory=None):
257
280
        if tree.changes_from(tree.basis_tree()).has_changed():
258
281
            raise BzrCommandError("Working tree has uncommitted changes.")
259
282
 
260
 
        if (source.endswith('.tar') or source.endswith('.tar.gz') or 
261
 
            source.endswith('.tar.bz2')) or source.endswith('.tgz'):
262
 
            try:
263
 
                if source.endswith('.bz2'):
264
 
                    tar_input = BZ2File(source, 'r')
265
 
                    tar_input = StringIO(tar_input.read())
266
 
                else:
267
 
                    tar_input = file(source, 'rb')
268
 
            except IOError, e:
269
 
                if e.errno == errno.ENOENT:
270
 
                    raise NoSuchFile(source)
271
 
            try:
272
 
                import_tar(tree, tar_input)
273
 
            finally:
274
 
                tar_input.close()
275
 
        elif source.endswith('.zip'):
276
 
            import_zip(tree, open(source, 'rb'))
277
 
        elif file_kind(source) == 'directory':
278
 
            s = StringIO(source)
279
 
            s.seek(0)
280
 
            import_dir(tree, s)
 
283
        try:
 
284
            archive, external_compressor = get_archive_type(source)
 
285
        except errors.NotArchiveType:
 
286
            if file_kind(source) == 'directory':
 
287
                s = StringIO(source)
 
288
                s.seek(0)
 
289
                import_dir(tree, s)
 
290
            else:
 
291
                raise BzrCommandError('Unhandled import source')
281
292
        else:
282
 
            raise BzrCommandError('Unhandled import source')
 
293
            if archive == 'zip':
 
294
                import_zip(tree, open_from_url(source))
 
295
            elif archive == 'tar':
 
296
                try:
 
297
                    tar_input = open_from_url(source)
 
298
                    if external_compressor == 'bz2':
 
299
                        import bz2
 
300
                        tar_input = StringIO(bz2.decompress(tar_input.read()))
 
301
                    elif external_compressor == 'lzma':
 
302
                        import lzma
 
303
                        tar_input = StringIO(lzma.decompress(tar_input.read()))
 
304
                except IOError, e:
 
305
                    if e.errno == errno.ENOENT:
 
306
                        raise NoSuchFile(source)
 
307
                try:
 
308
                    import_tar(tree, tar_input)
 
309
                finally:
 
310
                    tar_input.close()
283
311
    finally:
284
312
        tree.unlock()
 
313
 
 
314
 
 
315
def get_archive_type(path):
 
316
    """Return the type of archive and compressor indicated by path name.
 
317
 
 
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
 
320
    as ('tar', 'lzma').
 
321
    """
 
322
    matches = re.match(r'.*\.(zip|tgz|tar(.(gz|bz2|lzma|xz))?)$', path)
 
323
    if not matches:
 
324
        raise errors.NotArchiveType(path)
 
325
    external_compressor = None
 
326
    if matches.group(3) is not None:
 
327
        archive = 'tar'
 
328
        external_compressor = matches.group(3)
 
329
        if external_compressor == 'xz':
 
330
            external_compressor = 'lzma'
 
331
    elif matches.group(1) == 'tgz':
 
332
        return 'tar', 'gz'
 
333
    else:
 
334
        archive = matches.group(1)
 
335
    return archive, external_compressor