~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Aaron Bentley
  • Date: 2005-10-04 04:32:32 UTC
  • mfrom: (1185.12.6)
  • mto: (1185.12.13)
  • mto: This revision was merged to the branch mainline in revision 1419.
  • Revision ID: aaron.bentley@utoronto.ca-20051004043231-40302a149769263b
merged my own changes

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
 
# TODO: "--profile=cum", to change sort order.  Is there any value in leaving
28
 
# the profile output behind so it can be interactively examined?
 
27
 
 
28
# TODO: Help messages for options.
 
29
 
 
30
# TODO: Define arguments by objects, rather than just using names.
 
31
# Those objects can specify the expected type of the argument, which
 
32
# would help with validation and shell completion.
 
33
 
 
34
 
 
35
# TODO: Help messages for options.
 
36
 
 
37
# TODO: Define arguments by objects, rather than just using names.
 
38
# Those objects can specify the expected type of the argument, which
 
39
# would help with validation and shell completion.
 
40
 
 
41
 
29
42
 
30
43
import sys
31
44
import os
32
45
from warnings import warn
33
46
from inspect import getdoc
34
 
import errno
35
47
 
36
48
import bzrlib
37
49
import bzrlib.trace
39
51
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
40
52
from bzrlib.revisionspec import RevisionSpec
41
53
from bzrlib import BZRDIR
42
 
from bzrlib.option import Option
43
54
 
44
55
plugin_cmds = {}
45
56
 
69
80
    return cmd[4:].replace('_','-')
70
81
 
71
82
 
 
83
def _parse_revision_str(revstr):
 
84
    """This handles a revision string -> revno.
 
85
 
 
86
    This always returns a list.  The list will have one element for
 
87
    each revision.
 
88
 
 
89
    >>> _parse_revision_str('234')
 
90
    [<RevisionSpec_int 234>]
 
91
    >>> _parse_revision_str('234..567')
 
92
    [<RevisionSpec_int 234>, <RevisionSpec_int 567>]
 
93
    >>> _parse_revision_str('..')
 
94
    [<RevisionSpec None>, <RevisionSpec None>]
 
95
    >>> _parse_revision_str('..234')
 
96
    [<RevisionSpec None>, <RevisionSpec_int 234>]
 
97
    >>> _parse_revision_str('234..')
 
98
    [<RevisionSpec_int 234>, <RevisionSpec None>]
 
99
    >>> _parse_revision_str('234..456..789') # Maybe this should be an error
 
100
    [<RevisionSpec_int 234>, <RevisionSpec_int 456>, <RevisionSpec_int 789>]
 
101
    >>> _parse_revision_str('234....789') # Error?
 
102
    [<RevisionSpec_int 234>, <RevisionSpec None>, <RevisionSpec_int 789>]
 
103
    >>> _parse_revision_str('revid:test@other.com-234234')
 
104
    [<RevisionSpec_revid revid:test@other.com-234234>]
 
105
    >>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
 
106
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>]
 
107
    >>> _parse_revision_str('revid:test@other.com-234234..23')
 
108
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_int 23>]
 
109
    >>> _parse_revision_str('date:2005-04-12')
 
110
    [<RevisionSpec_date date:2005-04-12>]
 
111
    >>> _parse_revision_str('date:2005-04-12 12:24:33')
 
112
    [<RevisionSpec_date date:2005-04-12 12:24:33>]
 
113
    >>> _parse_revision_str('date:2005-04-12T12:24:33')
 
114
    [<RevisionSpec_date date:2005-04-12T12:24:33>]
 
115
    >>> _parse_revision_str('date:2005-04-12,12:24:33')
 
116
    [<RevisionSpec_date date:2005-04-12,12:24:33>]
 
117
    >>> _parse_revision_str('-5..23')
 
118
    [<RevisionSpec_int -5>, <RevisionSpec_int 23>]
 
119
    >>> _parse_revision_str('-5')
 
120
    [<RevisionSpec_int -5>]
 
121
    >>> _parse_revision_str('123a')
 
122
    Traceback (most recent call last):
 
123
      ...
 
124
    BzrError: No namespace registered for string: '123a'
 
125
    >>> _parse_revision_str('abc')
 
126
    Traceback (most recent call last):
 
127
      ...
 
128
    BzrError: No namespace registered for string: 'abc'
 
129
    """
 
