~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: mbp at sourcefrog
  • Date: 2005-03-23 23:52:10 UTC
  • Revision ID: mbp@sourcefrog.net-20050323235210-5464746b93c39ed0
more notes on darcs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/python
 
2
 
 
3
 
1
4
# Copyright (C) 2004, 2005 by Martin Pool
2
5
# Copyright (C) 2005 by Canonical Ltd
3
6
 
25
28
* Metadata format is not stable yet -- you may need to
26
29
  discard history in the future.
27
30
 
 
31
* No handling of subdirectories, symlinks or any non-text files.
 
32
 
28
33
* Insufficient error handling.
29
34
 
30
35
* Many commands unimplemented or partially implemented.
35
40
 
36
41
Interesting commands::
37
42
 
38
 
  bzr help [COMMAND]
39
 
       Show help screen
 
43
  bzr help
 
44
       Show summary help screen
40
45
  bzr version
41
46
       Show software version/licence/non-warranty.
42
47
  bzr init
45
50
       Make files versioned.
46
51
  bzr log
47
52
       Show revision history.
48
 
  bzr diff [FILE...]
 
53
  bzr diff
49
54
       Show changes from last revision to working copy.
50
55
  bzr commit -m 'MESSAGE'
51
56
       Store current state as new revision.
55
60
       Show summary of pending changes.
56
61
  bzr remove FILE...
57
62
       Make a file not versioned.
58
 
  bzr info
59
 
       Show statistics about this branch.
60
63
"""
61
64
 
62
 
 
63
 
 
64
 
 
65
 
import sys, os, time, types, shutil, tempfile, traceback, fnmatch, difflib, os.path
 
65
# not currently working:
 
66
#  bzr info
 
67
#       Show some information about this branch.
 
68
 
 
69
 
 
70
 
 
71
__copyright__ = "Copyright 2005 Canonical Development Ltd."
 
72
__author__ = "Martin Pool <mbp@canonical.com>"
 
73
__docformat__ = "restructuredtext en"
 
74
__version__ = '0.0.0'
 
75
 
 
76
 
 
77
import sys, os, random, time, sha, sets, types, re, shutil, tempfile
 
78
import traceback, socket, fnmatch, difflib
 
79
from os import path
66
80
from sets import Set
67
81
from pprint import pprint
68
82
from stat import *
71
85
import bzrlib
72
86
from bzrlib.store import ImmutableStore
73
87
from bzrlib.trace import mutter, note, log_error
74
 
from bzrlib.errors import bailout, BzrError, BzrCheckError
 
88
from bzrlib.errors import bailout, BzrError
75
89
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
76
90
from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
77
91
from bzrlib.revision import Revision
170
184
    Therefore simply saying 'bzr add .' will version all files that
171
185
    are currently unknown.
172
186
    """
173
 
    bzrlib.add.smart_add(file_list, verbose)
 
187
    if True:
 
188
        bzrlib.add.smart_add(file_list, verbose)
 
189
    else:
 
190
        # old way
 
191
        assert file_list
 
192
        b = Branch(file_list[0], find_root=True)
 
193
        b.add([b.relpath(f) for f in file_list], verbose=verbose)
 
194
 
174
195
    
175
196
 
176
197
def cmd_relpath(filename):
177
 
    """Show path of file relative to root"""
178
198
    print Branch(filename).relpath(filename)
179
199
 
180
200
 
181
 
 
182
201
def cmd_inventory(revision=None):
183
202
    """Show inventory of the current working copy."""
184
203
    ## TODO: Also optionally show a previous inventory
194
213
 
195
214
 
196
215
 
197
 
# TODO: Maybe a 'mv' command that has the combined move/rename
198
 
# special behaviour of Unix?
199
 
 
200
 
def cmd_move(source_list, dest):
201
 
    b = Branch('.')
202
 
 
203
 
    b.move([b.relpath(s) for s in source_list], b.relpath(dest))
204
 
 
205
 
 
206
 
 
207
 
def cmd_rename(from_name, to_name):
208
 
    """Change the name of an entry.
209
 
 
210
 
usage: bzr rename FROM_NAME TO_NAME
211
 
 
212
 
examples:
213
 
  bzr rename frob.c frobber.c
214
 
  bzr rename src/frob.c lib/frob.c
215
 
 
216
 
It is an error if the destination name exists.
217
 
 
218
 
See also the 'move' command, which moves files into a different
219
 
directory without changing their name.
220
 
 
221
 
TODO: Some way to rename multiple files without invoking bzr for each
222
 
one?"""
223
 
    b = Branch('.')
