~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

Handled simultaneous renames of parent and child better

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
# Those objects can specify the expected type of the argument, which
25
25
# would help with validation and shell completion.
26
26
 
27
 
 
 
27
# TODO: "--profile=cum", to change sort order.  Is there any value in leaving
 
28
# the profile output behind so it can be interactively examined?
28
29
 
29
30
import sys
30
31
import os
31
32
from warnings import warn
32
33
from inspect import getdoc
 
34
import errno
33
35
 
34
36
import bzrlib
 
37
from bzrlib.config import GlobalConfig
35
38
import bzrlib.trace
36
 
from bzrlib.trace import mutter, note, log_error, warning
37
 
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
38
 
from bzrlib.branch import find_branch
 
39
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
 
40
from bzrlib.errors import (BzrError, 
 
41
                           BzrCheckError,
 
42
                           BzrCommandError,
 
43
                           BzrOptionError,
 
44
                           NotBranchError,
 
45
                           CommandDefaultSyntax,
 
46
                           )
 
47
from bzrlib.revisionspec import RevisionSpec
39
48
from bzrlib import BZRDIR
 
49
from bzrlib.option import Option
40
50
 
41
51
plugin_cmds = {}
42
52
 
43
53
 
44
 
def register_command(cmd):
 
54
def register_command(cmd, decorate=False):
45
55
    "Utility function to help register a command"
46
56
    global plugin_cmds
47
57
    k = cmd.__name__
52
62
    if not plugin_cmds.has_key(k_unsquished):
53
63
        plugin_cmds[k_unsquished] = cmd
54
64
        mutter('registered plugin command %s', k_unsquished)      
 
65
        if decorate and k_unsquished in builtin_command_names():
 
66
            return _builtin_commands()[k_unsquished]
 
67
    elif decorate:
 
68
        result = plugin_cmds[k_unsquished]
 
69
        plugin_cmds[k_unsquished] = cmd
 
70
        return result
55
71
    else:
56
72
        log_error('Two plugins defined the same command: %r' % k)
57
73
        log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
66
82
    return cmd[4:].replace('_','-')
67
83
 
68
84
 
69
 
def _parse_revision_str(revstr):
70
 
    """This handles a revision string -> revno.
71
 
 
72
 
    This always returns a list.  The list will have one element for 
73
 
 
74
 
    It supports integers directly, but everything else it
75
 
    defers for passing to Branch.get_revision_info()
76
 
 
77
 
    >>> _parse_revision_str('234')
78
 
    [234]
79
 
    >>> _parse_revision_str('234..567')
80
 
    [234, 567]
81
 
    >>> _parse_revision_str('..')
82
 
    [None, None]
83
 
    >>> _parse_revision_str('..234')
84
 
    [None, 234]
85
 
    >>> _parse_revision_str('234..')
86
 
    [234, None]
87
 
    >>> _parse_revision_str('234..456..789') # Maybe this should be an error
88
 
    [234, 456, 789]
89
 
    >>> _parse_revision_str('234....789') # Error?
90
 
    [234, None, 789]
91
 
    >>> _parse_revision_str('revid:test@other.com-234234')
92
 
    ['revid:test@other.com-234234']
93
 
    >>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
94
 
    ['revid:test@other.com-234234', 'revid:test@other.com-234235']
95
 
    >>> _parse_revision_str('revid:test@other.com-234234..23')
96
 
    ['revid:test@other.com-234234', 23]
97
 
    >>> _parse_revision_str('date:2005-04-12')
98
 
    ['date:2005-04-12']
99
 
    >>> _parse_revision_str('date:2005-04-12 12:24:33')
100
 
    ['date:2005-04-12 12:24:33']
101
 
    >>> _parse_revision_str('date:2005-04-12T12:24:33')
102
 
    ['date:2005-04-12T12:24:33']
103
 
    >>> _parse_revision_str('date:2005-04-12,12:24:33')
104
 
    ['date:2005-04-12,12:24:33']
105
 
    >>> _parse_revision_str('-5..23')
106
 
    [-5, 23]
107
 
    >>> _parse_revision_str('-5')
108
 
    [-5]
109
 
    >>> _parse_revision_str('123a')
110
 
    ['123a']
111
 
    >>> _parse_revision_str('abc')
112
 
    ['abc']
113
 
    """
114
 
    import re
115
 
    old_format_re = re.compile('\d*:\d*')
116
 
    m = old_format_re.match(revstr)
117
 
    if m:
118
 
        warning('Colon separator for revision numbers is deprecated.'
119
 
                ' Use .. instead')
120
 
        revs = []
121
 
        for rev in revstr.split(':'):
122
 
            if rev:
123
 
                revs.append(int(rev))
124
 
            else:
125
 
                revs.append(None)
126
 
        return revs
127
 
    revs = []
128
 
    for x in revstr.split('..'):
129
 
        if not x:
130
 
            revs.append(None)
131
 
        else:
132
 
            try:
133
 
                revs.append(int(x))
134
 
            except ValueError:
135
 
                revs.append(x)
136
 
    return revs
137
 
 
138
 
 
139
 
def get_merge_type(typestring):
140
 
    """Attempt to find the merge class/factory associated with a string."""
141
 
    from merge import merge_types
142
 
    try:
143
 
        return merge_types[typestring][0]
144
 
    except KeyError:
145
 
        templ = '%s%%7s: %%s' % (' '*12)
146
 
        lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
147
 
        type_list = '\n'.join(lines)
148
 
        msg = "No known merge type %s. Supported types are:\n%s" %\
149
 
            (typestring, type_list)
150
 
        raise BzrCommandError(msg)
151
 
    
152
 
 
153
85
def _builtin_commands():
154
86
    import bzrlib.builtins
155
87
    r = {}
239
171
        List of argument forms, marked with whether they are optional,
240
172
        repeated, etc.
241
173
 
 
174
                Examples:
 
175
 
 
176
                ['to_location', 'from_branch?', 'file*']
 
177
 
 
178
                'to_location' is required
 
179
                'from_branch' is optional
 
180
                'file' can be specified 0 or more times
 
181
 
242
182
    takes_options
243
 
        List of options that may be given for this command.
 
183
        List of options that may be given for this command.  These can
 
184
        be either strings, referring to globally-defined options,
 
185
        or option objects.  Retrieve through options().
244
186
 
245
187
    hidden
246
188
        If true, this command isn't advertised.  This is typically
247
189
        for commands intended for expert users.
248
190
    """
249
191
    aliases = []
250
 
    
251
192
    takes_args = []
252
193
    takes_options = []
253
194
 
258
199
        if self.__doc__ == Command.__doc__:
259
200
            warn("No help message set for %r" % self)
260
201
 
261
 
 
262
 
    def run_argv(self, argv):
 
202
    def options(self):
 
203
        """Return dict of valid options for this command.
 
204
 
 
205
        Maps from long option name to option object."""
 
206
        r = dict()
 
207
        r['help'] = Option.OPTIONS['help']
 
208
        for o in self.takes_options:
 
209
            if not isinstance(o, Option):
 
210
                o = Option.OPTIONS[o]
 
211
            r[o.name] = o
 
212
        return r
 
213
 
 
214
    def run_argv(self, argv, defaults=None):
263
215
        """Parse command line and run."""
264
 
        args, opts = parse_args(argv)
265
 
 
 
216
        if defaults is not None:
 
217
            args, opts = parse_args(self, defaults)
 
218
        else:
 
219
            args = []
 
220
            opts = {}
 
221
        cmd_args, cmd_opts = parse_args(self, argv)
 
222
        args.extend(cmd_args)
 
223
        opts.update(cmd_opts)
266
224
        if 'help' in opts:  # e.g. bzr add --help
267
225
            from bzrlib.help import help_on_command
268
226
            help_on_command(self.name())
269
227
            return 0
270
 
 
271
 
        # check options are reasonable
272
 
        allowed = self.takes_options
 
228
        # XXX: This should be handled by the parser
 
229
        allowed_names = self.options().keys()
273
230
        for oname in opts:
274
 
            if oname not in allowed:
 
231
            if oname not in allowed_names:
275
232
                raise BzrCommandError("option '--%s' is not allowed for command %r"
276
233
                                      % (oname, self.name()))
277
 
 
278
234
        # mix arguments and options into one dictionary
279
235
        cmdargs = _match_argform(self.name(), self.takes_args, args)
280
236
        cmdopts = {}
285
241
        all_cmd_args.update(cmdopts)
286
242
 
287
243
        return self.run(**all_cmd_args)
288
 
 
289
244
    
290
245
    def run(self):
291
246
        """Actually run the command.
341
296
        parsed = [spec, None]
342
297
    return parsed
343
298
 
344
 
 
345
 
 
346
 
 
347
 
# list of all available options; the rhs can be either None for an
348
 
# option that takes no argument, or a constructor function that checks
349
 
