~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Martin Pool
  • Date: 2005-08-30 01:35:40 UTC
  • Revision ID: mbp@sourcefrog.net-20050830013540-34e8996a86ba25fb
- rename FunctionalTest to TestCaseInTempDir

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
 
 
19
 
import sys, os
 
18
# TODO: Split the command framework away from the actual commands.
 
19
 
 
20
# TODO: probably should say which arguments are candidates for glob
 
21
# expansion on windows and do that at the command level.
 
22
 
 
23
# TODO: Help messages for options.
 
24
 
 
25
# TODO: Define arguments by objects, rather than just using names.
 
26
# Those objects can specify the expected type of the argument, which
 
27
# would help with validation and shell completion.
 
28
 
 
29
 
 
30
# TODO: Help messages for options.
 
31
 
 
32
# TODO: Define arguments by objects, rather than just using names.
 
33
# Those objects can specify the expected type of the argument, which
 
34
# would help with validation and shell completion.
 
35
 
 
36
 
 
37
import sys
 
38
import os
20
39
 
21
40
import bzrlib
 
41
import bzrlib.trace
22
42
from bzrlib.trace import mutter, note, log_error, warning
23
43
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
24
44
from bzrlib.branch import find_branch
38
58
        k_unsquished = k
39
59
    if not plugin_cmds.has_key(k_unsquished):
40
60
        plugin_cmds[k_unsquished] = cmd
 
61
        mutter('registered plugin command %s', k_unsquished)      
41
62
    else:
42
63
        log_error('Two plugins defined the same command: %r' % k)
43
64
        log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
136
157
        raise BzrCommandError(msg)
137
158
    
138
159
 
 
160
def get_merge_type(typestring):
 
161
    """Attempt to find the merge class/factory associated with a string."""
 
162
    from merge import merge_types
 
163
    try:
 
164
        return merge_types[typestring][0]
 
165
    except KeyError:
 
166
        templ = '%s%%7s: %%s' % (' '*12)
 
167
        lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
 
168
        type_list = '\n'.join(lines)
 
169
        msg = "No known merge type %s. Supported types are:\n%s" %\
 
170
            (typestring, type_list)
 
171
        raise BzrCommandError(msg)
 
172
    
 
173
 
139
174
 
140
175
def _get_cmd_dict(plugins_override=True):
141
176
    d = {}
165
200
 
166
201
    # first look up this command under the specified name
167
202
    cmds = _get_cmd_dict(plugins_override=plugins_override)
 
203
    mutter("all commands: %r", cmds.keys())
168
204
    try:
169
205
        return cmd, cmds[cmd]
170
206
    except KeyError:
237
273
class ExternalCommand(Command):
238
274
    """Class to wrap external commands.
239
275
 
240
 
    We cheat a little here, when get_cmd_class() calls us we actually give it back
241
 
    an object we construct that has the appropriate path, help, options etc for the
242
 
    specified command.
243
 
 
244
 
    When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
245
 
    method, which we override to call the Command.__init__ method. That then calls
246
 
    our run method which is pretty straight forward.
247
 
 
248
 
    The only wrinkle is that we have to map bzr's dictionary of options and arguments
249
 
    back into command line options and arguments for the script.
 
276
    We cheat a little here, when get_cmd_class() calls us we actually
 
277
    give it back an object we construct that has the appropriate path,
 
278
    help, options etc for the specified command.
 
279
 
 
280
    When run_bzr() tries to instantiate that 'class' it gets caught by
 
281
    the __call__ method, which we override to call the Command.__init__
 
282
    method. That then calls our run method which is pretty straight
 
283
    forward.
 
284
 
 
285
    The only wrinkle is that we have to map bzr's dictionary of options
 
286
    and arguments back into command line options and arguments for the
 
287
    script.
250
288
    """
251
289
 
252
290
    def find_command(cls, cmd):
438
476
    takes_options = ['verbose', 'no-recurse']
439
477
    
440
478
    def run(self, file_list, verbose=False, no_recurse=False):
441
 
        from bzrlib.add import smart_add
442
 
        smart_add(file_list, verbose, not no_recurse)
 
479
        from bzrlib.add import smart_add, _PrintAddCallback
 
480
        recurse = not no_recurse
 
481
        smart_add(file_list, verbose, not no_recurse,
 
482
                  callback=_PrintAddCallback)
443
483
 
444
484
 
445
485
 
457
497
            os.mkdir(d)
458
498
            if not b:
459
499
                b = find_branch(d)
460
 
            b.add([d], verbose=True)
 
500
            b.add([d])
 
501
            print 'added', d
461
502
 
462
503
 