224
 
    b.rename_one(b.relpath(from_name), b.relpath(to_name))
225
 
    
226
 
 
227
 
 
228
 
 
229
 
def cmd_renames(dir='.'):
230
 
    """Show list of renamed files.
231
 
 
232
 
usage: bzr renames [BRANCH]
233
 
 
234
 
TODO: Option to show renames between two historical versions.
235
 
 
236
 
TODO: Only show renames under dir, rather than in the whole branch.
237
 
"""
238
 
    b = Branch(dir)
239
 
    old_inv = b.basis_tree().inventory
240
 
    new_inv = b.read_working_inventory()
241
 
    
242
 
    renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
243
 
    renames.sort()
244
 
    for old_name, new_name in renames:
245
 
        print "%s => %s" % (old_name, new_name)        
246
 
 
247
 
 
248
 
 
249
216
def cmd_info():
250
 
    """info: Show statistical information for this branch
251
 
 
252
 
usage: bzr info"""
253
 
    import info
254
 
    info.show_info(Branch('.'))        
 
217
    b = Branch('.')
 
218
    print 'branch format:', b.controlfile('branch-format', 'r').readline().rstrip('\n')
 
219
 
 
220
    def plural(n, base='', pl=None):
 
221
        if n == 1:
 
222
            return base
 
223
        elif pl is not None:
 
224
            return pl
 
225
        else:
 
226
            return 's'
 
227
 
 
228
    count_version_dirs = 0
 
229
 
 
230
    count_status = {'A': 0, 'D': 0, 'M': 0, 'R': 0, '?': 0, 'I': 0, '.': 0}
 
231
    for st_tup in bzrlib.diff_trees(b.basis_tree(), b.working_tree()):
 
232
        fs = st_tup[0]
 
233
        count_status[fs] += 1
 
234
        if fs not in ['I', '?'] and st_tup[4] == 'directory':
 
235
            count_version_dirs += 1
 
236
 
 
237
    print
 
238
    print 'in the working tree:'
 
239
    for name, fs in (('unchanged', '.'),
 
240
                     ('modified', 'M'), ('added', 'A'), ('removed', 'D'),
 
241
                     ('renamed', 'R'), ('unknown', '?'), ('ignored', 'I'),
 
242
                     ):
 
243
        print '  %5d %s' % (count_status[fs], name)
 
244
    print '  %5d versioned subdirector%s' % (count_version_dirs,
 
245
                                             plural(count_version_dirs, 'y', 'ies'))
 
246
 
 
247
    print
 
248
    print 'branch history:'
 
249
    history = b.revision_history()
 
250
    revno = len(history)
 
251
    print '  %5d revision%s' % (revno, plural(revno))
 
252
    committers = Set()
 
253
    for rev in history:
 
254
        committers.add(b.get_revision(rev).committer)
 
255
    print '  %5d committer%s' % (len(committers), plural(len(committers)))
 
256
    if revno > 0:
 
257
        firstrev = b.get_revision(history[0])
 
258
        age = int((time.time() - firstrev.timestamp) / 3600 / 24)
 
259
        print '  %5d day%s old' % (age, plural(age))
 
260
        print '  first revision: %s' % format_date(firstrev.timestamp,
 
261
                                                 firstrev.timezone)
 
262
 
 
263
        lastrev = b.get_revision(history[-1])
 
264
        print '  latest revision: %s' % format_date(lastrev.timestamp,
 
265
                                                    lastrev.timezone)
 
266
        
255
267
    
256
268
 
257
269
 
262
274
 
263
275
 
264
276
def cmd_file_id(filename):
265
 
    """Print file_id of a particular file or directory.
266
 
 
267
 
usage: bzr file-id FILE
268
 
 
269
 
The file_id is assigned when the file is first added and remains the
270
 
same through all revisions where the file exists, even when it is
271
 
moved or renamed.
272
 
"""
273
277
    b = Branch(filename)
274
278
    i = b.inventory.path2id(b.relpath(filename))
275
 
    if i == None:
276
 
        bailout("%r is not a versioned file" % filename)
 
279
    if i is None:
 
280
        bailout("%s is not a versioned file" % filename)
277
281
    else:
278
282
        print i
279
283
 
280
284
 
281
 
