~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: aaron.bentley at utoronto
  • Date: 2005-08-21 00:08:08 UTC
  • mto: (1092.1.41) (1185.3.4)
  • mto: This revision was merged to the branch mainline in revision 1110.
  • Revision ID: aaron.bentley@utoronto.ca-20050821000808-2a0e6ef95b1bca59
Changed copy_multi to permit failure and return a tuple, tested missing required revisions

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
import sys
 
24
import os
20
25
 
21
26
import bzrlib
22
27
from bzrlib.trace import mutter, note, log_error, warning
122
127
    return revs
123
128
 
124
129
 
 
130
def get_merge_type(typestring):
 
131
    """Attempt to find the merge class/factory associated with a string."""
 
132
    from merge import merge_types
 
133
    try:
 
134
        return merge_types[typestring][0]
 
135
    except KeyError:
 
136
        templ = '%s%%7s: %%s' % (' '*12)
 
137
        lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
 
138
        type_list = '\n'.join(lines)
 
139
        msg = "No known merge type %s. Supported types are:\n%s" %\
 
140
            (typestring, type_list)
 
141
        raise BzrCommandError(msg)
 
142
    
 
143
 
 
144
def get_merge_type(typestring):
 
145
    """Attempt to find the merge class/factory associated with a string."""
 
146
    from merge import merge_types
 
147
    try:
 
148
        return merge_types[typestring][0]
 
149
    except KeyError:
 
150
        templ = '%s%%7s: %%s' % (' '*12)
 
151
        lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
 
152
        type_list = '\n'.join(lines)
 
153
        msg = "No known merge type %s. Supported types are:\n%s" %\
 
154
            (typestring, type_list)
 
155
        raise BzrCommandError(msg)
 
156
    
 
157
 
125
158
 
126
159
def _get_cmd_dict(plugins_override=True):
127
160
    d = {}
200
233
        assert isinstance(arguments, dict)
201
234
        cmdargs = options.copy()
202
235
        cmdargs.update(arguments)
203
 
        assert self.__doc__ != Command.__doc__, \
204
 
               ("No help message set for %r" % self)
 
236
        if self.__doc__ == Command.__doc__:
 
237
            from warnings import warn
 
238
            warn("No help message set for %r" % self)
205
239
        self.status = self.run(**cmdargs)
 
240
        if self.status is None:
 
241
            self.status = 0
206
242
 
207
243
    
208
244
    def run(self):
220
256
class ExternalCommand(Command):
221
257
    """Class to wrap external commands.
222
258
 
223
 
    We cheat a little here, when get_cmd_class() calls us we actually give it back
224
 
    an object we construct that has the appropriate path, help, options etc for the
225
 
    specified command.
226
 
 
227
 
    When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
228
 
    method, which we override to call the Command.__init__ method. That then calls
229
 
    our run method which is pretty straight forward.
230
 
 
231
 
    The only wrinkle is that we have to map bzr's dictionary of options and arguments
232
 
    back into command line options and arguments for the script.
 
259
    We cheat a little here, when get_cmd_class() calls us we actually
 
260
    give it back an object we construct that has the appropriate path,
 
261
    help, options etc for the specified command.
 
262
 
 
263
    When run_bzr() tries to instantiate that 'class' it gets caught by
 
264
    the __call__ method, which we override to call the Command.__init__
 
265
    method. That then calls our run method which is pretty straight
 
266
    forward.
 
267
 
 
268
    The only wrinkle is that we have to map bzr's dictionary of options
 
269
    and arguments back into command line options and arguments for the
 
270
    script.
233
271
    """
234
272
 
235
273
    def find_command(cls, cmd):
409
447
    whether already versioned or not, are searched for files or
410
448
    subdirectories that are neither versioned or ignored, and these
411
449
    are added.  This search proceeds recursively into versioned
412
 
    directories.
 
450
    directories.  If no names are given '.' is assumed.
413
451
 
414
 
    Therefore simply saying 'bzr add .' will version all files that
 
452
    Therefore simply saying 'bzr add' will version all files that
415
453
    are currently unknown.
416
454
 
417
455
    TODO: Perhaps adding a file whose directly is not versioned should
418
456
    recursively add that parent, rather than giving an error?