# the type.
350
 
OPTIONS = {
351
 
    'all':                    None,
352
 
    'diff-options':           str,
353
 
    'help':                   None,
354
 
    'file':                   unicode,
355
 
    'force':                  None,
356
 
    'format':                 unicode,
357
 
    'forward':                None,
358
 
    'message':                unicode,
359
 
    'no-recurse':             None,
360
 
    'profile':                None,
361
 
    'revision':               _parse_revision_str,
362
 
    'short':                  None,
363
 
    'show-ids':               None,
364
 
    'timezone':               str,
365
 
    'verbose':                None,
366
 
    'version':                None,
367
 
    'email':                  None,
368
 
    'unchanged':              None,
369
 
    'update':                 None,
370
 
    'long':                   None,
371
 
    'root':                   str,
372
 
    'no-backup':              None,
373
 
    'merge-type':             get_merge_type,
374
 
    'pattern':                str,
375
 
    }
376
 
 
377
 
SHORT_OPTIONS = {
378
 
    'F':                      'file', 
379
 
    'h':                      'help',
380
 
    'm':                      'message',
381
 
    'r':                      'revision',
382
 
    'v':                      'verbose',
383
 
    'l':                      'long',
384
 
}
385
 
 
386
 
 
387
 
def parse_args(argv):
 
299
def parse_args(command, argv):
388
300
    """Parse command line.
389
301
    
390
302
    Arguments and options are parsed at this level before being passed
391
303
    down to specific command handlers.  This routine knows, from a
392
304
    lookup table, something about the available options, what optargs
393
305
    they take, and which commands will accept them.
394
 
 
395
 
    >>> parse_args('--help'.split())
396
 
    ([], {'help': True})
397
 
    >>> parse_args('help -- --invalidcmd'.split())
398
 
    (['help', '--invalidcmd'], {})
399
 
    >>> parse_args('--version'.split())
400
 
    ([], {'version': True})
401
 
    >>> parse_args('status --all'.split())
402
 
    (['status'], {'all': True})
403
 
    >>> parse_args('commit --message=biter'.split())
404
 
    (['commit'], {'message': u'biter'})
405
 
    >>> parse_args('log -r 500'.split())
406
 
    (['log'], {'revision': [500]})
407
 
    >>> parse_args('log -r500..600'.split())
408
 
    (['log'], {'revision': [500, 600]})
409
 
    >>> parse_args('log -vr500..600'.split())
410
 
    (['log'], {'verbose': True, 'revision': [500, 600]})
411
 
    >>> parse_args('log -rv500..600'.split()) #the r takes an argument
412
 
    (['log'], {'revision': ['v500', 600]})
413
306
    """
 
307
    # TODO: chop up this beast; make it a method of the Command
414
308
    args = []
415
309
    opts = {}
416
310
 
 
311
    cmd_options = command.options()
417
312
    argsover = False
418
313
    while argv:
419
314
        a = argv.pop(0)
420
 
        if not argsover and a[0] == '-':
 
315
        if argsover:
 
316
            args.append(a)
 
317
            continue
 
318
        elif a == '--':
 
319
            # We've received a standalone -- No more flags
 
320
            argsover = True
 
321
            continue
 
322
        if a[0] == '-':
421
323
            # option names must not be unicode
422
324
            a = str(a)
423
325
            optarg = None
424
326
            if a[1] == '-':
425
 
                if a == '--':
426
 
                    # We've received a standalone -- No more flags
427
 
                    argsover = True
428
 
                    continue
429
 
                mutter("  got option %r" % a)
 
327
                mutter("  got option %r", a)
430
328
                if '=' in a:
431
329
                    optname, optarg = a[2:].split('=', 1)
432
330
                else:
433
331
                    optname = a[2:]
434
 
                if optname not in OPTIONS:
435
 
                    raise BzrError('unknown long option %r' % a)
 
332
                if optname not in cmd_options:
 
333
                    raise BzrOptionError('unknown long option %r for command %s'
 
334
                        % (a, command.name()))
436
335
            else:
437
336
                shortopt = a[1:]
438
 
                if shortopt in SHORT_OPTIONS:
 
337
                if shortopt in Option.SHORT_OPTIONS:
439
338
                    # Multi-character options must have a space to delimit
440
339
                    # their value
441
 
                    optname = SHORT_OPTIONS[shortopt]
 
340
                    # ^^^ what does this mean? mbp 20051014
 
341
                    optname = Option.SHORT_OPTIONS[shortopt].name
