~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to upstream_import.py

  • Committer: Jelmer Vernooij
  • Date: 2011-06-24 13:35:53 UTC
  • mto: This revision was merged to the branch mainline in revision 771.
  • Revision ID: jelmer@samba.org-20110624133553-h9s8syvvvsvpd1o9
Add support for importing .tar.xz and .tar.lzma files.

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
6
5
from StringIO import StringIO
12
11
from bzrlib.bzrdir import BzrDir
13
12
from bzrlib.errors import NoSuchFile, BzrCommandError, NotBranchError
14
13
from bzrlib.osutils import (pathjoin, isdir, file_iterator, basename,
15
 
                            file_kind)
 
14
                            file_kind, splitpath)
16
15
from bzrlib.trace import warning
17
16
from bzrlib.transform import TreeTransform, resolve_conflicts, cook_conflicts
18
17
from bzrlib.workingtree import WorkingTree
 
18
from bzrlib.plugins.bzrtools.bzrtools import open_from_url
19
19
 
20
20
class ZipFileWrapper(object):
21
21
 
116
116
            return False
117
117
 
118
118
 
119
 
def top_directory(path):
 
119
def top_path(path):
120
120
    """Return the top directory given in a path."""
121
 
    dirname = os.path.dirname(path)
122
 
    last_dirname = dirname
123
 
    while True:
124
 
        dirname = os.path.dirname(dirname)
125
 
        if dirname == '' or dirname == last_dirname:
126
 
            return last_dirname
127
 
        last_dirname = dirname
 
121
    components = splitpath(path)
 
122
    if len(components) > 0:
 
123
        return components[0]
 
124
    else:
 
125
        return ''
128
126
 
129
127
 
130
128
def common_directory(names):
131
129
    """Determine a single directory prefix from a list of names"""
132
130
    possible_prefix = None
133
131
    for name in names:
134
 
        name_top = top_directory(name)
 
132
        name_top = top_path(name)
135
133
        if name_top == '':
136
134
            return None
137
135
        if possible_prefix is None:
164
162
            yield member.name
165
163
 
166
164
 
 
165
def should_ignore(relative_path):
 
166
    return top_path(relative_path) == '.bzr'
 
167
 
 
168
 
167
169
def import_tar(tree, tar_input):
168
170
    """Replace the contents of a working directory with tarfile contents.
169
171
    The tarfile may be a gzipped stream.  File ids will be updated.
179
181
    dir_file = DirWrapper(dir_input)
180
182
    import_archive(tree, dir_file)
181
183
 
 
184
 
182
185
def import_archive(tree, archive_file):
 
186
    tt = TreeTransform(tree)
 
187
    try:
 
188
        import_archive_to_transform(tree, archive_file, tt)
 
189
        tt.apply()
 
190
    finally:
 
191
        tt.finalize()
 
192
 
 
193
 
 
194
def import_archive_to_transform(tree, archive_file, tt):
183
195
    prefix = common_directory(names_of_files(archive_file))
184
 
    tt = TreeTransform(tree)
185
 
 
186
196
    removed = set()
187
197
    for path, entry in tree.inventory.iter_entries():
188
198
        if entry.parent_id is None:
198
208
        if member.type == 'g':
199
209
            # type 'g' is a header
200
210
            continue
201
 
        relative_path = member.name
 
211
        # Inverse functionality in bzr uses utf-8.  We could also
 
212
        # interpret relative to fs encoding, which would match native
 
213
        # behaviour better.
 
214
        relative_path = member.name.decode('utf-8')
202
215
        if prefix is not None:
203
216
            relative_path = relative_path[len(prefix)+1:]
204
217
            relative_path = relative_path.rstrip('/')
205
218
        if relative_path == '':
206
219
            continue
 
220
        if should_ignore(relative_path):
 
221
            continue
207
222
        add_implied_parents(implied_parents, relative_path)
208
223
        trans_id = tt.trans_id_tree_path(relative_path)
209
224
        added.add(relative_path.rstrip('/'))
244
259
 
245
260
    for conflict in cook_conflicts(resolve_conflicts(tt), tt):
246
261
        warning(conflict)
247
 
    tt.apply()
248
262
 
249
263
 
250
264
def do_import(source, tree_directory=None):
265
279
            raise BzrCommandError("Working tree has uncommitted changes.")
266
280
 
267
281
        if (source.endswith('.tar') or source.endswith('.tar.gz') or
268
 
            source.endswith('.tar.bz2')) or source.endswith('.tgz'):
 
282
            source.endswith('.tar.bz2') or source.endswith('.tgz') or
 
283
            source.endswith('.tar.lzma') or source.endswith('.tar.xz')):
269
284
            try:
 
285
                tar_input = open_from_url(source)
270
286
                if source.endswith('.bz2'):
271
 
                    tar_input = BZ2File(source, 'r')
272
 
                    tar_input = StringIO(tar_input.read())
273
 
                else:
274
 
                    tar_input = file(source, 'rb')
 
287
                    import bz2
 
288
                    tar_input = StringIO(bz2.decompress(tar_input.read()))
 
289
                elif source.endswith('.xz') or source.endswith('.lzma'):
 
290
                    import lzma
 
291
                    tar_input = StringIO(lzma.decompress(tar_input.read()))
275
292
            except IOError, e:
276
293
                if e.errno == errno.ENOENT:
277
294
                    raise NoSuchFile(source)
280
297
            finally:
281
298
                tar_input.close()
282
299
        elif source.endswith('.zip'):
283
 
            import_zip(tree, open(source, 'rb'))
 
300
            import_zip(tree, open_from_url(source))
284
301
        elif file_kind(source) == 'directory':
285
302
            s = StringIO(source)
286
303
            s.seek(0)