463
504
class cmd_relpath(Command):
503
544
    def run(self, source_list, dest):
504
545
        b = find_branch('.')
505
546
 
 
547
        # TODO: glob expansion on windows?
506
548
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
507
549
 
508
550
 
528
570
 
529
571
 
530
572
 
 
573
class cmd_mv(Command):
 
574
    """Move or rename a file.
 
575
 
 
576
    usage:
 
577
        bzr mv OLDNAME NEWNAME
 
578
        bzr mv SOURCE... DESTINATION
 
579
 
 
580
    If the last argument is a versioned directory, all the other names
 
581
    are moved into it.  Otherwise, there must be exactly two arguments
 
582
    and the file is changed to a new name, which must not already exist.
 
583
 
 
584
    Files cannot be moved between branches.
 
585
    """
 
586
    takes_args = ['names*']
 
587
    def run(self, names_list):
 
588
        if len(names_list) < 2:
 
589
            raise BzrCommandError("missing file argument")
 
590
        b = find_branch(names_list[0])
 
591
 
 
592
        rel_names = [b.relpath(x) for x in names_list]
 
593
        
 
594
        if os.path.isdir(names_list[-1]):
 
595
            # move into existing directory
 
596
            for pair in b.move(rel_names[:-1], rel_names[-1]):
 
597
                print "%s => %s" % pair
 
598
        else:
 
599
            if len(names_list) != 2:
 
600
                raise BzrCommandError('to mv multiple files the destination '
 
601
                                      'must be a versioned directory')
 
602
            for pair in b.move(rel_names[0], rel_names[1]):
 
603
                print "%s => %s" % pair
 
604
            
 
605
    
531
606
 
532
607
 
533
608
class cmd_pull(Command):
551
626
        import tempfile
552
627
        from shutil import rmtree
553
628
        import errno
 
629
        from bzrlib.branch import pull_loc
554
630
        
555
631
        br_to = find_branch('.')
556
632
        stored_loc = None
600
676
    """
601
677
    takes_args = ['from_location', 'to_location?']
602
678
    takes_options = ['revision']
 
679
    aliases = ['get', 'clone']
603
680
 
604
681
    def run(self, from_location, to_location=None, revision=None):
 
682
        from bzrlib.branch import copy_branch, find_cached_branch
 
683
        import tempfile
605
684
        import errno
606
 
        from bzrlib.merge import merge
607
 
        from bzrlib.branch import DivergedBranches, NoSuchRevision, \
608
 
             find_cached_branch, Branch
609
685
        from shutil import rmtree
610
 
        from meta_store import CachedStore
611
 
        import tempfile
612
686
        cache_root = tempfile.mkdtemp()
613
 
 
614
 
        if revision is None:
615
 
            revision = [None]
616
 
        elif len(revision) > 1:
617
 
            raise BzrCommandError('bzr branch --revision takes exactly 1 revision value')
618
 
 
619
687
        try:
 
688
            if revision is None:
 
689
                revision = [None]
 
690
            elif len(revision) > 1:
 
691
                raise BzrCommandError(
 
692
                    'bzr branch --revision takes exactly 1 revision value')
620
693
            try:
621
694
                br_from = find_cached_branch(from_location, cache_root)
622
695
            except OSError, e:
625
698
                                          ' exist.' % to_location)
626
699
                else:
627
700
                    raise
628
 
 
629
701
            if to_location is None:
630
702
                to_location = os.path.basename(from_location.rstrip("/\\"))
631
 
 
632
703
            try:
633
704
                os.mkdir(to_location)
634
705
            except OSError, e:
640
711
                                          to_location)
641
712
                else:
642
713
                    raise
643
 
            br_to = Branch(to_location, init=True)
644
 
 
645
 
            br_to.set_root_id(br_from.get_root_id())
646
 
 
647
 
            if revision:
648
 
                if revision[0] is None:
649
 
                    revno = br_from.revno()
650
 
                else:
651
 
                    revno, rev_id = br_from.get_revision_info(revision[0])
652
 
                try:
653
 
                    br_to.update_revisions(br_from, stop_revision=revno)
654
 
                except NoSuchRevision:
655
 
                    rmtree(to_location)
656
 
                    msg = "The branch %s has no revision %d." % (from_location,
657
 
                                                                 revno)
658
 
                    raise BzrCommandError(msg)
659
 
            
660
 
            merge((to_location, -1), (to_location, 0), this_dir=to_location,
661
 
                  check_clean=False, ignore_zero=True)
662
 
            from_location = pull_loc(br_from)
663
 
            br_to.controlfile("x-pull", "wb").write(from_location + "\n")
 
714
            try:
 
715
                copy_branch(br_from, to_location, revision[0])
 
716
            except bzrlib.errors.NoSuchRevision:
 
717
                rmtree(to_location)
 
718
                msg = "The branch %s has no revision %d." % (from_location, revision[0])
 
719
                raise BzrCommandError(msg)
664
720
        finally:
665
721
            rmtree(cache_root)
666
722
 
667
723
 
668
 
def pull_loc(branch):
669
 
    # TODO: Should perhaps just make attribute be 'base' in
670
 
    # RemoteBranch and Branch?
671
 
    if hasattr(branch, "baseurl"):
672
 
        return branch.baseurl
673
 
    else:
674
 
        return branch.base
675
 
 
676
 
 
677
 
 
678
724
class cmd_renames(Command):
679
725
    """Show list of renamed files.