419
457
    """
420
 
    takes_args = ['file+']
 
458
    takes_args = ['file*']
421
459
    takes_options = ['verbose', 'no-recurse']
422
460
    
423
461
    def run(self, file_list, verbose=False, no_recurse=False):
486
524
    def run(self, source_list, dest):
487
525
        b = find_branch('.')
488
526
 
 
527
        # TODO: glob expansion on windows?
489
528
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
490
529
 
491
530
 
511
550
 
512
551
 
513
552
 
 
553
class cmd_mv(Command):
 
554
    """Move or rename a file.
 
555
 
 
556
    usage:
 
557
        bzr mv OLDNAME NEWNAME
 
558
        bzr mv SOURCE... DESTINATION
 
559
 
 
560
    If the last argument is a versioned directory, all the other names
 
561
    are moved into it.  Otherwise, there must be exactly two arguments
 
562
    and the file is changed to a new name, which must not already exist.
 
563
 
 
564
    Files cannot be moved between branches.
 
565
    """
 
566
    takes_args = ['names*']
 
567
    def run(self, names_list):
 
568
        if len(names_list) < 2:
 
569
            raise BzrCommandError("missing file argument")
 
570
        b = find_branch(names_list[0])
 
571
 
 
572
        rel_names = [b.relpath(x) for x in names_list]
 
573
        
 
574
        if os.path.isdir(names_list[-1]):
 
575
            # move into existing directory
 
576
            b.move(rel_names[:-1], rel_names[-1])
 
577
        else:
 
578
            if len(names_list) != 2:
 
579
                raise BzrCommandError('to mv multiple files the destination '
 
580
                                      'must be a versioned directory')
 
581
            b.move(rel_names[0], rel_names[1])
 
582
            
 
583
    
514
584
 
515
585
 
516
586
class cmd_pull(Command):
583
653
    """
584
654
    takes_args = ['from_location', 'to_location?']
585
655
    takes_options = ['revision']
 
656
    aliases = ['get', 'clone']
586
657
 
587
658
    def run(self, from_location, to_location=None, revision=None):
588
659
        import errno
589
660
        from bzrlib.merge import merge
590
 
        from bzrlib.branch import DivergedBranches, NoSuchRevision, \
 
661
        from bzrlib.branch import DivergedBranches, \
591
662
             find_cached_branch, Branch
592
663
        from shutil import rmtree
593
664
        from meta_store import CachedStore
634
705
                    revno, rev_id = br_from.get_revision_info(revision[0])
635
706
                try:
636
707
                    br_to.update_revisions(br_from, stop_revision=revno)
637
 
                except NoSuchRevision:
 
708
                except bzrlib.errors.NoSuchRevision:
638
709
                    rmtree(to_location)
639
710
                    msg = "The branch %s has no revision %d." % (from_location,
640
711
                                                                 revno)
780
851
    If files are listed, only the changes in those files are listed.
781
852
    Otherwise, all changes for the tree are listed.
782
853
 
783
 
    TODO: Given two revision arguments, show the difference between them.
784
 
 
785
854
    TODO: Allow diff across branches.
786
855
 
787
856
    TODO: Option to use external diff command; could be GNU diff, wdiff,
796
865
          deleted files.
797
866
 
798
867
    TODO: This probably handles non-Unix newlines poorly.
 
868
 
 
869
    examples:
 
870
        bzr diff
 
871
        bzr diff -r1
 
872
        bzr diff -r1:2
