~abentley/bzrtools/bzrtools.dev

83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
1
# Copyright (C) 2005 by Aaron Bentley
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
115 by aaron.bentley at utoronto
Import fixes from magnus@therning.org
16
from bzrlib.branch import Branch
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
17
from bzrlib.commands import Command
105 by Aaron Bentley
Fixed NoPyBaz detection
18
from errors import NoPyBaz
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
19
try:
20
    import pybaz
21
    import pybaz.errors
105 by Aaron Bentley
Fixed NoPyBaz detection
22
    from pybaz.backends.baz import null_cmd
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
23
except ImportError:
100 by Aaron Bentley
Fixed up the baz-import plugin
24
    raise NoPyBaz
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
25
import tempfile
26
import os
27
import os.path
28
import shutil
29
import bzrlib
278 by Aaron Bentley
Handled cases where user supplies empty directories or branches
30
from bzrlib.errors import BzrError, NotBranchError, BzrCommandError
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
31
import bzrlib.trace
32
import bzrlib.merge
97 by aaron.bentley at utoronto
Added now-required imports
33
import bzrlib.inventory
34
import bzrlib.osutils
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
35
import sys
36
import email.Utils
37
from progress import *
38
39
def add_id(files, id=None):
40
    """Adds an explicit id to a list of files.
41
42
    :param files: the name of the file to add an id to
43
    :type files: list of str
44
    :param id: tag one file using the specified id, instead of generating id
45
    :type id: str
46
    """
47
    args = ["add-id"]
48
    if id is not None:
49
        args.extend(["--id", id])
50
    args.extend(files)
51
    return null_cmd(args)
52
53
def test_environ():
54
    """
55
    >>> q = test_environ()
56
    >>> os.path.exists(q)
57
    True
58
    >>> os.path.exists(os.path.join(q, "home", ".arch-params"))
59
    True
60
    >>> teardown_environ(q)
61
    >>> os.path.exists(q)
62
    False
63
    """
64
    tdir = tempfile.mkdtemp(prefix="testdir-")
65
    os.environ["HOME"] = os.path.join(tdir, "home")
66
    os.mkdir(os.environ["HOME"])
67
    arch_dir = os.path.join(tdir, "archive_dir")
68
    pybaz.make_archive("test@example.com", arch_dir)
69
    work_dir = os.path.join(tdir, "work_dir")
70
    os.mkdir(work_dir)
71
    os.chdir(work_dir)
72
    pybaz.init_tree(work_dir, "test@example.com/test--test--0")
73
    lib_dir = os.path.join(tdir, "lib_dir")
74
    os.mkdir(lib_dir)
75
    pybaz.register_revision_library(lib_dir)
76
    pybaz.set_my_id("Test User<test@example.org>")
77
    return tdir
78
79
def add_file(path, text, id):
80
    """
81
    >>> q = test_environ()
82
    >>> add_file("path with space", "text", "lalala")
83
    >>> tree = pybaz.tree_root(".")
84
    >>> inv = list(tree.iter_inventory_ids(source=True, both=True))
85
    >>> ("x_lalala", "path with space") in inv
86
    True
87
    >>> teardown_environ(q)
88
    """
89
    file(path, "wb").write(text)
90
    add_id([path], id)
91
92
93
def add_dir(path, id):
94
    """
95
    >>> q = test_environ()
96
    >>> add_dir("path with\(sp) space", "lalala")
97
    >>> tree = pybaz.tree_root(".")
98
    >>> inv = list(tree.iter_inventory_ids(source=True, both=True))
99
    >>> ("x_lalala", "path with\(sp) space") in inv
100
    True
101
    >>> teardown_environ(q)
102
    """
103
    os.mkdir(path)
104
    add_id([path], id)
105
106
def teardown_environ(tdir):
107
    os.chdir("/")
108
    shutil.rmtree(tdir)
109
110
def timport(tree, summary):
111
    msg = tree.log_message()