680
726
 
797
843
    If files are listed, only the changes in those files are listed.
798
844
    Otherwise, all changes for the tree are listed.
799
845
 
800
 
    TODO: Given two revision arguments, show the difference between them.
801
 
 
802
846
    TODO: Allow diff across branches.
803
847
 
804
848
    TODO: Option to use external diff command; could be GNU diff, wdiff,
813
857
          deleted files.
814
858
 
815
859
    TODO: This probably handles non-Unix newlines poorly.
 
860
 
 
861
    examples:
 
862
        bzr diff
 
863
        bzr diff -r1
 
864
        bzr diff -r1:2
816
865
    """
817
866
    
818
867
    takes_args = ['file*']
831
880
        else:
832
881
            b = find_branch('.')
833
882
 
834
 
        # TODO: Make show_diff support taking 2 arguments
835
 
        base_rev = None
836
883
        if revision is not None:
837
 
            if len(revision) != 1:
838
 
                raise BzrCommandError('bzr diff --revision takes exactly one revision identifier')
839
 
            base_rev = revision[0]
840
 
    
841
 
        show_diff(b, base_rev, specific_files=file_list,
842
 
                  external_diff_options=diff_options)
843
 
 
 
884
            if len(revision) == 1:
 
885
                show_diff(b, revision[0], specific_files=file_list,
 
886
                          external_diff_options=diff_options)
 
887
            elif len(revision) == 2:
 
888
                show_diff(b, revision[0], specific_files=file_list,
 
889
                          external_diff_options=diff_options,
 
890
                          revision2=revision[1])
 
891
            else:
 
892
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
 
893
        else:
 
894
            show_diff(b, None, specific_files=file_list,
 
895
                      external_diff_options=diff_options)
844
896
 
845
897
        
846
898
 
872
924
    """List files modified in working tree."""
873
925
    hidden = True
874
926
    def run(self):
875
 
        from bzrlib.diff import compare_trees
 
927
        from bzrlib.delta import compare_trees
876
928
 
877
929
        b = find_branch('.')
878
930
        td = compare_trees(b.basis_tree(), b.working_tree())
927
979
    """
928
980
 
929
981
    takes_args = ['filename?']
930
 
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long', 'message']
 
982
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
 
983
                     'long', 'message', 'short',]
931
984
    
932
985
    def run(self, filename=None, timezone='original',
933
986
            verbose=False,
935
988
            forward=False,
936
989
            revision=None,
937
990
            message=None,
938
 
            long=False):
 
991
            long=False,
 
992
            short=False):
939
993
        from bzrlib.branch import find_branch
940
994
        from bzrlib.log import log_formatter, show_log
941
995
        import codecs
975
1029
        # in e.g. the default C locale.
976
1030
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
977
1031
 
978
 
        if long:
 
1032
        if not short:
979
1033
            log_format = 'long'
980
1034
        else:
981
1035
            log_format = 'short'
1198
1252
 