def cmd_file_id_path(filename):
282
 
    """Print path of file_ids to a file or directory.
283
 
 
284
 
usage: bzr file-id-path FILE
285
 
 
286
 
This prints one line for each directory down to the target,
287
 
starting at the branch root."""
288
 
    b = Branch(filename)
289
 
    inv = b.inventory
290
 
    fid = inv.path2id(b.relpath(filename))
291
 
    if fid == None:
292
 
        bailout("%r is not a versioned file" % filename)
293
 
    for fip in inv.get_idpath(fid):
294
 
        print fip
 
285
def cmd_find_filename(fileid):
 
286
    n = find_filename(fileid)
 
287
    if n is None:
 
288
        bailout("%s is not a live file id" % fileid)
 
289
    else:
 
290
        print n
295
291
 
296
292
 
297
293
def cmd_revision_history():
299
295
        print patchid
300
296
 
301
297
 
302
 
def cmd_directories():
303
 
    for name, ie in Branch('.').read_working_inventory().directories():
304
 
        if name == '':
305
 
            print '.'
306
 
        else:
307
 
            print name
308
 
 
309
 
 
310
 
def cmd_missing():
311
 
    for name, ie in Branch('.').working_tree().missing():
312
 
        print name
313
 
 
314
298
 
315
299
def cmd_init():
316
300
    # TODO: Check we're not already in a working directory?  At the
325
309
    Branch('.', init=True)
326
310
 
327
311
 
328
 
def cmd_diff(revision=None, file_list=None):
329
 
    """bzr diff: Show differences in working tree.
330
 
    
331
 
usage: bzr diff [-r REV] [FILE...]
332
 
 
333
 
--revision REV
334
 
    Show changes since REV, rather than predecessor.
335
 
 
336
 
If files are listed, only the changes in those files are listed.
337
 
Otherwise, all changes for the tree are listed.
338
 
 
339
 
TODO: Given two revision arguments, show the difference between them.
340
 
 
341
 
TODO: Allow diff across branches.
342
 
 
343
 
TODO: Option to use external diff command; could be GNU diff, wdiff,
344
 
or a graphical diff.
345
 
 
346
 
TODO: If a directory is given, diff everything under that.
347
 
 
348
 
TODO: Selected-file diff is inefficient and doesn't show you deleted files.
349
 
"""
350
 
 
351
 
    ## TODO: Shouldn't be in the cmd function.
 
312
def cmd_diff(revision=None):
 
313
    """Show diff from basis to working copy.
 
314
 
 
315
    :todo: Take one or two revision arguments, look up those trees,
 
316
           and diff them.
 
317
 
 
318
    :todo: Allow diff across branches.
 
319
 
 
320
    :todo: Mangle filenames in diff to be more relevant.
 
321
 
 
322
    :todo: Shouldn't be in the cmd function.
 
323
    """
352
324
 
353
325
    b = Branch('.')
354
326
 
358
330
        old_tree = b.revision_tree(b.lookup_revision(revision))
359
331
        
360
332
    new_tree = b.working_tree()
 
333
    old_inv = old_tree.inventory
 
334
    new_inv = new_tree.inventory
361
335
 
362
336
    # TODO: Options to control putting on a prefix or suffix, perhaps as a format string
363
337
    old_label = ''
372
346
    # be usefully made into a much faster special case.
373
347
 
374
348
    # TODO: Better to return them in sorted order I think.
375
 
 
376
 
    # FIXME: If given a file list, compare only those files rather
377
 
    # than comparing everything and then throwing stuff away.
378
349
    
379
350
    for file_state, fid, old_name, new_name, kind in bzrlib.diff_trees(old_tree, new_tree):
 
351
        d = None
380
352
 
381
 
        if file_list and new_name not in file_list:
382
 
            continue
383
 
        
384
353
        # Don't show this by default; maybe do it if an option is passed
385
354
        # idlabel = '      {%s}' % fid
386
355
        idlabel = ''
388
357
        # FIXME: Something about the diff format makes patch unhappy
389
358
        # with newly-added files.
390
359
 
391
 
        def diffit(oldlines, newlines, **kw):
392
 
            # FIXME: difflib is wrong if there is no trailing newline.
393
 
 
394
 
            # Special workaround for Python2.3, where difflib fails if
395
 
            # both sequences are empty.
396
 
            if oldlines or newlines:
397
 
                sys.stdout.writelines(difflib.unified_diff(oldlines, newlines, **kw))
 
360
        def diffit(*a, **kw):
 