799
873
    """
800
874
    
801
875
    takes_args = ['file*']
814
888
        else:
815
889
            b = find_branch('.')
816
890
 
817
 
        # TODO: Make show_diff support taking 2 arguments
818
 
        base_rev = None
819
891
        if revision is not None:
820
 
            if len(revision) != 1:
821
 
                raise BzrCommandError('bzr diff --revision takes exactly one revision identifier')
822
 
            base_rev = revision[0]
823
 
    
824
 
        show_diff(b, base_rev, specific_files=file_list,
825
 
                  external_diff_options=diff_options)
826
 
 
 
892
            if len(revision) == 1:
 
893
                show_diff(b, revision[0], specific_files=file_list,
 
894
                          external_diff_options=diff_options)
 
895
            elif len(revision) == 2:
 
896
                show_diff(b, revision[0], specific_files=file_list,
 
897
                          external_diff_options=diff_options,
 
898
                          revision2=revision[1])
 
899
            else:
 
900
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
 
901
        else:
 
902
            show_diff(b, None, specific_files=file_list,
 
903
                      external_diff_options=diff_options)
827
904
 
828
905
        
829
906
 
855
932
    """List files modified in working tree."""
856
933
    hidden = True
857
934
    def run(self):
858
 
        from bzrlib.diff import compare_trees
 
935
        from bzrlib.delta import compare_trees
859
936
 
860
937
        b = find_branch('.')
861
938
        td = compare_trees(b.basis_tree(), b.working_tree())
910
987
    """
911
988
 
912
989
    takes_args = ['filename?']
913
 
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long', 'message']
 
990
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
 
991
                     'long', 'message', 'short',]
914
992
    
915
993
    def run(self, filename=None, timezone='original',
916
994
            verbose=False,
918
996
            forward=False,
919
997
            revision=None,
920
998
            message=None,
921
 
            long=False):
 
999
            long=False,
 
1000
            short=False):
922
1001
        from bzrlib.branch import find_branch
923
1002
        from bzrlib.log import log_formatter, show_log
924
1003
        import codecs
958
1037
        # in e.g. the default C locale.
959
1038
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
960
1039
 
961
 
        if long:
 
1040
        if not short:
962
1041
            log_format = 'long'
963
1042
        else:
964
1043
            log_format = 'short'
1181
1260
 
1182
1261
class cmd_commit(Command):
1183
1262
    """Commit changes into a new revision.
 
1263
    
 
1264
    If no arguments are given, the entire tree is committed.
1184
1265
 
1185
1266
    If selected files are specified, only changes to those files are
1186
 
    committed.  If a directory is specified then its contents are also
1187
 
    committed.
 
1267
    committed.  If a directory is specified then the directory and everything 
 
1268
    within it is committed.
1188
1269
 
1189
1270
    A selected-file commit may fail in some cases where the committed
1190
1271
    tree would be invalid, such as trying to commit a file in a
1198
1279
    takes_options = ['message', 'file', 'verbose', 'unchanged']
1199
1280
    aliases = ['ci', 'checkin']
1200
1281
 
 
1282
    # TODO: Give better message for -s, --summary, used by tla people
 
1283
    
1201
1284
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1202
1285
            unchanged=False):
1203
1286
        from bzrlib.errors import PointlessCommit
1205
1288
 
1206
1289
        ## Warning: shadows builtin file()
1207
1290
        if not message and not file:
 
1291
            # FIXME: Ugly; change status code to send to a provided function?
 
1292
            
1208
1293
            import cStringIO
1209
1294
            stdout = sys.stdout
1210
1295
            catcher = cStringIO.StringIO()
1225
1310
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1226
1311
 
1227
1312
        b = find_branch('.')
1228
 
 
 
1313
        if selected_list:
 
1314
            selected_list = [b.relpath(s) for s in selected_list]
 
1315
            
1229
1316
        try:
1230
1317
            b.commit(message, verbose=verbose,
1231
1318
                     specific_files=selected_list,
1303
1390
class cmd_selftest(Command):
1304
1391
    """Run internal test suite"""
1305
1392
    hidden = True
1306
 
    def run(self):
 
1393
    takes_options = ['verbose']
 
1394
    def run(self, verbose=False):
1307
1395
        from bzrlib.selftest import selftest
1308
 
        return int(not selftest())
 
1396
        return int(not selftest(verbose=verbose))
1309
1397
 
1310
1398
 
1311
1399
class cmd_version(Command):
1367
1455
 
1368
1456
 
1369
1457
class cmd_merge(Command):
1370
 
    """Perform a three-way merge of trees.
1371
 
    
1372
 
    The SPEC parameters are working tree or revision specifiers.  Working trees
1373
 
    are specified using standard paths or urls.  No component of a directory
1374
 
    path may begin with '@'.
1375
 
    
1376
 
    Working tree examples: '.', '..', 'foo@', but NOT 'foo/@bar'