112
    msg["summary"] = summary
113
    tree.import_(msg)
114
115
def commit(tree, summary):
116
    """
117
    >>> q = test_environ()
118
    >>> tree = pybaz.tree_root(".")
119
    >>> timport(tree, "import")
120
    >>> commit(tree, "commit")
121
    >>> logs = [str(l.revision) for l in tree.iter_logs()]
122
    >>> len(logs)
123
    2
124
    >>> logs[0]
125
    'test@example.com/test--test--0--base-0'
126
    >>> logs[1]
127
    'test@example.com/test--test--0--patch-1'
128
    >>> teardown_environ(q)
129
    """
130
    msg = tree.log_message()
131
    msg["summary"] = summary
132
    tree.commit(msg)
133
134
def commit_test_revisions():
135
    """
136
    >>> q = test_environ()
137
    >>> commit_test_revisions()
138
    >>> a = pybaz.Archive("test@example.com")
139
    >>> revisions = list(a.iter_revisions("test--test--0"))
140
    >>> len(revisions)
141
    3
142
    >>> str(revisions[2])
143
    'test@example.com/test--test--0--base-0'
144
    >>> str(revisions[1])
145
    'test@example.com/test--test--0--patch-1'
146
    >>> str(revisions[0])
147
    'test@example.com/test--test--0--patch-2'
148
    >>> teardown_environ(q)
149
    """
150
    tree = pybaz.tree_root(".")
151
    add_file("mainfile", "void main(void){}", "mainfile by aaron")
152
    timport(tree, "Created mainfile")
153
    file("mainfile", "wb").write("or something like that")
154
    commit(tree, "altered mainfile")
155
    add_file("ofile", "this is another file", "ofile by aaron")
156
    commit(tree, "altered mainfile")
157
158
159
def commit_more_test_revisions():
160
    """
161
    >>> q = test_environ()
162
    >>> commit_test_revisions()
163
    >>> commit_more_test_revisions()
164
    >>> a = pybaz.Archive("test@example.com")
165
    >>> revisions = list(a.iter_revisions("test--test--0"))
166
    >>> len(revisions)
167
    4
168
    >>> str(revisions[0])
169
    'test@example.com/test--test--0--patch-3'
170
    >>> teardown_environ(q)
171
    """
172
    tree = pybaz.tree_root(".")
173
    add_file("trainfile", "void train(void){}", "trainfile by aaron")
174
    commit(tree, "altered trainfile")
175
176
class NoSuchVersion(Exception):
177
    def __init__(self, version):
178
        Exception.__init__(self, "The version %s does not exist." % version)
179
        self.version = version
180
181
def version_ancestry(version):
182
    """
183
    >>> q = test_environ()
184
    >>> commit_test_revisions()
185
    >>> version = pybaz.Version("test@example.com/test--test--0")
186
    >>> ancestors = version_ancestry(version)
187
    >>> str(ancestors[0])
188
    'test@example.com/test--test--0--base-0'
189
    >>> str(ancestors[1])
190
    'test@example.com/test--test--0--patch-1'
191
    >>> version = pybaz.Version("test@example.com/test--test--0.5")
192
    >>> ancestors = version_ancestry(version)
193
    Traceback (most recent call last):
194
    NoSuchVersion: The version test@example.com/test--test--0.5 does not exist.
195
    >>> teardown_environ(q)
196
    """
197
    try:
198
        revision = version.iter_revisions(reverse=True).next()
199
    except:
200
        if not version.exists():
201
            raise NoSuchVersion(version)
202
        else:
203
            raise
204
    ancestors = list(revision.iter_ancestors(metoo=True))
205
    ancestors.reverse()
206
    return ancestors
207
208
def get_last_revision(branch):
221 by abentley
bzrtools 0.1.1 (baz-import patch)
209
    last_patch = branch.last_revision()
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
210
    try:
211
        return arch_revision(last_patch)
212
    except NotArchRevision:
213
        raise UserError(
214
            "Directory \"%s\" already exists, and the last revision is not"
215
            " an Arch revision (%s)" % (output_dir, last_patch))
216
217
218
def get_remaining_revisions(output_dir, version):
219
    last_patch = None
220
    old_revno = None
221
    if os.path.exists(output_dir):
222
        # We are starting from an existing directory, figure out what
223
        # the current version is
224
        branch = find_branch(output_dir)
225
        last_patch = get_last_revision(branch)
278 by Aaron Bentley
Handled cases where user supplies empty directories or branches
226
        if last_patch is None:
227
            raise NotPreviousImport(branch.base)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
228
        if version is None:
229
            version = last_patch.version
230
    elif version is None:
231
        raise UserError("No version specified, and directory does not exist.")
232
233
    try:
234
        ancestors = version_ancestry(version)
270 by Aaron Bentley
Fixed baz-import with unregistered ancestors
235
        if len(ancestors) > 0 and not ancestors[0].archive.is_registered():
268 by Aaron Bentley
Handled the case where the first ancestor is in an unregistered archive.
236
            ancestors = ancestors[1:]
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
237
    except NoSuchVersion, e:
238
        raise UserError(e)
239
240
    if last_patch:
241
        for i in range(len(ancestors)):
242
            if ancestors[i] == last_patch:
243
                break
244
        else:
245
            raise UserError("Directory \"%s\" already exists, and the last "
246
                "revision (%s) is not in the ancestry of %s" % 
247
                (output_dir, last_patch, version))
248
        # Strip off all of the ancestors which are already present
249
        # And get a directory starting with the latest ancestor
250
        latest_ancestor = ancestors[i]
251
        old_revno = find_branch(output_dir).revno()
252
        ancestors = ancestors[i+1:]
253
    return ancestors, old_revno
254
255
def import_version(output_dir, version, fancy=True, fast=False, verbose=False, 
256
                   dry_run=False, max_count=None, skip_symlinks=False):
257
    """
258
    >>> q = test_environ()
259
    >>> result_path = os.path.join(q, "result")
260
    >>> commit_test_revisions()
261
    >>> version = pybaz.Version("test@example.com/test--test--0.1")
262
    >>> import_version('/', version, fancy=False, dry_run=True)
263
    Traceback (most recent call last):
264
    UserError: / exists, but is not a bzr branch.
265
    >>> import_version(result_path, version, fancy=False, dry_run=True)
266
    Traceback (most recent call last):
267
    UserError: The version test@example.com/test--test--0.1 does not exist.
268
    >>> version = pybaz.Version("test@example.com/test--test--0")
269
    >>> import_version(result_path, version, fancy=False, dry_run=True)
270
    not fancy
271
    ....
272
    Dry run, not modifying output_dir
273
    Cleaning up
274
    >>> import_version(result_path, version, fancy=False)
275
    not fancy
276
    ....
277
    Cleaning up
278
    Import complete.
279
    >>> import_version(result_path, version, fancy=False)
280
    Tree is up-to-date with test@example.com/test--test--0--patch-2
281
    >>> commit_more_test_revisions()
282
    >>> import_version(result_path, version, fancy=False)
283
    not fancy
284
    ..
285
    Cleaning up
286
    Import complete.
287
    >>> teardown_environ(q)
288
    """
289
    try:
290
        ancestors, old_revno = get_remaining_revisions(output_dir, version)
291
    except NotInABranch, e:
278 by Aaron Bentley
Handled cases where user supplies empty directories or branches
292
        raise NotPreviousImport(e.path)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
293
    if len(ancestors) == 0:
294
        last_revision = get_last_revision(find_branch(output_dir))
295
        print 'Tree is up-to-date with %s' % last_revision
296
        return
297
298
    progress_bar = ProgressBar()
299
    tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
300
                               dir=os.path.dirname(output_dir))
301
    try:
302
        if not fancy:
303
            print "not fancy"
304
        try:
305
            for result in iter_import_version(output_dir, ancestors, tempdir,
306
                    fast=fast, verbose=verbose, dry_run=dry_run, 
307
                    max_count=max_count, skip_symlinks=skip_symlinks):
308
                if fancy:
102 by Aaron Bentley
Got baz2bzr/annotate working now that ProgressBar is a function
309
                    show_progress(progress_bar, result)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
310
                else:
311
                    sys.stdout.write('.')
312
        finally:
313
            if fancy:
90 by Aaron Bentley
Adapted bzrlib's progress bar
314
                progress_bar.clear()
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
315
            else:
316
                sys.stdout.write('\n')
317
318
        if dry_run:
319
            print 'Dry run, not modifying output_dir'
320
            return
321
        if os.path.exists(output_dir):
322
            # Move the bzr control directory back, and update the working tree
323
            tmp_bzr_dir = os.path.join(tempdir, '.bzr')
324
            
325
            bzr_dir = os.path.join(output_dir, '.bzr')
326
            new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
327
328
            os.rename(bzr_dir, tmp_bzr_dir) # Move the original bzr out of the way
329
            os.rename(new_bzr_dir, bzr_dir)
330
            try:
331
                bzrlib.merge.merge((output_dir, -1), (output_dir, old_revno), 
332
                                   check_clean=False, this_dir=output_dir, 
333
                                   ignore_zero=True)
334
            except:
335
                # If something failed, move back the original bzr directory
336
                os.rename(bzr_dir, new_bzr_dir)
337
                os.rename(tmp_bzr_dir, bzr_dir)
338
                raise
339
        else:
340
            revdir = os.path.join(tempdir, "rd")
341
            os.rename(revdir, output_dir)
342
343
    finally:
344
        print 'Cleaning up'
345
        shutil.rmtree(tempdir)
346
    print "Import complete."
347
            
278 by Aaron Bentley
Handled cases where user supplies empty directories or branches
348
class UserError(BzrCommandError):
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
349
    def __init__(self, message):
350
        """Exception to throw when a user makes an impossible request
351
        :param message: The message to emit when printing this exception
352
        :type message: string
353
        """
278 by Aaron Bentley
Handled cases where user supplies empty directories or branches
354
        BzrCommandError.__init__(self, message)
355
356
class NotPreviousImport(UserError):
357
    def __init__(self, path):
358
        UserError.__init__(self, "%s is not the location of a previous import."
359
                           % path)
360
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
361
362
def revision_id(arch_revision):
363
    """
364
    Generate a Bzr revision id from an Arch revision id.  'x' in the id
365
    designates a revision imported with an experimental algorithm.  A number
366
    would indicate a particular standardized version.
367
368
    :param arch_revision: The Arch revision to generate an ID for.
369
370
    >>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"))
371
    'Arch-x:you@example.com%cat--br--0--base-0'
372
    """
373
    return "Arch-x:%s" % str(arch_revision).replace('/', '%')
374
375
class NotArchRevision(Exception):
376
    def __init__(self, revision_id):
377
        msg = "The revision id %s does not look like it came from Arch."\
378
            % revision_id
379
        Exception.__init__(self, msg)
380
381
def arch_revision(revision_id):
382
    """
383
    >>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0"))
384
    Traceback (most recent call last):
385
    NotArchRevision: The revision id Arch-x:jrandom@example.com%test--test--0 does not look like it came from Arch.
386
    >>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0--base-5"))
387
    Traceback (most recent call last):
388
    NotArchRevision: The revision id Arch-x:jrandom@example.com%test--test--0--base-5 does not look like it came from Arch.
389
    >>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0--patch-5"))
390
    'jrandom@example.com/test--test--0--patch-5'
391
    """
392
    if revision_id is None:
393
        return None
394
    if revision_id[:7] != 'Arch-x:':
395
        raise NotArchRevision(revision_id)
396
    else:
397
        try:
398
            return pybaz.Revision(revision_id[7:].replace('%', '/'))