361
            sys.stdout.writelines(difflib.unified_diff(*a, **kw))
398
362
            print
399
363
        
400
364
        if file_state in ['.', '?', 'I']:
431
395
 
432
396
 
433
397
 
434
 
def cmd_deleted(show_ids=False):
435
 
    """List files deleted in the working tree.
436
 
 
437
 
TODO: Show files deleted since a previous revision, or between two revisions.
438
 
    """
439
 
    b = Branch('.')
440
 
    old = b.basis_tree()
441
 
    new = b.working_tree()
442
 
 
443
 
    ## TODO: Much more efficient way to do this: read in new
444
 
    ## directories with readdir, rather than stating each one.  Same
445
 
    ## level of effort but possibly much less IO.  (Or possibly not,
446
 
    ## if the directories are very large...)
447
 
 
448
 
    for path, ie in old.inventory.iter_entries():
449
 
        if not new.has_id(ie.file_id):
450
 
            if show_ids:
451
 
                print '%-50s %s' % (path, ie.file_id)
452
 
            else:
453
 
                print path
454
 
 
455
 
 
456
 
 
457
 
def cmd_parse_inventory():
458
 
    import cElementTree
459
 
    
460
 
    cElementTree.ElementTree().parse(file('.bzr/inventory'))
461
 
 
462
 
 
463
 
 
464
 
def cmd_load_inventory():
465
 
    """Load inventory for timing purposes"""
466
 
    Branch('.').basis_tree().inventory
467
 
 
468
 
 
469
 
def cmd_dump_inventory():
470
 
    Branch('.').read_working_inventory().write_xml(sys.stdout)
471
 
 
472
 
 
473
 
def cmd_dump_new_inventory():
474
 
    import bzrlib.newinventory
475
 
    inv = Branch('.').basis_tree().inventory
476
 
    bzrlib.newinventory.write_inventory(inv, sys.stdout)
477
 
 
478
 
 
479
 
def cmd_load_new_inventory():
480
 
    import bzrlib.newinventory
481
 
    bzrlib.newinventory.read_new_inventory(sys.stdin)
482
 
                
483
 
    
484
 
def cmd_dump_slacker_inventory():
485
 
    import bzrlib.newinventory
486
 
    inv = Branch('.').basis_tree().inventory
487
 
    bzrlib.newinventory.write_slacker_inventory(inv, sys.stdout)
488
 
                
489
 
    
490
 
 
491
398
def cmd_root(filename=None):
492
399
    """Print the branch root."""
493
400
    print bzrlib.branch.find_branch_root(filename)
533
440
        print quotefn(f)
534
441
 
535
442
 
536
 
 
537
 
def cmd_ignored():
538
 
    """List ignored files and the patterns that matched them.
539
 
      """
540
 
    tree = Branch('.').working_tree()
541
 
    for path, file_class, kind, file_id in tree.list_files():
542
 
        if file_class != 'I':
543
 
            continue
544
 
        ## XXX: Slightly inefficient since this was already calculated
545
 
        pat = tree.is_ignored(path)
546
 
        print '%-50s %s' % (path, pat)
547
 
 
548
 
 
549
443
def cmd_lookup_revision(revno):
550
444
    try:
551
445
        revno = int(revno)
564
458
    t = b.revision_tree(rh)
565
459
    t.export(dest)
566
460
 
567
 
def cmd_cat(revision, filename):
568
 
    """Print file to stdout."""
569
 
    b = Branch('.')
570
 
    b.print_file(b.relpath(filename), int(revision))
571
461
 
572
462
 
573
463
######################################################################
586
476
 
587
477
 
588
478
def cmd_commit(message=None, verbose=False):
589
 
    """Commit changes to a new revision.
590
 
 
591
 
--message MESSAGE
592
 
    Description of changes in this revision; free form text.
593
 
    It is recommended that the first line be a single-sentence
594
 
    summary.
595
 
--verbose
596
 
    Show status of changed files,
597
 
 
598
 
TODO: Commit only selected files.
599
 
 
600
 
TODO: Run hooks on tree to-be-committed, and after commit.
601
 
 
602
 
TODO: Strict commit that fails if there are unknown or deleted files.
603
 
"""
604
 
 
605
479
    if not message:
606
480
        bailout("please specify a commit message")
607
481
    Branch('.').commit(message, verbose=verbose)
608
482
 
609
483
 
610
 