442
342
                else:
443
343
                    # Single character short options, can be chained,
444
344
                    # and have their value appended to their name
445
345
                    shortopt = a[1:2]
446
 
                    if shortopt not in SHORT_OPTIONS:
 
346
                    if shortopt not in Option.SHORT_OPTIONS:
447
347
                        # We didn't find the multi-character name, and we
448
348
                        # didn't find the single char name
449
349
                        raise BzrError('unknown short option %r' % a)
450
 
                    optname = SHORT_OPTIONS[shortopt]
 
350
                    optname = Option.SHORT_OPTIONS[shortopt].name
451
351
 
452
352
                    if a[2:]:
453
353
                        # There are extra things on this option
454
354
                        # see if it is the value, or if it is another
455
355
                        # short option
456
 
                        optargfn = OPTIONS[optname]
 
356
                        optargfn = Option.OPTIONS[optname].type
457
357
                        if optargfn is None:
458
358
                            # This option does not take an argument, so the
459
359
                            # next entry is another short option, pack it back
464
364
                            # into the array
465
365
                            optarg = a[2:]
466
366
            
 
367
                if optname not in cmd_options:
 
368
                    raise BzrOptionError('unknown short option %r for command'
 
369
                        ' %s' % (shortopt, command.name()))
467
370
            if optname in opts:
468
371
                # XXX: Do we ever want to support this, e.g. for -r?
469
372
                raise BzrError('repeated option %r' % a)
470
373
                
471
 
            optargfn = OPTIONS[optname]
 
374
            option_obj = cmd_options[optname]
 
375
            optargfn = option_obj.type
472
376
            if optargfn:
473
377
                if optarg == None:
474
378
                    if not argv:
482
386
                opts[optname] = True
483
387
        else:
484
388
            args.append(a)
485
 
 
486
389
    return args, opts
487
390
 
488
391
 
489
 
 
490
 
 
491
392
def _match_argform(cmd, takes_args, args):
492
393
    argdict = {}
493
394
 
536
437
def apply_profiled(the_callable, *args, **kwargs):
537
438
    import hotshot
538
439
    import tempfile
 
440
    import hotshot.stats
539
441
    pffileno, pfname = tempfile.mkstemp()
540
442
    try:
541
443
        prof = hotshot.Profile(pfname)
543
445
            ret = prof.runcall(the_callable, *args, **kwargs) or 0
544
446
        finally:
545
447
            prof.close()
546
 
 
547
 
        import hotshot.stats
548
448
        stats = hotshot.stats.load(pfname)
549
 
        #stats.strip_dirs()
550
 
        stats.sort_stats('time')
 
449
        stats.strip_dirs()
 
450
        stats.sort_stats('cum')   # 'time'
551
451
        ## XXX: Might like to write to stderr or the trace file instead but
552
452
        ## print_stats seems hardcoded to stdout
553
453
        stats.print_stats(20)
554
 
 
555
454
        return ret
556
455
    finally:
557
456
        os.close(pffileno)
558
457
        os.remove(pfname)
559
458
 
560
459
 
 
460
def apply_lsprofiled(the_callable, *args, **kwargs):
 
461
    from bzrlib.lsprof import profile
 
462
    ret,stats = profile(the_callable,*args,**kwargs)
 
463
    stats.sort()
 
464
    stats.pprint()
 
465
    return ret
 
466
 
561
467
def run_bzr(argv):
562
468
    """Execute a command.
563
469
 
580
486
        other behaviour.)
581
487
 
582
488
    --profile
583
 
        Run under the Python profiler.
 
489
        Run under the Python hotshot profiler.
 
490
 
 
491
    --lsprof
 
492
        Run under the Python lsprof profiler.
584
493
    """
585
 
    
586
494
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
587
495
 
588
 
    opt_profile = opt_no_plugins = opt_builtin = False
 
496
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = False
 
497
    opt_no_defaults = False
589
498
 
590
499
    # --no-plugins is handled specially at a very early stage. We need
591
500
    # to load plugins before doing other command parsing so that they
592
501
    # can override commands, but this needs to happen first.
593
502
 
594
 
    for a in argv:
 
503
    for a in argv[:]:
595
504
        if a == '--profile':
596
505
            opt_profile = True
 
506
        elif a == '--lsprof':
 
507
            opt_lsprof = True
597
508
        elif a == '--no-plugins':
598
509
            opt_no_plugins = True
599
510
        elif a == '--builtin':
600
511
            opt_builtin = True
 