399
        except pybaz.errors.NamespaceError, e:
400
            raise NotArchRevision(revision_id)
401
            
402
def iter_import_version(output_dir, ancestors, tempdir, fast=False,
403
                        verbose=False, dry_run=False, max_count=None,
404
                        skip_symlinks=False):
405
    revdir = None
406
407
    # Uncomment this for testing, it basically just has baz2bzr only update
408
    # 5 patches at a time
409
    if max_count:
410
        ancestors = ancestors[:max_count]
411
412
    # Not sure if I want this output. basically it tells you ahead of time
413
    # what it is going to do, but then later it tells you as it is doing it.
414
    # what probably would be best would be to collapse it into ranges, so that
415
    # this gives the simple view, and then later it gives the blow by blow.
416
    #if verbose:
417
    #    print 'Adding the following revisions:'
418
    #    for a in ancestors:
419
    #        print '\t%s' % a
420
421
    previous_version=None
422
423
    for i in range(len(ancestors)):
424
        revision = ancestors[i]
425
        if verbose:
426
            version = str(revision.version)
427
            if version != previous_version:
428
                clear_progress_bar()
429
                print '\rOn version: %s' % version
430
            yield Progress(str(revision.patchlevel), i, len(ancestors))
431
            previous_version = version
432
        else:
433
            yield Progress("revisions", i, len(ancestors))
434
        if revdir is None:
435
            revdir = os.path.join(tempdir, "rd")
436
            baz_inv, log = get_revision(revdir, revision, 
437
                                        skip_symlinks=skip_symlinks)
438
            if os.path.exists(output_dir):
439
                bzr_dir = os.path.join(output_dir, '.bzr')
440
                new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
441
                # This would be much faster with a simple os.rename(), but if
442
                # we fail, we have corrupted the original .bzr directory.  Is
443
                # that a big problem, as we can just back out the last
444
                # revisions in .bzr/revision_history I don't really know
445
                shutil.copytree(bzr_dir, new_bzr_dir)
446
                # Now revdir should have a tree with the latest .bzr, and the
447
                # next revision of the baz tree
448
                branch = find_branch(revdir)
449
            else:
158 by Aaron Bentley
Updated to match API changes
450
                branch = Branch.initialize(revdir)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
451
        else:
452
            old = os.path.join(revdir, ".bzr")
453
            new = os.path.join(tempdir, ".bzr")
454
            os.rename(old, new)
455
            baz_inv, log = apply_revision(revdir, revision, 
456
                                          skip_symlinks=skip_symlinks)
457
            os.rename(new, old)
458
            branch = find_branch(revdir)
459
        timestamp = email.Utils.mktime_tz(log.date + (0,))
460
        rev_id = revision_id(revision)
461
        branch.lock_write()
462
        try:
272 by Aaron Bentley
Adjusted baz-import for bzrlib API changes
463
            branch.working_tree().set_inventory(baz_inv)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
464
            bzrlib.trace.silent = True
286.1.1 by Aaron Bentley
Updates to match API changes
465
            wt = branch.working_tree()
466
            wt.commit(log.summary, verbose=False, committer=log.creator,
467
                      timestamp=timestamp, timezone=0, rev_id=rev_id)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
468
        finally:
469
            bzrlib.trace.silent = False   
470
            branch.unlock()
471
    yield Progress("revisions", len(ancestors), len(ancestors))
472
    unlink_unversioned(branch, revdir)
473
474
def unlink_unversioned(branch, revdir):
475
    for unversioned in branch.working_tree().extras():
476
        path = os.path.join(revdir, unversioned)
477
        if os.path.isdir(path):
478
            shutil.rmtree(path)
479
        else:
480
            os.unlink(path)
481
482
def get_log(tree, revision):
483
    log = tree.iter_logs(version=revision.version, reverse=True).next()
133 by Aaron Bentley
Weakened check so baz-import works
484
    assert str(log.revision) == str(revision), (log.revision, revision)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
