/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Martin Pool
  • Date: 2006-10-06 02:04:17 UTC
  • mfrom: (1908.10.1 bench_usecases.merge2)
  • mto: This revision was merged to the branch mainline in revision 2068.
  • Revision ID: mbp@sourcefrog.net-20061006020417-4949ca86f4417a4d
merge additional fix from cfbolz

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
# TODO: "--profile=cum", to change sort order.  Is there any value in leaving
29
29
# the profile output behind so it can be interactively examined?
30
30
 
31
 
import sys
 
31
import codecs
 
32
import errno
32
33
import os
33
34
from warnings import warn
34
 
import errno
 
35
import sys
35
36
 
36
37
import bzrlib
 
38
import bzrlib.errors as errors
37
39
from bzrlib.errors import (BzrError,
 
40
                           BzrCommandError,
38
41
                           BzrCheckError,
39
 
                           BzrCommandError,
40
 
                           BzrOptionError,
41
42
                           NotBranchError)
 
43
from bzrlib import option
42
44
from bzrlib.option import Option
43
 
from bzrlib.revisionspec import RevisionSpec
44
 
from bzrlib.symbol_versioning import *
 
45
import bzrlib.osutils
 
46
from bzrlib.symbol_versioning import (deprecated_method, zero_eight)
45
47
import bzrlib.trace
46
48
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
47
49
 
62
64
        k_unsquished = _unsquish_command_name(k)
63
65
    else:
64
66
        k_unsquished = k
65
 
    if not plugin_cmds.has_key(k_unsquished):
 
67
    if k_unsquished not in plugin_cmds:
66
68
        plugin_cmds[k_unsquished] = cmd
67
69
        mutter('registered plugin command %s', k_unsquished)
68
70
        if decorate and k_unsquished in builtin_command_names():
127
129
    """
128
130
    from bzrlib.externalcommand import ExternalCommand
129
131
 
130
 
    cmd_name = str(cmd_name)            # not unicode
 
132
    # We want only 'ascii' command names, but the user may have typed
 
133
    # in a Unicode name. In that case, they should just get a
 
134
    # 'command not found' error later.
 
135
    # In the future, we may actually support Unicode command names.
131
136
 
132
137
    # first look up this command under the specified name
133
138
    cmds = _get_cmd_dict(plugins_override=plugins_override)
145
150
    if cmd_obj:
146
151
        return cmd_obj
147
152
 
148
 
    raise BzrCommandError("unknown command %r" % cmd_name)
 
153
    raise BzrCommandError('unknown command "%s"' % cmd_name)
149
154
 
150
155
 
151
156
class Command(object):
189
194
    hidden
190
195
        If true, this command isn't advertised.  This is typically
191
196
        for commands intended for expert users.
 
197
 
 
198
    encoding_type
 
199
        Command objects will get a 'outf' attribute, which has been
 
200
        setup to properly handle encoding of unicode strings.
 
201
        encoding_type determines what will happen when characters cannot
 
202
        be encoded
 
203
            strict - abort if we cannot decode
 
204
            replace - put in a bogus character (typically '?')
 
205
            exact - do not encode sys.stdout
 
206
 
192
207
    """
193
208
    aliases = []
194
209
    takes_args = []
195
210
    takes_options = []
 
211
    encoding_type = 'strict'
196
212
 
197
213
    hidden = False
198
214
    
208
224
        r = dict()
209
225
        r['help'] = Option.OPTIONS['help']
210
226
        for o in self.takes_options:
211
 
            if not isinstance(o, Option):
 
227
            if isinstance(o, basestring):
212
228
                o = Option.OPTIONS[o]
213
229
            r[o.name] = o
214
230
        return r
215
231
 
 
232
    def _setup_outf(self):
 
233
        """Return a file linked to stdout, which has proper encoding."""
 
234
        assert self.encoding_type in ['strict', 'exact', 'replace']
 
235
 
 
236
        # Originally I was using self.stdout, but that looks
 
237
        # *way* too much like sys.stdout
 
238
        if self.encoding_type == 'exact':
 