1199
1253
class cmd_commit(Command):
1200
1254
    """Commit changes into a new revision.
 
1255
    
 
1256
    If no arguments are given, the entire tree is committed.
1201
1257
 
1202
1258
    If selected files are specified, only changes to those files are
1203
 
    committed.  If a directory is specified then its contents are also
1204
 
    committed.
 
1259
    committed.  If a directory is specified then the directory and everything 
 
1260
    within it is committed.
1205
1261
 
1206
1262
    A selected-file commit may fail in some cases where the committed
1207
1263
    tree would be invalid, such as trying to commit a file in a
1215
1271
    takes_options = ['message', 'file', 'verbose', 'unchanged']
1216
1272
    aliases = ['ci', 'checkin']
1217
1273
 
 
1274
    # TODO: Give better message for -s, --summary, used by tla people
 
1275
    
1218
1276
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1219
1277
            unchanged=False):
1220
1278
        from bzrlib.errors import PointlessCommit
1222
1280
 
1223
1281
        ## Warning: shadows builtin file()
1224
1282
        if not message and not file:
 
1283
            # FIXME: Ugly; change status code to send to a provided function?
 
1284
            
1225
1285
            import cStringIO
1226
1286
            stdout = sys.stdout
1227
1287
            catcher = cStringIO.StringIO()
1242
1302
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1243
1303
 
1244
1304
        b = find_branch('.')
1245
 
 
 
1305
        if selected_list:
 
1306
            selected_list = [b.relpath(s) for s in selected_list]
 
1307
            
1246
1308
        try:
1247
1309
            b.commit(message, verbose=verbose,
1248
1310
                     specific_files=selected_list,
1267
1329
 
1268
1330
    def run(self, dir='.'):
1269
1331
        from bzrlib.check import check
 
1332
 
1270
1333
        check(find_branch(dir))
1271
1334
 
1272
1335
 
1273
 
 
1274
1336
class cmd_scan_cache(Command):
1275
1337
    hidden = True
1276
1338
    def run(self):
1295
1357
class cmd_upgrade(Command):
1296
1358
    """Upgrade branch storage to current format.
1297
1359
 
1298
 
    This should normally be used only after the check command tells
1299
 
    you to run it.
 
1360
    The check command or bzr developers may sometimes advise you to run
 
1361
    this command.
1300
1362
    """
1301
1363
    takes_args = ['dir?']
1302
1364
 
1311
1373
    takes_options = ['email']
1312
1374
    
1313
1375
    def run(self, email=False):
 
1376
        try:
 
1377
            b = bzrlib.branch.find_branch('.')
 
1378
        except:
 
1379
            b = None
 
1380
        
1314
1381
        if email:
1315
 
            print bzrlib.osutils.user_email()
 
1382
            print bzrlib.osutils.user_email(b)
1316
1383
        else:
1317
 
            print bzrlib.osutils.username()
 
1384
            print bzrlib.osutils.username(b)
1318
1385
 
1319
1386
 
1320
1387
class cmd_selftest(Command):
1321
1388
    """Run internal test suite"""
1322
1389
    hidden = True
1323
 
    takes_options = ['verbose']
1324
 
    def run(self, verbose=False):
 
1390
    takes_options = ['verbose', 'pattern']
 
1391
    def run(self, verbose=False, pattern=".*"):
 
1392
        import bzrlib.ui
1325
1393
        from bzrlib.selftest import selftest
1326
 
        return int(not selftest(verbose=verbose))
 
1394
        # we don't want progress meters from the tests to go to the
 
1395
        # real output; and we don't want log messages cluttering up
 
1396
        # the real logs.
 
1397
        save_ui = bzrlib.ui.ui_factory
 
1398
        bzrlib.trace.info('running tests...')
 
1399
        try:
 
1400
            bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
1401
            result = selftest(verbose=verbose, pattern=pattern)
 
1402
            if result:
 
1403
                bzrlib.trace.info('tests passed')
 
1404
            else:
 
1405
                bzrlib.trace.info('tests failed')
 
1406
            return int(not result)
 
1407
        finally:
 
1408
            bzrlib.ui.ui_factory = save_ui
1327
1409
 
1328
1410
 
1329
1411
class cmd_version(Command):
1384
1466
 
1385
1467
 
1386
1468
 
 
1469
class cmd_find_merge_base(Command):
 
1470
    """Find and print a base revision for merging two branches.
 
1471
 
 
1472
    TODO: Options to specify revisions on either side, as if
 
1473
          merging only part of the history.
 
1474
    """
 
1475
    takes_args = ['branch', 'other']
 
1476
    hidden = True
 
1477
    
 
1478
    def run(self, branch, other):
 
1479
        branch1 = find_branch(branch)
 
1480
        branch2 = find_branch(other)
 
1481
 
 
1482
        base_revno, base_revid = branch1.common_ancestor(branch2)
 
1483
 
 
1484
        if base_revno is None:
 
1485
            raise bzrlib.errors.UnrelatedBranches()
 
1486
 
 
1487
        print 'merge base is revision %s' % base_revid
 
1488
        print ' r%-6d in %s' % (base_revno, branch)
 
1489
 
 
1490
        other_revno = branch2.revision_id_to_revno(base_revid)
 
1491
        
 
1492
        print ' r%-6d in %s' % (other_revno, other)
 
1493
 
 
1494
 
 
1495
 
1387
1496
class cmd_merge(Command):
1388
 
    """Perform a three-way merge of trees.
1389
 
    
1390
 
    The SPEC parameters are working tree or revision specifiers.  Working trees