1377
 
 
1378
 
    Revisions are specified using a dirname/@revno pair, where dirname is the
1379
 
    branch directory and revno is the revision within that branch.  If no revno
1380
 
    is specified, the latest revision is used.
1381
 
 
1382
 
    Revision examples: './@127', 'foo/@', '../@1'
1383
 
 
1384
 
    The OTHER_SPEC parameter is required.  If the BASE_SPEC parameter is
1385
 
    not supplied, the common ancestor of OTHER_SPEC the current branch is used
1386
 
    as the BASE.
1387
 
 
 
1458
    """Perform a three-way merge.
 
1459
    
 
1460
    The branch is the branch you will merge from.  By default, it will merge
 
1461
    the latest revision.  If you specify a revision, that revision will be
 
1462
    merged.  If you specify two revisions, the first will be used as a BASE, 
 
1463
    and the second one as OTHER.  Revision numbers are always relative to the
 
1464
    specified branch.
 
1465
    
 
1466
    Examples:
 
1467
 
 
1468
    To merge the latest revision from bzr.dev
 
1469
    bzr merge ../bzr.dev
 
1470
 
 
1471
    To merge changes up to and including revision 82 from bzr.dev
 
1472
    bzr merge -r 82 ../bzr.dev
 
1473
 
 
1474
    To merge the changes introduced by 82, without previous changes:
 
1475
    bzr merge -r 81..82 ../bzr.dev
 
1476
    
1388
1477
    merge refuses to run if there are any uncommitted changes, unless
1389
1478
    --force is given.
1390
1479
    """
1391
 
    takes_args = ['other_spec', 'base_spec?']
1392
 
    takes_options = ['force']
 
1480
    takes_args = ['branch?']
 
1481
    takes_options = ['revision', 'force', 'merge-type']
1393
1482
 
1394
 
    def run(self, other_spec, base_spec=None, force=False):
 
1483
    def run(self, branch='.', revision=None, force=False, 
 
1484
            merge_type=None):
1395
1485
        from bzrlib.merge import merge
1396
 
        merge(parse_spec(other_spec), parse_spec(base_spec),
1397
 
              check_clean=(not force))
 
1486
        from bzrlib.merge_core import ApplyMerge3
 
1487
        if merge_type is None:
 
1488
            merge_type = ApplyMerge3
1398
1489
 
 
1490
        if revision is None or len(revision) < 1:
 
1491
            base = (None, None)
 
1492
            other = (branch, -1)
 
1493
        else:
 
1494
            if len(revision) == 1:
 
1495
                other = (branch, revision[0])
 
1496
                base = (None, None)
 
1497
            else:
 
1498
                assert len(revision) == 2
 
1499
                if None in revision:
 
1500
                    raise BzrCommandError(
 
1501
                        "Merge doesn't permit that revision specifier.")
 
1502
                base = (branch, revision[0])
 
1503
                other = (branch, revision[1])
 
1504
            
 
1505
        merge(other, base, check_clean=(not force), merge_type=merge_type)
1399
1506
 
1400
1507
 
1401
1508
class cmd_revert(Command):
1402
 
    """Restore selected files from a previous revision.
1403
 
    """
1404
 
    takes_args = ['file+']
1405
 
    def run(self, file_list):
1406
 
        from bzrlib.branch import find_branch
1407
 
        
1408
 
        if not file_list:
1409
 
            file_list = ['.']
1410
 
            
1411
 
        b = find_branch(file_list[0])
1412
 
 
1413
 
        b.revert([b.relpath(f) for f in file_list])
1414
 
 
1415
 
 
1416
 
class cmd_merge_revert(Command):
1417
1509
    """Reverse all changes since the last commit.
1418
1510
 
1419
 
    Only versioned files are affected.
1420
 
 
1421
 
    TODO: Store backups of any files that will be reverted, so
1422
 
          that the revert can be undone.          
 
1511
    Only versioned files are affected.  Specify filenames to revert only 
 
1512
    those files.  By default, any files that are changed will be backed up
 
1513
    first.  Backup files have a '~' appended to their name.
1423
1514
    """
1424
 
    takes_options = ['revision']
 
1515
    takes_options = ['revision', 'no-backup']
 