512
        elif a in ('--quiet', '-q'):
 
513
            be_quiet()
 
514
        elif a in ('--no-defaults',):
 
515
            opt_no_defaults = True
601
516
        else:
602
 
            break
 
517
            continue
603
518
        argv.remove(a)
604
519
 
605
520
    if (not argv) or (argv[0] == '--help'):
618
533
    if not opt_no_plugins:
619
534
        from bzrlib.plugin import load_plugins
620
535
        load_plugins()
 
536
    else:
 
537
        from bzrlib.plugin import disable_plugins
 
538
        disable_plugins()
621
539
 
622
540
    cmd = str(argv.pop(0))
623
541
 
624
542
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
625
 
 
626
 
    if opt_profile:
627
 
        ret = apply_profiled(cmd_obj.run_argv, argv)
 
543
    if opt_no_defaults is True:
 
544
        cmd_defaults = []
628
545
    else:
629
 
        ret = cmd_obj.run_argv(argv)
630
 
    return ret or 0
 
546
        cmd_defaults = GlobalConfig().get_command_defaults(cmd_obj.name())
 
547
    try:
 
548
        if opt_lsprof:
 
549
            ret = apply_lsprofiled(cmd_obj.run_argv, argv, cmd_defaults)
 
550
        elif opt_profile:
 
551
            ret = apply_profiled(cmd_obj.run_argv, argv, cmd_defaults)
 
552
        else:
 
553
            ret = cmd_obj.run_argv(argv, cmd_defaults)
 
554
        return ret or 0
 
555
    finally:
 
556
        # reset, in case we may do other commands later within the same process
 
557
        be_quiet(False)
 
558
 
 
559
def display_command(func):
 
560
    """Decorator that suppresses pipe/interrupt errors."""
 
561
    def ignore_pipe(*args, **kwargs):
 
562
        try:
 
563
            result = func(*args, **kwargs)
 
564
            sys.stdout.flush()
 
565
            return result
 
566
        except IOError, e:
 
567
            if not hasattr(e, 'errno'):
 
568
                raise
 
569
            if e.errno != errno.EPIPE:
 
570
                raise
 
571
            pass
 
572
        except KeyboardInterrupt:
 
573
            pass
 
574
    return ignore_pipe
631
575
 
632
576
 
633
577
def main(argv):
634
578
    import bzrlib.ui
 
579
    from bzrlib.ui.text import TextUIFactory
 
580
    ## bzrlib.trace.enable_default_logging()
635
581
    bzrlib.trace.log_startup(argv)
636
 
    bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
637
 
 
 
582
    bzrlib.ui.ui_factory = TextUIFactory()
 
583
    ret = run_bzr_catch_errors(argv[1:])
 
584
    mutter("return code %d", ret)
 
585
    return ret
 
586
 
 
587
 
 
588
def run_bzr_catch_errors(argv):
638
589
    try:
639
590
        try:
640
 
            return run_bzr(argv[1:])
 
591
            return run_bzr(argv)
641
592
        finally:
642
593
            # do this here inside the exception wrappers to catch EPIPE
643
594
            sys.stdout.flush()
644
 
    except BzrCommandError, e:
645
 
        # command line syntax error, etc
646
 
        log_error(str(e))
647
 
        return 1
648
 
    except BzrError, e:
649
 
        bzrlib.trace.log_exception()
650
 
        return 1
651
 
    except AssertionError, e:
652
 
        bzrlib.trace.log_exception('assertion failed: ' + str(e))
653
 
        return 3
654
 
    except KeyboardInterrupt, e:
655
 
        bzrlib.trace.note('interrupted')
656
 
        return 2
657
595
    except Exception, e:
 
596
        # used to handle AssertionError and KeyboardInterrupt
 
597
        # specially here, but hopefully they're handled ok by the logger now
658
598
        import errno
659
599
        if (isinstance(e, IOError) 
660
600
            and hasattr(e, 'errno')
661
601
            and e.errno == errno.EPIPE):
662
602
            bzrlib.trace.note('broken pipe')
663
 
            return 2
 
603
            return 3
664
604
        else:
665
605
            bzrlib.trace.log_exception()
666
 
            return 2
667
 
 
 
606
            if os.environ.get('BZR_PDB'):
 
607
                print '**** entering debugger'
 
608
                import pdb
 
609
                pdb.post_mortem(sys.exc_traceback)
 
610
            return 3
668
611
 
669
612
if __name__ == '__main__':
670
613
    sys.exit(main(sys.argv))