1391
 
    are specified using standard paths or urls.  No component of a directory
1392
 
    path may begin with '@'.
1393
 
    
1394
 
    Working tree examples: '.', '..', 'foo@', but NOT 'foo/@bar'
1395
 
 
1396
 
    Revisions are specified using a dirname/@revno pair, where dirname is the
1397
 
    branch directory and revno is the revision within that branch.  If no revno
1398
 
    is specified, the latest revision is used.
1399
 
 
1400
 
    Revision examples: './@127', 'foo/@', '../@1'
1401
 
 
1402
 
    The OTHER_SPEC parameter is required.  If the BASE_SPEC parameter is
1403
 
    not supplied, the common ancestor of OTHER_SPEC the current branch is used
1404
 
    as the BASE.
1405
 
 
 
1497
    """Perform a three-way merge.
 
1498
    
 
1499
    The branch is the branch you will merge from.  By default, it will merge
 
1500
    the latest revision.  If you specify a revision, that revision will be
 
1501
    merged.  If you specify two revisions, the first will be used as a BASE, 
 
1502
    and the second one as OTHER.  Revision numbers are always relative to the
 
1503
    specified branch.
 
1504
    
 
1505
    Examples:
 
1506
 
 
1507
    To merge the latest revision from bzr.dev
 
1508
    bzr merge ../bzr.dev
 
1509
 
 
1510
    To merge changes up to and including revision 82 from bzr.dev
 
1511
    bzr merge -r 82 ../bzr.dev
 
1512
 
 
1513
    To merge the changes introduced by 82, without previous changes:
 
1514
    bzr merge -r 81..82 ../bzr.dev
 
1515
    
1406
1516
    merge refuses to run if there are any uncommitted changes, unless
1407
1517
    --force is given.
1408
1518
    """
1409
 
    takes_args = ['other_spec', 'base_spec?']
1410
 
    takes_options = ['force', 'merge-type']
 
1519
    takes_args = ['branch?']
 
1520
    takes_options = ['revision', 'force', 'merge-type']
1411
1521
 
1412
 
    def run(self, other_spec, base_spec=None, force=False, merge_type=None):
 
1522
    def run(self, branch='.', revision=None, force=False, 
 
1523
            merge_type=None):
1413
1524
        from bzrlib.merge import merge
1414
1525
        from bzrlib.merge_core import ApplyMerge3
1415
1526
        if merge_type is None:
1416
1527
            merge_type = ApplyMerge3
1417
 
        merge(parse_spec(other_spec), parse_spec(base_spec),
1418
 
              check_clean=(not force), merge_type=merge_type)
 
1528
 
 
1529
        if revision is None or len(revision) < 1:
 
1530
            base = [None, None]
 
1531
            other = (branch, -1)
 
1532
        else:
 
1533
            if len(revision) == 1:
 
1534
                other = (branch, revision[0])
 
1535
                base = (None, None)
 
1536
            else:
 
1537
                assert len(revision) == 2
 
1538
                if None in revision:
 
1539
                    raise BzrCommandError(
 
1540
                        "Merge doesn't permit that revision specifier.")
 
1541
                base = (branch, revision[0])
 
1542
                other = (branch, revision[1])
 
1543
            
 
1544
        merge(other, base, check_clean=(not force), merge_type=merge_type)
1419
1545
 
1420
1546
 
1421
1547
class cmd_revert(Command):
1431
1557
 
1432
1558
    def run(self, revision=None, no_backup=False, file_list=None):
1433
1559
        from bzrlib.merge import merge
 
1560
        from bzrlib.branch import Branch
1434
1561
        if file_list is not None:
1435
1562
            if len(file_list) == 0:
1436
1563
                raise BzrCommandError("No files specified")
1443
1570
              ignore_zero=True,
1444
1571
              backup_files=not no_backup,
1445
1572
              file_list=file_list)
 
1573
        if not file_list:
 
1574
            Branch('.').set_pending_merges([])
1446
1575
 
1447
1576
 
1448
1577
class cmd_assert_fail(Command):
1456
1585
    """Show help on a command or other topic.
1457
1586
 
1458
1587
    For a list of all available commands, say 'bzr help commands'."""
 
1588
    takes_options = ['long']
1459
1589
    takes_args = ['topic?']
1460
1590
    aliases = ['?']
1461
1591
    
1462
 
    def run(self, topic=None):
 
1592
    def run(self, topic=None, long=False):
1463
1593
        import help
 
1594
        if topic is None and long:
 
1595
            topic = "commands"
1464
1596
        help.help(topic)
1465
1597
 
1466
1598
 
 
1599
class cmd_shell_complete(Command):
 