1516
    takes_args = ['file*']
 
1517
    aliases = ['merge-revert']
1425
1518
 
1426
 
    def run(self, revision=None):
 
1519
    def run(self, revision=None, no_backup=False, file_list=None):
1427
1520
        from bzrlib.merge import merge
 
1521
        if file_list is not None:
 
1522
            if len(file_list) == 0:
 
1523
                raise BzrCommandError("No files specified")
1428
1524
        if revision is None:
1429
1525
            revision = [-1]
1430
1526
        elif len(revision) != 1:
1431
 
            raise BzrCommandError('bzr merge-revert --revision takes exactly 1 argument')
 
1527
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1432
1528
        merge(('.', revision[0]), parse_spec('.'),
1433
1529
              check_clean=False,
1434
 
              ignore_zero=True)
 
1530
              ignore_zero=True,
 
1531
              backup_files=not no_backup,
 
1532
              file_list=file_list)
1435
1533
 
1436
1534
 
1437
1535
class cmd_assert_fail(Command):
1455
1553
 
1456
1554
 
1457
1555
 
 
1556
class cmd_missing(Command):
 
1557
    """What is missing in this branch relative to other branch.
 
1558
    """
 
1559
    takes_args = ['remote?']
 
1560
    aliases = ['mis', 'miss']
 
1561
    # We don't have to add quiet to the list, because 
 
1562
    # unknown options are parsed as booleans
 
1563
    takes_options = ['verbose', 'quiet']
 
1564
 
 
1565
    def run(self, remote=None, verbose=False, quiet=False):
 
1566
        from bzrlib.branch import find_branch, DivergedBranches
 
1567
        from bzrlib.errors import BzrCommandError
 
1568
        from bzrlib.missing import get_parent, show_missing
 
1569
 
 
1570
        if verbose and quiet:
 
1571
            raise BzrCommandError('Cannot pass both quiet and verbose')
 
1572
 
 
1573
        b = find_branch('.')
 
1574
        parent = get_parent(b)
 
1575
        if remote is None:
 
1576
            if parent is None:
 
1577
                raise BzrCommandError("No missing location known or specified.")
 
1578
            else:
 
1579
                if not quiet:
 
1580
                    print "Using last location: %s" % parent
 
1581
                remote = parent
 
1582
        elif parent is None:
 
1583
            # We only update x-pull if it did not exist, missing should not change the parent
 
1584
            b.controlfile('x-pull', 'wb').write(remote + '\n')
 
1585
        br_remote = find_branch(remote)
 
1586
 
 
1587
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
 
1588
 
 
1589
 
1458
1590
class cmd_plugins(Command):
1459
1591
    """List plugins"""
1460
1592
    hidden = True
1487
1619
    'no-recurse':             None,
1488
1620
    'profile':                None,
1489
1621
    'revision':               _parse_revision_str,
 
1622
    'short':                  None,
1490
1623
    'show-ids':               None,
1491
1624
    'timezone':               str,
1492
1625
    'verbose':                None,
1496
1629
    'update':                 None,
1497
1630
    'long':                   None,
1498
1631
    'root':                   str,
 
1632
    'no-backup':              None,
 
1633
    'merge-type':             get_merge_type,
1499
1634
    }
1500
1635
 