239
            self.outf = sys.stdout
 
240
            return
 
241
 
 
242
        output_encoding = bzrlib.osutils.get_terminal_encoding()
 
243
 
 
244
        # use 'replace' so that we don't abort if trying to write out
 
245
        # in e.g. the default C locale.
 
246
        self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
 
247
        # For whatever reason codecs.getwriter() does not advertise its encoding
 
248
        # it just returns the encoding of the wrapped file, which is completely
 
249
        # bogus. So set the attribute, so we can find the correct encoding later.
 
250
        self.outf.encoding = output_encoding
 
251
 
216
252
    @deprecated_method(zero_eight)
217
253
    def run_argv(self, argv):
218
254
        """Parse command line and run.
223
259
 
224
260
    def run_argv_aliases(self, argv, alias_argv=None):
225
261
        """Parse the command line and run with extra aliases in alias_argv."""
 
262
        if argv is None:
 
263
            warn("Passing None for [] is deprecated from bzrlib 0.10", 
 
264
                 DeprecationWarning, stacklevel=2)
 
265
            argv = []
226
266
        args, opts = parse_args(self, argv, alias_argv)
227
267
        if 'help' in opts:  # e.g. bzr add --help
228
268
            from bzrlib.help import help_on_command
229
269
            help_on_command(self.name())
230
270
            return 0
231
 
        # XXX: This should be handled by the parser
232
 
        allowed_names = self.options().keys()
233
 
        for oname in opts:
234
 
            if oname not in allowed_names:
235
 
                raise BzrCommandError("option '--%s' is not allowed for"
236
 
                                      " command %r" % (oname, self.name()))
237
271
        # mix arguments and options into one dictionary
238
272
        cmdargs = _match_argform(self.name(), self.takes_args, args)
239
273
        cmdopts = {}
243
277
        all_cmd_args = cmdargs.copy()
244
278
        all_cmd_args.update(cmdopts)
245
279
 
 
280
        self._setup_outf()
 
281
 
246
282
        return self.run(**all_cmd_args)
247
283
    
248
284
    def run(self):
268
304
    def name(self):
269
305
        return _unsquish_command_name(self.__class__.__name__)
270
306
 
 
307
    def plugin_name(self):
 
308
        """Get the name of the plugin that provides this command.
 
309
 
 
310
        :return: The name of the plugin or None if the command is builtin.
 
311
        """
 
312
        mod_parts = self.__module__.split('.')
 
313
        if len(mod_parts) >= 3 and mod_parts[1] == 'plugins':
 
314
            return mod_parts[2]
 
315
        else:
 
316
            return None
 
317
 
271
318
 
272
319
def parse_spec(spec):
273
320
    """
308
355
    lookup table, something about the available options, what optargs
309
356
    they take, and which commands will accept them.