485
    return log
486
487
def get_revision(revdir, revision, skip_symlinks=False):
488
    revision.get(revdir)
489
    tree = pybaz.tree_root(revdir)
490
    log = get_log(tree, revision)
491
    try:
492
        return bzr_inventory_data(tree, skip_symlinks=skip_symlinks), log 
493
    except BadFileKind, e:
494
        raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) )
495
496
497
def apply_revision(revdir, revision, skip_symlinks=False):
498
    tree = pybaz.tree_root(revdir)
499
    revision.apply(tree)
500
    log = get_log(tree, revision)
501
    try:
502
        return bzr_inventory_data(tree, skip_symlinks=skip_symlinks), log
503
    except BadFileKind, e:
504
        raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) )
505
506
507
508
509
class BadFileKind(Exception):
510
    """The file kind is not permitted in bzr inventories"""
511
    def __init__(self, tree_root, path, kind):
512
        self.tree_root = tree_root
513
        self.path = path
514
        self.kind = kind
515
        Exception.__init__(self, "File %s is of forbidden type %s" %
516
                           (os.path.join(tree_root, path), kind))
517
518
def bzr_inventory_data(tree, skip_symlinks=False):
519
    inv_iter = tree.iter_inventory_ids(source=True, both=True)
520
    inv_map = {}
106 by Aaron Bentley
Used limited url-encoding for file ids
521
    for arch_id, path in inv_iter:
522
        bzr_file_id = arch_id.replace('%', '%25').replace('/', '%2f')
523
        inv_map[path] = bzr_file_id 
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
524
525
    bzr_inv = []
526
    for path, file_id in inv_map.iteritems():
527
        full_path = os.path.join(tree, path)
528
        kind = bzrlib.osutils.file_kind(full_path)
529
        if skip_symlinks and kind == "symlink":
530
            continue
531
        if kind not in ("file", "directory"):
532
            raise BadFileKind(tree, path, kind)
533
        parent_dir = os.path.dirname(path)
534
        if parent_dir != "":
535
            parent_id = inv_map[parent_dir]
536
        else:
537
            parent_id = bzrlib.inventory.ROOT_ID
538
        bzr_inv.append((path, file_id, parent_id, kind))
539
    bzr_inv.sort()
540
    return bzr_inv
541
542
class NotInABranch(Exception):
543
    def __init__(self, path):
544
        Exception.__init__(self, "%s is not in a branch." % path)
545
        self.path = path
546
547
548
def find_branch(path):
549
    """
550
    >>> find_branch('/')
551
    Traceback (most recent call last):
552
    NotInABranch: / is not in a branch.
553
    >>> sb = bzrlib.ScratchBranch()
123 by aaron.bentley at utoronto
changed branch references
554
    >>> isinstance(find_branch(sb.base), Branch)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
555
    True
556
    """
557
    try:
158 by Aaron Bentley
Updated to match API changes
558
        return Branch.open(path)
278 by Aaron Bentley
Handled cases where user supplies empty directories or branches
559
    except NotBranchError, e:
560
        raise NotInABranch(path)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
561
562
class cmd_baz_import(Command):
563
    """Import an Arch or Baz branch into a bzr branch"""
564
    takes_args = ['to_location', 'from_branch?']
565
    takes_options = ['verbose']
566
567
    def run(self, to_location, from_branch=None, skip_symlinks=False, 
568
            fast=False, max_count=None, verbose=False, dry_run=False):
569
        to_location = os.path.realpath(str(to_location))
570
        if from_branch is not None:
571
            try:
100 by Aaron Bentley
Fixed up the baz-import plugin
572
                from_branch = pybaz.Version(from_branch)
83 by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin
573
            except pybaz.errors.NamespaceError:
574
                print "%s is not a valid Arch branch." % from_branch
575
                return 1
90 by Aaron Bentley
Adapted bzrlib's progress bar
576
        import_version(to_location, from_branch)