1600
    """Show appropriate completions for context.
 
1601
 
 
1602
    For a list of all available commands, say 'bzr shell-complete'."""
 
1603
    takes_args = ['context?']
 
1604
    aliases = ['s-c']
 
1605
    hidden = True
 
1606
    
 
1607
    def run(self, context=None):
 
1608
        import shellcomplete
 
1609
        shellcomplete.shellcomplete(context)
 
1610
 
 
1611
 
 
1612
class cmd_missing(Command):
 
1613
    """What is missing in this branch relative to other branch.
 
1614
    """
 
1615
    takes_args = ['remote?']
 
1616
    aliases = ['mis', 'miss']
 
1617
    # We don't have to add quiet to the list, because 
 
1618
    # unknown options are parsed as booleans
 
1619
    takes_options = ['verbose', 'quiet']
 
1620
 
 
1621
    def run(self, remote=None, verbose=False, quiet=False):
 
1622
        from bzrlib.branch import find_branch, DivergedBranches
 
1623
        from bzrlib.errors import BzrCommandError
 
1624
        from bzrlib.missing import get_parent, show_missing
 
1625
 
 
1626
        if verbose and quiet:
 
1627
            raise BzrCommandError('Cannot pass both quiet and verbose')
 
1628
 
 
1629
        b = find_branch('.')
 
1630
        parent = get_parent(b)
 
1631
        if remote is None:
 
1632
            if parent is None:
 
1633
                raise BzrCommandError("No missing location known or specified.")
 
1634
            else:
 
1635
                if not quiet:
 
1636
                    print "Using last location: %s" % parent
 
1637
                remote = parent
 
1638
        elif parent is None:
 
1639
            # We only update x-pull if it did not exist, missing should not change the parent
 
1640
            b.controlfile('x-pull', 'wb').write(remote + '\n')
 
1641
        br_remote = find_branch(remote)
 
1642
 
 
1643
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
 
1644
 
1467
1645
 
1468
1646
 
1469
1647
class cmd_plugins(Command):
1474
1652
        from inspect import getdoc
1475
1653
        from pprint import pprint
1476
1654
        for plugin in bzrlib.plugin.all_plugins:
1477
 
            print plugin.__path__[0]
 
1655
            if hasattr(plugin, '__path__'):
 
1656
                print plugin.__path__[0]
 
1657
            else:
 
1658
                print `plugin`
1478
1659
            d = getdoc(plugin)
1479
1660
            if d:
1480
1661
                print '\t', d.split('\n')[0]
1498
1679
    'no-recurse':             None,
1499
1680
    'profile':                None,
1500
1681
    'revision':               _parse_revision_str,
 
1682
    'short':                  None,
1501
1683
    'show-ids':               None,
1502
1684
    'timezone':               str,
1503
1685
    'verbose':                None,
1509
1691
    'root':                   str,
1510
1692
    'no-backup':              None,
1511
1693
    'merge-type':             get_merge_type,
 
1694
    'pattern':                str,
1512
1695
    }
1513
1696
 