130
    import re
 
131
    old_format_re = re.compile('\d*:\d*')
 
132
    m = old_format_re.match(revstr)
 
133
    revs = []
 
134
    if m:
 
135
        warning('Colon separator for revision numbers is deprecated.'
 
136
                ' Use .. instead')
 
137
        for rev in revstr.split(':'):
 
138
            if rev:
 
139
                revs.append(RevisionSpec(int(rev)))
 
140
            else:
 
141
                revs.append(RevisionSpec(None))
 
142
    else:
 
143
        for x in revstr.split('..'):
 
144
            if not x:
 
145
                revs.append(RevisionSpec(None))
 
146
            else:
 
147
                revs.append(RevisionSpec(x))
 
148
    return revs
 
149
 
 
150
 
72
151
def _builtin_commands():
73
152
    import bzrlib.builtins
74
153
    r = {}
159
238
        repeated, etc.
160
239
 
161
240
    takes_options
162
 
        List of options that may be given for this command.  These can
163
 
        be either strings, referring to globally-defined options,
164
 
        or option objects.  Retrieve through options().
 
241
        List of options that may be given for this command.
165
242
 
166
243
    hidden
167
244
        If true, this command isn't advertised.  This is typically
168
245
        for commands intended for expert users.
169
246
    """
170
247
    aliases = []
 
248
    
171
249
    takes_args = []
172
250
    takes_options = []
173
251
 
178
256
        if self.__doc__ == Command.__doc__:
179
257
            warn("No help message set for %r" % self)
180
258
 
181
 
    def options(self):
182
 
        """Return dict of valid options for this command.
183
 
 
184
 
        Maps from long option name to option object."""
185
 
        r = dict()
186
 
        r['help'] = Option.OPTIONS['help']
187
 
        for o in self.takes_options:
188
 
            if not isinstance(o, Option):
189
 
                o = Option.OPTIONS[o]
190
 
            r[o.name] = o
191
 
        return r
192
259
 
193
260
    def run_argv(self, argv):
194
261
        """Parse command line and run."""
195
 
        args, opts = parse_args(self, argv)
 
262
        args, opts = parse_args(argv)
 
263
 
196
264
        if 'help' in opts:  # e.g. bzr add --help
197
265
            from bzrlib.help import help_on_command
198
266
            help_on_command(self.name())
199
267
            return 0
200
 
        # XXX: This should be handled by the parser
201
 
        allowed_names = self.options().keys()
 
268
 
 
269
        # check options are reasonable
 
270
        allowed = self.takes_options
202
271
        for oname in opts:
203
 
            if oname not in allowed_names:
 
272
            if oname not in allowed:
204
273
                raise BzrCommandError("option '--%s' is not allowed for command %r"
205
274
                                      % (oname, self.name()))
 
275
 
206
276
        # mix arguments and options into one dictionary
207
277
        cmdargs = _match_argform(self.name(), self.takes_args, args)
208
278
        cmdopts = {}
213
283
        all_cmd_args.update(cmdopts)
214
284
 
215
285
        return self.run(**all_cmd_args)
 
286
 
216
287
    
217
288
    def run(self):
218
289
        """Actually run the command.
268
339
        parsed = [spec, None]
269
340
    return parsed
270
341
 
271
 
def parse_args(command, argv):
 
342
 
 
343
# list of all available options; the rhs can be either None for an
 
344
# option that takes no argument, or a constructor function that checks
 
345
# the type.
 
346
OPTIONS = {
 
347
    'all':                    None,
 
348
    'basis':                  str,
 
349
    'diff-options':           str,
 
350
    'help':                   None,
 
351
    'file':                   unicode,
 
352
    'force':                  None,
 
353
    'format':                 unicode,
 
354
    'forward':                None,
 
355
    'message':                unicode,
 
356
    'no-recurse':             None,
 
357
    'profile':                None,
 
358
    'revision':               _parse_revision_str,
 
359
    'short':                  None,
 
360
    'show-ids':               None,
 
361
    'timezone':               str,
 
362
    'verbose':                None,
 
363
    'version':                None,
 
364
    'email':                  None,
 
365
    'unchanged':              None,
 
366
    'update':                 None,
 
367
    'long':                   None,
 
368
    'root':                   str,
 
369
    'no-backup':              None,
 
370
    'pattern':                str,
 
371
    }
 
