~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

sync with bzr.dev mainline

Show diffs side-by-side

added added

removed removed

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