def cmd_check(dir='.'):
611
 
    """check: Consistency check of branch history.
612
 
 
613
 
usage: bzr check [-v] [BRANCH]
614
 
 
615
 
options:
616
 
  --verbose, -v         Show progress of checking.
617
 
 
618
 
This command checks various invariants about the branch storage to
619
 
detect data corruption or bzr bugs.
620
 
"""
621
 
    import bzrlib.check
622
 
    bzrlib.check.check(Branch(dir, find_root=False))
 
484
def cmd_check():
 
485
    """Check consistency of the branch."""
 
486
    check()
623
487
 
624
488
 
625
489
def cmd_is(pred, *rest):
646
510
 
647
511
 
648
512
def cmd_gen_revision_id():
 
513
    import time
649
514
    print bzrlib.branch._gen_revision_id(time.time())
650
515
 
651
516
 
652
 
def cmd_selftest():
 
517
def cmd_selftest(verbose=False):
653
518
    """Run internal test suite"""
654
519
    ## -v, if present, is seen by doctest; the argument is just here
655
520
    ## so our parser doesn't complain
688
553
# help
689
554
 
690
555
 
691
 
def cmd_help(topic=None):
692
 
    if topic == None:
693
 
        print __doc__
694
 
        return
695
 
 
696
 
    # otherwise, maybe the name of a command?
697
 
    try:
698
 
        cmdfn = globals()['cmd_' + topic.replace('-', '_')]
699
 
    except KeyError:
700
 
        bailout("no help for %r" % topic)
701
 
 
702
 
    doc = cmdfn.__doc__
703
 
    if doc == None:
704
 
        bailout("sorry, no detailed help yet for %r" % topic)
705
 
 
706
 
    print doc
707
 
        
708
 
 
 
556
def cmd_help():
 
557
    # TODO: Specific help for particular commands
 
558
    print __doc__
709
559
 
710
560
 
711
561
def cmd_version():
712
 
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
713
 
    print bzrlib.__copyright__
 
562
    print "bzr (bazaar-ng) %s" % __version__
 
563
    print __copyright__
714
564
    print "http://bazaar-ng.org/"
715
565
    print
716
566
    print \
736
586
    'all':                    None,
737
587
    'help':                   None,
738
588
    'message':                unicode,
739
 
    'profile':                None,
740
589
    'revision':               int,
741
590
    'show-ids':               None,
742
591
    'timezone':               str,