372
 
 
373
SHORT_OPTIONS = {
 
374
    'F':                      'file', 
 
375
    'h':                      'help',
 
376
    'm':                      'message',
 
377
    'r':                      'revision',
 
378
    'v':                      'verbose',
 
379
    'l':                      'long',
 
380
}
 
381
 
 
382
 
 
383
def parse_args(argv):
272
384
    """Parse command line.
273
385
    
274
386
    Arguments and options are parsed at this level before being passed
275
387
    down to specific command handlers.  This routine knows, from a
276
388
    lookup table, something about the available options, what optargs
277
389
    they take, and which commands will accept them.
 
390
 
 
391
    >>> parse_args('--help'.split())
 
392
    ([], {'help': True})
 
393
    >>> parse_args('help -- --invalidcmd'.split())
 
394
    (['help', '--invalidcmd'], {})
 
395
    >>> parse_args('--version'.split())
 
396
    ([], {'version': True})
 
397
    >>> parse_args('status --all'.split())
 
398
    (['status'], {'all': True})
 
399
    >>> parse_args('commit --message=biter'.split())
 
400
    (['commit'], {'message': u'biter'})
 
401
    >>> parse_args('log -r 500'.split())
 
402
    (['log'], {'revision': [<RevisionSpec_int 500>]})
 
403
    >>> parse_args('log -r500..600'.split())
 
404
    (['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
 
405
    >>> parse_args('log -vr500..600'.split())
 
406
    (['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
 
407
    >>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
 
408
    (['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})
278
409
    """
279
 
    # TODO: chop up this beast; make it a method of the Command
280
410
    args = []
281
411
    opts = {}
282
412
 
283
 
    cmd_options = command.options()
284
413
    argsover = False
285
414
    while argv:
286
415
        a = argv.pop(0)
287
 
        if argsover:
288
 
            args.append(a)
289
 
            continue
290
 
        elif a == '--':
291
 
            # We've received a standalone -- No more flags
292
 
            argsover = True
293
 
            continue
294
 
        if a[0] == '-':
 
416
        if not argsover and a[0] == '-':
295
417
            # option names must not be unicode
296
418
            a = str(a)
297
419
            optarg = None
298
420
            if a[1] == '-':
 
421
                if a == '--':
 
422
                    # We've received a standalone -- No more flags
 
423
                    argsover = True
 
424
                    continue
299
425
                mutter("  got option %r" % a)
300
426
                if '=' in a:
301
427
                    optname, optarg = a[2:].split('=', 1)
302
428
                else:
303
429
                    optname = a[2:]
304
 
                if optname not in cmd_options:
305
 
                    raise BzrCommandError('unknown long option %r for command %s' 
306
 
                            % (a, command.name()))
 
430
                if optname not in OPTIONS:
 
431
                    raise BzrError('unknown long option %r' % a)
307
432
            else:
308
433
                shortopt = a[1:]
309
 
                if shortopt in Option.SHORT_OPTIONS:
 
434
                if shortopt in SHORT_OPTIONS:
310
435
                    # Multi-character options must have a space to delimit
311
436
                    # their value
312
 
                    # ^^^ what does this mean? mbp 20051014
313
 
                    optname = Option.SHORT_OPTIONS[shortopt].name
 
437
                    optname = SHORT_OPTIONS[shortopt]
314
438
                else:
315
439
                    # Single character short options, can be chained,
316
440
                    # and have their value appended to their name
317
441
                    shortopt = a[1:2]
318
 
                    if shortopt not in Option.SHORT_OPTIONS:
 
442
                    if shortopt not in SHORT_OPTIONS:
319
443
                        # We didn't find the multi-character name, and we
320
444
                        # didn't find the single char name