310
357
    """
311
 
    # TODO: chop up this beast; make it a method of the Command
312
 
    args = []
313
 
    opts = {}
314
 
    alias_opts = {}
315
 
 
316
 
    cmd_options = command.options()
317
 
    argsover = False
318
 
    proc_aliasarg = True # Are we processing alias_argv now?
319
 
    for proc_argv in alias_argv, argv:
320
 
        while proc_argv:
321
 
            a = proc_argv.pop(0)
322
 
            if argsover:
323
 
                args.append(a)
324
 
                continue
325
 
            elif a == '--':
326
 
                # We've received a standalone -- No more flags
327
 
                argsover = True
328
 
                continue
329
 
            if a[0] == '-':
330
 
                # option names must not be unicode
331
 
                a = str(a)
332
 
                optarg = None
333
 
                if a[1] == '-':
334
 
                    mutter("  got option %r", a)
335
 
                    if '=' in a:
336
 
                        optname, optarg = a[2:].split('=', 1)
337
 
                    else:
338
 
                        optname = a[2:]
339
 
                    if optname not in cmd_options:
340
 
                        raise BzrOptionError('unknown long option %r for'
341
 
                                             ' command %s' % 
342
 
                                             (a, command.name()))
343
 
                else:
344
 
                    shortopt = a[1:]
345
 
                    if shortopt in Option.SHORT_OPTIONS:
346
 
                        # Multi-character options must have a space to delimit
347
 
                        # their value
348
 
                        # ^^^ what does this mean? mbp 20051014
349
 
                        optname = Option.SHORT_OPTIONS[shortopt].name
350
 
                    else:
351
 
                        # Single character short options, can be chained,
352
 
                        # and have their value appended to their name
353
 
                        shortopt = a[1:2]
354
 
                        if shortopt not in Option.SHORT_OPTIONS:
355
 
                            # We didn't find the multi-character name, and we
356
 
                            # didn't find the single char name
357
 
                            raise BzrError('unknown short option %r' % a)
358
 
                        optname = Option.SHORT_OPTIONS[shortopt].name
359
 
 
360
 
                        if a[2:]:
361
 
                            # There are extra things on this option
362
 
                            # see if it is the value, or if it is another
363
 
                            # short option
364
 
                            optargfn = Option.OPTIONS[optname].type
365
 
                            if optargfn is None:
366
 
                                # This option does not take an argument, so the
367
 
                                # next entry is another short option, pack it
368
 
                                # back into the list
369
 
                                proc_argv.insert(0, '-' + a[2:])
370
 
                            else:
371
 
                                # This option takes an argument, so pack it
372
 
                                # into the array
373
 
                                optarg = a[2:]
374
 
                
375
 
                    if optname not in cmd_options:
376
 
                        raise BzrOptionError('unknown short option %r for'
377
 
                                             ' command %s' % 
378
 
                                             (shortopt, command.name()))
379
 
                if optname in opts:
380
 
                    # XXX: Do we ever want to support this, e.g. for -r?
381
 
                    if proc_aliasarg:
382
 
                        raise BzrError('repeated option %r' % a)
383
 
                    elif optname in alias_opts:
384
 
                        # Replace what's in the alias with what's in the real
385
 
                        # argument
386
 
                        del alias_opts[optname]
387
 
                        del opts[optname]
388
 
                        proc_argv.insert(0, a)
389
 
                        continue
390
 
                    else:
391
 
                        raise BzrError('repeated option %r' % a)
392
 
                    
393
 
                option_obj = cmd_options[optname]
394
 
                optargfn = option_obj.type
395
 
                if optargfn:
396
 
                    if optarg == None:
397
 
                        if not proc_argv:
398
 
                            raise BzrError('option %r needs an argument' % a)
399
 
                        else:
400
 
                            optarg = proc_argv.pop(0)
401
 
                    opts[optname] = optargfn(optarg)
402
 
                    if proc_aliasarg:
403
 
                        alias_opts[optname] = optargfn(optarg)
404
 
                else:
405
 
                    if optarg != None:
406
 
                        raise BzrError('option %r takes no argument' % optname)
407
 
                    opts[optname] = True
408
 
                    if proc_aliasarg:
409
 
                        alias_opts[optname] = True
410
 
            else:
411
 
                args.append(a)
412
 
        proc_aliasarg = False # Done with alias argv
 
358
    # TODO: make it a method of the Command?
 
359
    parser = option.get_optparser(command.options())
 
360
    if alias_argv is not None:
 
361
        args = alias_argv + argv
 
362
    else:
 
363
        args = argv
 
364
 
 
365
    options, args = parser.parse_args(args)
 
366
    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if 
 
367
                 v is not option.OptionParser.DEFAULT_VALUE])
413
368
    return args, opts
414
369
 
415
370
 
440
395
                raise BzrCommandError("command %r needs one or more %s"
441
396
                        % (cmd, argname.upper()))
442
397
            argdict[argname + '_list'] = args[:-1]
443
 
            args[:-1] = []                
 
398
            args[:-1] = []
444
399
        else:
445
400
            # just a plain arg
446
401
            argname = ap
512
467
    
513
468
    argv
514
469
       The command-line arguments, without the program name from argv[0]
 
470
       These should already be decoded. All library/test code calling
 
471
       run_bzr should be passing valid strings (don't need decoding).
515
472
    
516
473
    Returns a command status or raises an exception.
517
474
 
534
491
    --lsprof
535
492
        Run under the Python lsprof profiler.
536
493
    """