1501
1636
SHORT_OPTIONS = {
1651
1786
    return argdict
1652
1787
 
1653
1788
 
1654
 
def _parse_master_args(argv):
1655
 
    """Parse the arguments that always go with the original command.
1656
 
    These are things like bzr --no-plugins, etc.
1657
 
 
1658
 
    There are now 2 types of option flags. Ones that come *before* the command,
1659
 
    and ones that come *after* the command.
1660
 
    Ones coming *before* the command are applied against all possible commands.
1661
 
    And are generally applied before plugins are loaded.
1662
 
 
1663
 
    The current list are:
1664
 
        --builtin   Allow plugins to load, but don't let them override builtin commands,
1665
 
                    they will still be allowed if they do not override a builtin.
1666
 
        --no-plugins    Don't load any plugins. This lets you get back to official source
1667
 
                        behavior.
1668
 
        --profile   Enable the hotspot profile before running the command.
1669
 
                    For backwards compatibility, this is also a non-master option.
1670
 
        --version   Spit out the version of bzr that is running and exit.
1671
 
                    This is also a non-master option.
1672
 
        --help      Run help and exit, also a non-master option (I think that should stay, though)
1673
 
 
1674
 
    >>> argv, opts = _parse_master_args(['bzr', '--test'])
1675
 
    Traceback (most recent call last):
1676
 
    ...
1677
 
    BzrCommandError: Invalid master option: 'test'
1678
 
    >>> argv, opts = _parse_master_args(['bzr', '--version', 'command'])
1679
 
    >>> print argv
1680
 
    ['command']
1681
 
    >>> print opts['version']
1682
 
    True
1683
 
    >>> argv, opts = _parse_master_args(['bzr', '--profile', 'command', '--more-options'])
1684
 
    >>> print argv
1685
 
    ['command', '--more-options']
1686
 
    >>> print opts['profile']
1687
 
    True
1688
 
    >>> argv, opts = _parse_master_args(['bzr', '--no-plugins', 'command'])
1689
 
    >>> print argv
1690
 
    ['command']
1691
 
    >>> print opts['no-plugins']
1692
 
    True
1693
 
    >>> print opts['profile']
1694
 
    False
1695
 
    >>> argv, opts = _parse_master_args(['bzr', 'command', '--profile'])
1696
 
    >>> print argv
1697
 
    ['command', '--profile']
1698
 
    >>> print opts['profile']
1699
 
    False
1700
 
    """
1701
 
    master_opts = {'builtin':False,
1702
 
        'no-plugins':False,
1703
 
        'version':False,
1704
 
        'profile':False,
1705
 
        'help':False
1706
 
    }
1707
 
 
1708
 
    # This is the point where we could hook into argv[0] to determine
1709
 
    # what front-end is supposed to be run
1710
 
    # For now, we are just ignoring it.
1711
 
    cmd_name = argv.pop(0)
1712
 
    for arg in argv[:]:
1713
 
        if arg[:2] != '--': # at the first non-option, we return the rest
1714
 
            break
1715
 
        arg = arg[2:] # Remove '--'
1716
 
        if arg not in master_opts:
1717
 
            # We could say that this is not an error, that we should
1718
 
            # just let it be handled by the main section instead
1719
 
            raise BzrCommandError('Invalid master option: %r' % arg)
1720
 
        argv.pop(0) # We are consuming this entry
1721
 
        master_opts[arg] = True
1722
 
    return argv, master_opts
1723
 
 
1724
 
 
1725
1789
 
1726
1790
def run_bzr(argv):
1727
1791
    """Execute a command.
1728
1792
 
1729
1793
    This is similar to main(), but without all the trappings for
1730
1794
    logging and error handling.  
 
1795
    
 
1796
    argv
 
1797
       The command-line arguments, without the program name from argv[0]
 
1798
    
 
1799
    Returns a command status or raises an exception.
 
1800
 
 
1801
    Special master options: these must come before the command because
 
1802
    they control how the command is interpreted.
 
1803
 
 
1804
    --no-plugins
 
1805
        Do not load plugin modules at all
 
1806
 
 
1807
    --builtin
 
1808
        Only use builtin commands.  (Plugins are still allowed to change
 
1809
        other behaviour.)
 
1810
 
 
1811
    --profile
 
1812
        Run under the Python profiler.
1731
1813
    """
 
1814
    
1732
1815
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
 
1816
 
 
1817
    opt_profile = opt_no_plugins = opt_builtin = False
 
1818
 
 
1819
    # --no-plugins is handled specially at a very early stage. We need
 
1820
    # to load plugins before doing other command parsing so that they
 
1821
    # can override commands, but this needs to happen first.
 
1822
 
 
1823
    for a in argv[:]:
 
1824
        if a == '--profile':
 
1825
            opt_profile = True
 
1826
        elif a == '--no-plugins':
 
1827
            opt_no_plugins = True
 
1828
        elif a == '--builtin':
 
1829
            opt_builtin = True
 
1830
        else:
 
1831
            break
 
1832
        argv.remove(a)
 
1833
 
 
1834
    if not opt_no_plugins:
 
1835
        from bzrlib.plugin import load_plugins
 
1836
        load_plugins()
 
1837
 
 
1838
    args, opts = parse_args(argv)
 
1839
 
 
1840
    if 'help' in opts:
 
1841
        from bzrlib.help import help
 
1842
        if args:
 
1843
            help(args[0])
 
1844
        else:
 
1845
            help()
 
1846
        return 0            
 
1847
        
 
1848
    if 'version' in opts:
 
1849
        show_version()
 
1850
        return 0
1733
1851
    
1734
 
    try:
1735
 
        # some options like --builtin and --no-plugins have special effects
1736
 
        argv, master_opts = _parse_master_args(argv)
1737
 
        if not master_opts['no-plugins']:
1738
 
            from bzrlib.plugin import load_plugins
1739
 
            load_plugins()
1740
 
 
1741
 
        args, opts = parse_args(argv)
1742
 
 
1743
 
        if master_opts['help']:
1744
 
            from bzrlib.help import help
1745
 
            if argv:
1746
 
                help(argv[0])
1747
 
            else:
1748
 
                help()
1749
 
            return 0            
1750
 
            
1751
 
        if 'help' in opts:
1752
 
            from bzrlib.help import help
1753
 
            if args:
1754
 
                help(args[0])
1755
 
            else:
1756
 
                help()
1757
 
            return 0
1758
 
        elif 'version' in opts:
1759
 
            show_version()
1760
 
            return 0
1761
 
        elif args and args[0] == 'builtin':
1762
 
            include_plugins=False
1763
 
            args = args[1:]
1764
 
        cmd = str(args.pop(0))
1765
 
    except IndexError:
1766
 
        import help
1767
 
        help.help()
 
1852
    if not args:
 
1853
        print >>sys.stderr, "please try 'bzr help' for help"
1768
1854
        return 1
1769
 
          
1770
 
 
1771
 
    plugins_override = not (master_opts['builtin'])
1772
 
    canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
1773
 
 
1774
 
    profile = master_opts['profile']
1775
 
    # For backwards compatibility, I would rather stick with --profile being a
1776
 
    # master/global option
1777
 
    if 'profile' in opts:
1778
 
        profile = True
1779
 
        del opts['profile']
 
1855
    
 
1856
    cmd = str(args.pop(0))
 
1857
 
 
1858
    canonical_cmd, cmd_class = \
 
1859
                   get_cmd_class(cmd, plugins_override=not opt_builtin)
1780
1860
 
1781
1861
    # check options are reasonable
1782
1862
    allowed = cmd_class.takes_options
1791
1871
    for k, v in opts.items():
1792
1872
        cmdopts[k.replace('-', '_')] = v
1793
1873
 
1794
 
    if profile:
 
1874
    if opt_profile:
1795
1875
        import hotshot, tempfile
1796
1876
        pffileno, pfname = tempfile.mkstemp()
1797
1877
        try:
1818
1898
 
1819
1899
def _report_exception(summary, quiet=False):
1820
1900
    import traceback
 
1901
    
1821
1902
    log_error('bzr: ' + summary)
1822
1903
    bzrlib.trace.log_exception()
1823
1904
 
 
1905
    if os.environ.get('BZR_DEBUG'):
 
1906
        traceback.print_exc()
 
1907
 
1824
1908
    if not quiet:
 
1909
        sys.stderr.write('\n')
1825
1910
        tb = sys.exc_info()[2]
1826
1911
        exinfo = traceback.extract_tb(tb)
1827
1912
        if exinfo:
1837
1922
    try:
1838
1923
        try:
1839
1924
            try:
1840
 
                return run_bzr(argv)
 
1925
                return run_bzr(argv[1:])
1841
1926
            finally:
1842
1927
                # do this here inside the exception wrappers to catch EPIPE
1843
1928
                sys.stdout.flush()
1844
1929
        except BzrError, e:
1845
1930
            quiet = isinstance(e, (BzrCommandError))
1846
 
            _report_exception('error: ' + e.args[0], quiet=quiet)
 
1931
            _report_exception('error: ' + str(e), quiet=quiet)
1847
1932
            if len(e.args) > 1:
1848
1933
                for h in e.args[1]:
1849
1934
                    # some explanation or hints