321
445
                        raise BzrError('unknown short option %r' % a)
322
 
                    optname = Option.SHORT_OPTIONS[shortopt].name
 
446
                    optname = SHORT_OPTIONS[shortopt]
323
447
 
324
448
                    if a[2:]:
325
449
                        # There are extra things on this option
326
450
                        # see if it is the value, or if it is another
327
451
                        # short option
328
 
                        optargfn = Option.OPTIONS[optname].type
 
452
                        optargfn = OPTIONS[optname]
329
453
                        if optargfn is None:
330
454
                            # This option does not take an argument, so the
331
455
                            # next entry is another short option, pack it back
340
464
                # XXX: Do we ever want to support this, e.g. for -r?
341
465
                raise BzrError('repeated option %r' % a)
342
466
                
343
 
            option_obj = cmd_options[optname]
344
 
            optargfn = option_obj.type
 
467
            optargfn = OPTIONS[optname]
345
468
            if optargfn:
346
469
                if optarg == None:
347
470
                    if not argv:
355
478
                opts[optname] = True
356
479
        else:
357
480
            args.append(a)
 
481
 
358
482
    return args, opts
359
483
 
360
484
 
 
485
 
 
486
 
361
487
def _match_argform(cmd, takes_args, args):
362
488
    argdict = {}
363
489
 
406
532
def apply_profiled(the_callable, *args, **kwargs):
407
533
    import hotshot
408
534
    import tempfile
409
 
    import hotshot.stats
410
535
    pffileno, pfname = tempfile.mkstemp()
411
536
    try:
412
537
        prof = hotshot.Profile(pfname)
414
539
            ret = prof.runcall(the_callable, *args, **kwargs) or 0
415
540
        finally:
416
541
            prof.close()
 
542
 
 
543
        import hotshot.stats
417
544
        stats = hotshot.stats.load(pfname)
418
 
        stats.strip_dirs()
419
 
        stats.sort_stats('cum')   # 'time'
 
545
        #stats.strip_dirs()
 
546
        stats.sort_stats('time')
420
547
        ## XXX: Might like to write to stderr or the trace file instead but
421
548
        ## print_stats seems hardcoded to stdout
422
549
        stats.print_stats(20)
 
550
 
423
551
        return ret
424
552
    finally:
425
553
        os.close(pffileno)
450
578
    --profile
451
579
        Run under the Python profiler.
452
580
    """
 
581
    # Load all of the transport methods
 
582
    import bzrlib.transport.local, bzrlib.transport.http
 
583
    
453
584
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
454
585
 
455
586
    opt_profile = opt_no_plugins = opt_builtin = False
496
627
        ret = cmd_obj.run_argv(argv)
497
628
    return ret or 0
498
629
 
499
 
def display_command(func):
500
 
    def ignore_pipe(*args, **kwargs):
501
 
        try:
502
 
            return func(*args, **kwargs)
503
 
        except IOError, e:
504
 
            if e.errno != errno.EPIPE:
505
 
                raise
506
 
        except KeyboardInterrupt:
507
 
            pass
508
 
    return ignore_pipe
509
630
 
510
631
def main(argv):
511
632
    import bzrlib.ui
518
639
def run_bzr_catch_errors(argv):
519
640
    try:
520
641
        try:
521
 
            return run_bzr(argv)
522
 
        finally:
523
 
            # do this here inside the exception wrappers to catch EPIPE
524
 
            sys.stdout.flush()
 
642
            try:
 
643
                return run_bzr(argv)
 
644
            finally:
 
645
                # do this here inside the exception wrappers to catch EPIPE
 
646
                sys.stdout.flush()
 
647
        #wrap common errors as CommandErrors.
 
648
        except (NotBranchError,), e:
 
649
            raise BzrCommandError(str(e))
525
650
    except BzrCommandError, e:
526
651
        # command line syntax error, etc
527
652
        log_error(str(e))
543
668
            bzrlib.trace.note('broken pipe')
544
669
            return 2
545
670
        else:
546
 
            ## import pdb
547
 
            ## pdb.pm()
548
671
            bzrlib.trace.log_exception()
549
672
            return 2
550
673