537
 
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
 
494
    argv = list(argv)
538
495
 
539
496
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
540
497
                opt_no_aliases = False
553
510
        elif a == '--lsprof':
554
511
            opt_lsprof = True
555
512
        elif a == '--lsprof-file':
 
513
            opt_lsprof = True
556
514
            opt_lsprof_file = argv[i + 1]
557
515
            i += 1
558
516
        elif a == '--no-plugins':
570
528
    argv = argv_copy
571
529
    if (not argv):
572
530
        from bzrlib.builtins import cmd_help
573
 
        cmd_help().run_argv([])
 
531
        cmd_help().run_argv_aliases([])
574
532
        return 0
575
533
 
576
534
    if argv[0] == '--version':
577
 
        from bzrlib.builtins import show_version
 
535
        from bzrlib.version import show_version
578
536
        show_version()
579
537
        return 0
580
538
        
593
551
            alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
594
552
            argv[0] = alias_argv.pop(0)
595
553
 
596
 
    cmd = str(argv.pop(0))
 
554
    cmd = argv.pop(0)
 
555
    # We want only 'ascii' command names, but the user may have typed
 
556
    # in a Unicode name. In that case, they should just get a
 
557
    # 'command not found' error later.
597
558
 
598
559
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
599
560
    if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
623
584
            sys.stdout.flush()
624
585
            return result
625
586
        except IOError, e:
626
 
            if not hasattr(e, 'errno'):
 
587
            if getattr(e, 'errno', None) is None:
627
588
                raise
628
589
            if e.errno != errno.EPIPE:
629
 
                raise
 
590
                # Win32 raises IOError with errno=0 on a broken pipe
 
591
                if sys.platform != 'win32' or e.errno != 0:
 
592
                    raise
630
593
            pass
631
594
        except KeyboardInterrupt:
632
595
            pass
636
599
def main(argv):
637
600
    import bzrlib.ui
638
601
    from bzrlib.ui.text import TextUIFactory
639
 
    ## bzrlib.trace.enable_default_logging()
640
 
    bzrlib.trace.log_startup(argv)
641
602
    bzrlib.ui.ui_factory = TextUIFactory()
642
 
    ret = run_bzr_catch_errors(argv[1:])
 
603
    argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
 
604
    ret = run_bzr_catch_errors(argv)
643
605
    mutter("return code %d", ret)
644
606
    return ret
645
607
 
646
608
 
647
609
def run_bzr_catch_errors(argv):
648
610
    try:
649
 
        try:
650
 
            return run_bzr(argv)
651
 
        finally:
652
 
            # do this here inside the exception wrappers to catch EPIPE
653
 
            sys.stdout.flush()
654
 
    except Exception, e:
 
611
        return run_bzr(argv)
 
612
        # do this here inside the exception wrappers to catch EPIPE
 
613
        sys.stdout.flush()
 
614
    except (KeyboardInterrupt, Exception), e:
655
615
        # used to handle AssertionError and KeyboardInterrupt
656
616
        # specially here, but hopefully they're handled ok by the logger now
657
 
        import errno
658
 
        if (isinstance(e, IOError) 
659
 
            and hasattr(e, 'errno')
660
 
            and e.errno == errno.EPIPE):
661
 
            bzrlib.trace.note('broken pipe')
662
 
            return 3
663
 
        else:
664
 
            bzrlib.trace.log_exception()
665
 
            if os.environ.get('BZR_PDB'):
666
 
                print '**** entering debugger'
667
 
                import pdb
668
 
                pdb.post_mortem(sys.exc_traceback)
669
 
            return 3
 
617
        bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
 
618
        if os.environ.get('BZR_PDB'):
 
619
            print '**** entering debugger'
 
620
            import pdb
 
621
            pdb.post_mortem(sys.exc_traceback)
 
622
        return 3
670
623
 
671
624
if __name__ == '__main__':
672
625
    sys.exit(main(sys.argv))