1514
1697
SHORT_OPTIONS = {
1664
1847
    return argdict
1665
1848
 
1666
1849
 
1667
 
def _parse_master_args(argv):
1668
 
    """Parse the arguments that always go with the original command.
1669
 
    These are things like bzr --no-plugins, etc.
1670
 
 
1671
 
    There are now 2 types of option flags. Ones that come *before* the command,
1672
 
    and ones that come *after* the command.
1673
 
    Ones coming *before* the command are applied against all possible commands.
1674
 
    And are generally applied before plugins are loaded.
1675
 
 
1676
 
    The current list are:
1677
 
        --builtin   Allow plugins to load, but don't let them override builtin commands,
1678
 
                    they will still be allowed if they do not override a builtin.
1679
 
        --no-plugins    Don't load any plugins. This lets you get back to official source
1680
 
                        behavior.
1681
 
        --profile   Enable the hotspot profile before running the command.
1682
 
                    For backwards compatibility, this is also a non-master option.
1683
 
        --version   Spit out the version of bzr that is running and exit.
1684
 
                    This is also a non-master option.
1685
 
        --help      Run help and exit, also a non-master option (I think that should stay, though)
1686
 
 
1687
 
    >>> argv, opts = _parse_master_args(['--test'])
1688
 
    Traceback (most recent call last):
1689
 
    ...
1690
 
    BzrCommandError: Invalid master option: 'test'
1691
 
    >>> argv, opts = _parse_master_args(['--version', 'command'])
1692
 
    >>> print argv
1693
 
    ['command']
1694
 
    >>> print opts['version']
1695
 
    True
1696
 
    >>> argv, opts = _parse_master_args(['--profile', 'command', '--more-options'])
1697
 
    >>> print argv
1698
 
    ['command', '--more-options']
1699
 
    >>> print opts['profile']
1700
 
    True
1701
 
    >>> argv, opts = _parse_master_args(['--no-plugins', 'command'])
1702
 
    >>> print argv
1703
 
    ['command']
1704
 
    >>> print opts['no-plugins']
1705
 
    True
1706
 
    >>> print opts['profile']
1707
 
    False
1708
 
    >>> argv, opts = _parse_master_args(['command', '--profile'])
1709
 
    >>> print argv
1710
 
    ['command', '--profile']
1711
 
    >>> print opts['profile']
1712
 
    False
1713
 
    """
1714
 
    master_opts = {'builtin':False,
1715
 
        'no-plugins':False,
1716
 
        'version':False,
1717
 
        'profile':False,
1718
 
        'help':False
1719
 
    }
1720
 
 
1721
 
    for arg in argv[:]:
1722
 
        if arg[:2] != '--': # at the first non-option, we return the rest
1723
 
            break
1724
 
        arg = arg[2:] # Remove '--'
1725
 
        if arg not in master_opts:
1726
 
            # We could say that this is not an error, that we should
1727
 
            # just let it be handled by the main section instead
1728
 
            raise BzrCommandError('Invalid master option: %r' % arg)
1729
 
        argv.pop(0) # We are consuming this entry
1730
 
        master_opts[arg] = True
1731
 
    return argv, master_opts
1732
 
 
1733
 
 
1734
1850
 
1735
1851
def run_bzr(argv):
1736
1852
    """Execute a command.
1739
1855
    logging and error handling.  
1740
1856
    
1741
1857
    argv
1742
 
       The command-line arguments, without the program name.
 
1858
       The command-line arguments, without the program name from argv[0]
1743
1859
    
1744
1860
    Returns a command status or raises an exception.
 
1861
 
 
1862
    Special master options: these must come before the command because
 
1863
    they control how the command is interpreted.
 
1864
 
 
1865
    --no-plugins
 
1866
        Do not load plugin modules at all
 
1867
 
 
1868
    --builtin
 
1869
        Only use builtin commands.  (Plugins are still allowed to change
 
1870
        other behaviour.)
 
1871
 
 
1872
    --profile
 
1873
        Run under the Python profiler.
1745
1874
    """
 
1875
    
1746
1876
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
1747
1877
 
1748
 
    # some options like --builtin and --no-plugins have special effects
1749
 
    argv, master_opts = _parse_master_args(argv)
1750
 
    if not master_opts['no-plugins']:
 
1878
    opt_profile = opt_no_plugins = opt_builtin = False
 
1879
 
 
1880
    # --no-plugins is handled specially at a very early stage. We need
 
1881
    # to load plugins before doing other command parsing so that they
 
1882
    # can override commands, but this needs to happen first.
 
1883
 
 
1884
    for a in argv[:]:
 
1885
        if a == '--profile':
 
1886
            opt_profile = True
 
1887
        elif a == '--no-plugins':
 
1888
            opt_no_plugins = True
 
1889
        elif a == '--builtin':
 
1890
            opt_builtin = True
 
1891
        else:
 
1892
            break
 
1893
        argv.remove(a)
 
1894
 
 
1895
    if not opt_no_plugins:
1751
1896
        from bzrlib.plugin import load_plugins
1752
1897
        load_plugins()
1753
1898
 
1754
1899
    args, opts = parse_args(argv)
1755
1900
 
1756
 
    if master_opts.get('help') or 'help' in opts:
 
1901
    if 'help' in opts:
1757
1902
        from bzrlib.help import help
1758
 
        if argv:
1759
 
            help(argv[0])
 
1903
        if args:
 
1904
            help(args[0])
1760
1905
        else:
1761
1906
            help()
1762
1907
        return 0            
1765
1910
        show_version()
1766
1911
        return 0
1767
1912
    
1768
 
    if args and args[0] == 'builtin':
1769
 
        include_plugins=False
1770
 
        args = args[1:]
 
1913
    if not args:
 
1914
        from bzrlib.help import help
 
1915
        help(None)
 
1916
        return 0
1771
1917
    
1772
 
    try:
1773
 
        cmd = str(args.pop(0))
1774
 
    except IndexError:
1775
 
        print >>sys.stderr, "please try 'bzr help' for help"
1776
 
        return 1
1777
 
 
1778
 
    plugins_override = not (master_opts['builtin'])
1779
 
    canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
1780
 
 
1781
 
    profile = master_opts['profile']
1782
 
    # For backwards compatibility, I would rather stick with --profile being a
1783
 
    # master/global option
1784
 
    if 'profile' in opts:
1785
 
        profile = True
1786
 
        del opts['profile']
 
1918
    cmd = str(args.pop(0))
 
1919
 
 
1920
    canonical_cmd, cmd_class = \
 
1921
                   get_cmd_class(cmd, plugins_override=not opt_builtin)
1787
1922
 
1788
1923
    # check options are reasonable
1789
1924
    allowed = cmd_class.takes_options
1798
1933
    for k, v in opts.items():
1799
1934
        cmdopts[k.replace('-', '_')] = v
1800
1935
 
1801
 
    if profile:
 
1936
    if opt_profile:
1802
1937
        import hotshot, tempfile
1803
1938
        pffileno, pfname = tempfile.mkstemp()
1804
1939
        try:
1823
1958
        return cmd_class(cmdopts, cmdargs).status 
1824
1959
 
1825
1960
 
1826
 
def _report_exception(summary, quiet=False):
1827
 
    import traceback
1828
 
    log_error('bzr: ' + summary)
1829
 
    bzrlib.trace.log_exception()
1830
 
 
1831
 
    if not quiet:
1832
 
        tb = sys.exc_info()[2]
1833
 
        exinfo = traceback.extract_tb(tb)
1834
 
        if exinfo:
1835
 
            sys.stderr.write('  at %s:%d in %s()\n' % exinfo[-1][:3])
1836
 
        sys.stderr.write('  see ~/.bzr.log for debug information\n')
1837
 
 
1838
 
 
1839
 
 
1840
1961
def main(argv):
1841
 
    
1842
 
    bzrlib.trace.open_tracefile(argv)
 
1962
    import bzrlib.ui
 
1963
    bzrlib.trace.log_startup(argv)
 
1964
    bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
1843
1965
 
1844
1966
    try:
1845
1967
        try:
1846
 
            try:
1847
 
                return run_bzr(argv[1:])
1848
 
            finally:
1849
 
                # do this here inside the exception wrappers to catch EPIPE
1850
 
                sys.stdout.flush()
1851
 
        except BzrError, e:
1852
 
            quiet = isinstance(e, (BzrCommandError))
1853
 
            _report_exception('error: ' + e.args[0], quiet=quiet)
1854
 
            if len(e.args) > 1:
1855
 
                for h in e.args[1]:
1856
 
                    # some explanation or hints
1857
 
                    log_error('  ' + h)
1858
 
            return 1
1859
 
        except AssertionError, e:
1860
 
            msg = 'assertion failed'
1861
 
            if str(e):
1862
 
                msg += ': ' + str(e)
1863
 
            _report_exception(msg)
1864
 
            return 2
1865
 
        except KeyboardInterrupt, e:
1866
 
            _report_exception('interrupted', quiet=True)
1867
 
            return 2
1868
 
        except Exception, e:
1869
 
            import errno
1870
 
            quiet = False
1871
 
            if (isinstance(e, IOError) 
1872
 
                and hasattr(e, 'errno')
1873
 
                and e.errno == errno.EPIPE):
1874
 
                quiet = True
1875
 
                msg = 'broken pipe'
1876
 
            else:
1877
 
                msg = str(e).rstrip('\n')
1878
 
            _report_exception(msg, quiet)
1879
 
            return 2
1880
 
    finally:
1881
 
        bzrlib.trace.close_trace()
 
1968
            return run_bzr(argv[1:])
 
1969
        finally:
 
1970
            # do this here inside the exception wrappers to catch EPIPE
 
1971
            sys.stdout.flush()
 
1972
    except BzrCommandError, e:
 
1973
        # command line syntax error, etc
 
1974
        log_error(str(e))
 
1975
        return 1
 
1976
    except BzrError, e:
 
1977
        bzrlib.trace.log_exception()
 
1978
        return 1
 
1979
    except AssertionError, e:
 
1980
        bzrlib.trace.log_exception('assertion failed: ' + str(e))
 
1981
        return 3
 
1982
    except KeyboardInterrupt, e:
 
1983
        bzrlib.trace.note('interrupted')
 
1984
        return 2
 
1985
    except Exception, e:
 
1986
        import errno
 
1987
        if (isinstance(e, IOError) 
 
1988
            and hasattr(e, 'errno')
 
1989
            and e.errno == errno.EPIPE):
 
1990
            bzrlib.trace.note('broken pipe')
 
1991
            return 2
 
1992
        else:
 
1993
            bzrlib.trace.log_exception()
 
1994
            return 2
1882
1995
 
1883
1996
 
1884
1997
if __name__ == '__main__':