754
603
# listed take none.
755
604
cmd_options = {
756
605
    'add':                    ['verbose'],
757
 
    'cat':                    ['revision'],
758
606
    'commit':                 ['message', 'verbose'],
759
 
    'deleted':                ['show-ids'],
760
607
    'diff':                   ['revision'],
761
608
    'inventory':              ['revision'],
762
 
    'log':                    ['timezone'],
 
609
    'log':                    ['show-ids', 'timezone'],
763
610
    'ls':                     ['revision', 'verbose'],
764
611
    'remove':                 ['verbose'],
765
612
    'status':                 ['all'],
767
614
 
768
615
 
769
616
cmd_args = {
 
617
    'init':                   [],
770
618
    'add':                    ['file+'],
771
 
    'cat':                    ['filename'],
772
619
    'commit':                 [],
773
 
    'diff':                   ['file*'],
774
 
    'export':                 ['revno', 'dest'],
 
620
    'diff':                   [],
775
621
    'file-id':                ['filename'],
776
 
    'file-id-path':           ['filename'],
 
622
    'root':                   ['filename?'],
 
623
    'relpath':                ['filename'],
777
624
    'get-file-text':          ['text_id'],
778
625
    'get-inventory':          ['inventory_id'],
779
626
    'get-revision':           ['revision_id'],
780
627
    'get-revision-inventory': ['revision_id'],
781
 
    'help':                   ['topic?'],
782
 
    'init':                   [],
783
628
    'log':                    [],
784
629
    'lookup-revision':        ['revno'],
785
 
    'move':                   ['source$', 'dest'],
786
 
    'relpath':                ['filename'],
 
630
    'export':                 ['revno', 'dest'],
787
631
    'remove':                 ['file+'],
788
 
    'rename':                 ['from_name', 'to_name'],
789
 
    'renames':                ['dir?'],
790
 
    'root':                   ['filename?'],
791
632
    'status':                 [],
792
633
    }
793
634
 
844
685
                    else:
845
686
                        optarg = argv.pop(0)
846
687
                opts[optname] = optargfn(optarg)
 
688
                mutter("    option argument %r" % opts[optname])
847
689
            else:
848
690
                if optarg != None:
849
691
                    bailout('option %r takes no argument' % optname)
879
721
        if ap[-1] == '?':
880
722
            if args:
881
723
                argdict[argname] = args.pop(0)
882
 
        elif ap[-1] == '*': # all remaining arguments
883
 
            if args:
884
 
                argdict[argname + '_list'] = args[:]
885
 
                args = []
886
 
            else:
887
 
                argdict[argname + '_list'] = None
 
724
        elif ap[-1] == '*':
 
725
            assert 0
888
726
        elif ap[-1] == '+':
889
727
            if not args:
890
728
                bailout("command %r needs one or more %s"
892
730
            else:
893
731
                argdict[argname + '_list'] = args[:]
894
732
                args = []
895
 
        elif ap[-1] == '$': # all but one
896
 
            if len(args) < 2:
897
 
                bailout("command %r needs one or more %s"
898
 
                        % (cmd, argname.upper()))
899
 
            argdict[argname + '_list'] = args[:-1]
900
 
            args[:-1] = []                
901
733
        else:
902
734
            # just a plain arg
903
735
            argname = ap
926
758
        if 'help' in opts:
927
759
            # TODO: pass down other arguments in case they asked for
928
760
            # help on a command name?
929
 
            if args:
930
 
                cmd_help(args[0])
931
 
            else:
932
 
                cmd_help()
 
761
            cmd_help()
933
762
            return 0
934
763
        elif 'version' in opts:
935
764
            cmd_version()
939
768
        log_error('usage: bzr COMMAND\n')
940
769
        log_error('  try "bzr help"\n')
941
770
        return 1
942
 
 
 
771
            
943
772
    try:
944
773
        cmd_handler = globals()['cmd_' + cmd.replace('-', '_')]
945
774
    except KeyError:
946
775
        bailout("unknown command " + `cmd`)
947
776
 
948
 
    # global option
949
 
    if 'profile' in opts:
950
 
        profile = True
951
 
        del opts['profile']
952
 
    else:
953
 
        profile = False
 
777
    # TODO: special --profile option to turn on the Python profiler
954
778
 
955
779
    # check options are reasonable
956
780
    allowed = cmd_options.get(cmd, [])
959
783
            bailout("option %r is not allowed for command %r"
960
784
                    % (oname, cmd))
961
785
 
962
 
    # TODO: give an error if there are any mandatory options which are
963
 
    # not specified?  Or maybe there shouldn't be any "mandatory
964
 
    # options" (it is an oxymoron)
965
 
 
966
 
    # mix arguments and options into one dictionary
967
786
    cmdargs = _match_args(cmd, args)
968
 
    for k, v in opts.items():
969
 
        cmdargs[k.replace('-', '_')] = v
970
 
 
971
 
    if profile:
972
 
        import hotshot
973
 
        prof = hotshot.Profile('.bzr.profile')
974
 
        ret = prof.runcall(cmd_handler, **cmdargs) or 0
975
 
        prof.close()
976
 
 
977
 
        import hotshot.stats
978
 
        stats = hotshot.stats.load('.bzr.profile')
979
 
        #stats.strip_dirs()
980
 
        stats.sort_stats('time')
981
 
        stats.print_stats(20)
982
 
 
983
 
        return ret
984
 
    else:
985
 
        return cmd_handler(**cmdargs) or 0
 
787
    cmdargs.update(opts)
 
788
 
 
789
    ret = cmd_handler(**cmdargs) or 0
986
790
 
987
791
 
988
792
 
1003
807
        if len(e.args) > 1:
1004
808
            for h in e.args[1]:
1005
809
                log_error('  ' + h + '\n')
1006
 
        traceback.print_exc(None, bzrlib.trace._tracefile)
1007
 
        log_error('(see $HOME/.bzr.log for debug information)\n')
1008
810
        return 1
1009
811
    except Exception, e:
1010
812
        log_error('bzr: exception: %s\n' % e)
1011
 
        log_error('(see $HOME/.bzr.log for debug information)\n')
 
813
        log_error('    see .bzr.log for details\n')
1012
814
        traceback.print_exc(None, bzrlib.trace._tracefile)
1013
 
        ## traceback.print_exc(None, sys.stderr)
 
815
        traceback.print_exc(None, sys.stderr)
1014
816
        return 1
1015
817
 
1016
818
    # TODO: Maybe nicer handling of IOError?