~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

Late bind to PatienceSequenceMatcher to allow plugin to override.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
import os
33
33
from warnings import warn
34
34
import errno
35
 
import codecs
36
35
 
37
36
import bzrlib
38
 
import bzrlib.errors as errors
39
37
from bzrlib.errors import (BzrError,
 
38
                           BzrCheckError,
40
39
                           BzrCommandError,
41
 
                           BzrCheckError,
 
40
                           BzrOptionError,
42
41
                           NotBranchError)
43
42
from bzrlib.option import Option
44
 
import bzrlib.osutils
45
43
from bzrlib.revisionspec import RevisionSpec
46
 
from bzrlib.symbol_versioning import (deprecated_method, zero_eight)
 
44
from bzrlib.symbol_versioning import *
47
45
import bzrlib.trace
48
46
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
49
47
 
147
145
    if cmd_obj:
148
146
        return cmd_obj
149
147
 
150
 
    raise BzrCommandError('unknown command "%s"' % cmd_name)
 
148
    raise BzrCommandError("unknown command %r" % cmd_name)
151
149
 
152
150
 
153
151
class Command(object):
191
189
    hidden
192
190
        If true, this command isn't advertised.  This is typically
193
191
        for commands intended for expert users.
194
 
 
195
 
    encoding_type
196
 
        Command objects will get a 'outf' attribute, which has been
197
 
        setup to properly handle encoding of unicode strings.
198
 
        encoding_type determines what will happen when characters cannot
199
 
        be encoded
200
 
            strict - abort if we cannot decode
201
 
            replace - put in a bogus character (typically '?')
202
 
            exact - do not encode sys.stdout
203
 
 
204
192
    """
205
193
    aliases = []
206
194
    takes_args = []
207
195
    takes_options = []
208
 
    encoding_type = 'strict'
209
196
 
210
197
    hidden = False
211
198
    
226
213
            r[o.name] = o
227
214
        return r
228
215
 
229
 
    def _setup_outf(self):
230
 
        """Return a file linked to stdout, which has proper encoding."""
231
 
        assert self.encoding_type in ['strict', 'exact', 'replace']
232
 
 
233
 
        # Originally I was using self.stdout, but that looks
234
 
        # *way* too much like sys.stdout
235
 
        if self.encoding_type == 'exact':
236
 
            self.outf = sys.stdout
237
 
            return
238
 
 
239
 
        output_encoding = bzrlib.osutils.get_terminal_encoding()
240
 
 
241
 
        # use 'replace' so that we don't abort if trying to write out
242
 
        # in e.g. the default C locale.
243
 
        self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
244
 
        # For whatever reason codecs.getwriter() does not advertise its encoding
245
 
        # it just returns the encoding of the wrapped file, which is completely
246
 
        # bogus. So set the attribute, so we can find the correct encoding later.
247
 
        self.outf.encoding = output_encoding
248
 
 
249
216
    @deprecated_method(zero_eight)
250
217
    def run_argv(self, argv):
251
218
        """Parse command line and run.
265
232
        allowed_names = self.options().keys()
266
233
        for oname in opts:
267
234
            if oname not in allowed_names:
268
 
                raise BzrOptionError("option '--%s' is not allowed for"
269
 
                                " command %r" % (oname, self.name()))
 
235
                raise BzrCommandError("option '--%s' is not allowed for"
 
236
                                      " command %r" % (oname, self.name()))
270
237
        # mix arguments and options into one dictionary
271
238
        cmdargs = _match_argform(self.name(), self.takes_args, args)
272
239
        cmdopts = {}
276
243
        all_cmd_args = cmdargs.copy()
277
244
        all_cmd_args.update(cmdopts)
278
245
 
279
 
        self._setup_outf()
280
 
 
281
246
        return self.run(**all_cmd_args)
282
247
    
283
248
    def run(self):
303
268
    def name(self):
304
269
        return _unsquish_command_name(self.__class__.__name__)
305
270
 
306
 
    def plugin_name(self):
307
 
        """Get the name of the plugin that provides this command.
308
 
 
309
 
        :return: The name of the plugin or None if the command is builtin.
310
 
        """
311
 
        mod_parts = self.__module__.split('.')
312
 
        if len(mod_parts) >= 3 and mod_parts[1] == 'plugins':
313
 
            return mod_parts[2]
314
 
        else:
315
 
            return None
316
 
 
317
271
 
318
272
def parse_spec(spec):
319
273
    """
368
322
            if argsover:
369
323
                args.append(a)
370
324
                continue
371
 
            elif a == '-':
372
 
                args.append(a)
373
 
                continue
374
325
            elif a == '--':
375
326
                # We've received a standalone -- No more flags
376
327
                argsover = True
386
337
                    else:
387
338
                        optname = a[2:]
388
339
                    if optname not in cmd_options:
389
 
                        raise BzrCommandError('unknown option "%s"' % a)
 
340
                        raise BzrOptionError('unknown long option %r for'
 
341
                                             ' command %s' % 
 
342
                                             (a, command.name()))
390
343
                else:
391
344
                    shortopt = a[1:]
392
345
                    if shortopt in Option.SHORT_OPTIONS:
401
354
                        if shortopt not in Option.SHORT_OPTIONS:
402
355
                            # We didn't find the multi-character name, and we
403
356
                            # didn't find the single char name
404
 
                            raise BzrCommandError('unknown option "%s"' % a)
 
357
                            raise BzrError('unknown short option %r' % a)
405
358
                        optname = Option.SHORT_OPTIONS[shortopt].name
406
359
 
407
360
                        if a[2:]:
418
371
                                # This option takes an argument, so pack it
419
372
                                # into the array
420
373
                                optarg = a[2:]
 
374
                
421
375
                    if optname not in cmd_options:
422
 
                        raise BzrCommandError('unknown option "%s"' % shortopt)
 
376
                        raise BzrOptionError('unknown short option %r for'
 
377
                                             ' command %s' % 
 
378
                                             (shortopt, command.name()))
423
379
                if optname in opts:
424
380
                    # XXX: Do we ever want to support this, e.g. for -r?
425
381
                    if proc_aliasarg:
426
 
                        raise BzrCommandError('repeated option %r' % a)
 
382
                        raise BzrError('repeated option %r' % a)
427
383
                    elif optname in alias_opts:
428
384
                        # Replace what's in the alias with what's in the real
429
385
                        # argument
432
388
                        proc_argv.insert(0, a)
433
389
                        continue
434
390
                    else:
435
 
                        raise BzrCommandError('repeated option %r' % a)
 
391
                        raise BzrError('repeated option %r' % a)
436
392
                    
437
393
                option_obj = cmd_options[optname]
438
394
                optargfn = option_obj.type
439
395
                if optargfn:
440
396
                    if optarg == None:
441
397
                        if not proc_argv:
442
 
                            raise BzrCommandError('option %r needs an argument' % a)
 
398
                            raise BzrError('option %r needs an argument' % a)
443
399
                        else:
444
400
                            optarg = proc_argv.pop(0)
445
401
                    opts[optname] = optargfn(optarg)
447
403
                        alias_opts[optname] = optargfn(optarg)
448
404
                else:
449
405
                    if optarg != None:
450
 
                        raise BzrCommandError('option %r takes no argument' % optname)
 
406
                        raise BzrError('option %r takes no argument' % optname)
451
407
                    opts[optname] = True
452
408
                    if proc_aliasarg:
453
409
                        alias_opts[optname] = True
484
440
                raise BzrCommandError("command %r needs one or more %s"
485
441
                        % (cmd, argname.upper()))
486
442
            argdict[argname + '_list'] = args[:-1]
487
 
            args[:-1] = []
 
443
            args[:-1] = []                
488
444
        else:
489
445
            # just a plain arg
490
446
            argname = ap
556
512
    
557
513
    argv
558
514
       The command-line arguments, without the program name from argv[0]
559
 
       These should already be decoded. All library/test code calling
560
 
       run_bzr should be passing valid strings (don't need decoding).
561
515
    
562
516
    Returns a command status or raises an exception.
563
517
 
580
534
    --lsprof
581
535
        Run under the Python lsprof profiler.
582
536
    """
583
 
    argv = list(argv)
 
537
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
584
538
 
585
539
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
586
540
                opt_no_aliases = False
599
553
        elif a == '--lsprof':
600
554
            opt_lsprof = True
601
555
        elif a == '--lsprof-file':
602
 
            opt_lsprof = True
603
556
            opt_lsprof_file = argv[i + 1]
604
557
            i += 1
605
558
        elif a == '--no-plugins':
673
626
            if not hasattr(e, 'errno'):
674
627
                raise
675
628
            if e.errno != errno.EPIPE:
676
 
                # Win32 raises IOError with errno=0 on a broken pipe
677
 
                if sys.platform != 'win32' or e.errno != 0:
678
 
                    raise
 
629
                raise
679
630
            pass
680
631
        except KeyboardInterrupt:
681
632
            pass
685
636
def main(argv):
686
637
    import bzrlib.ui
687
638
    from bzrlib.ui.text import TextUIFactory
 
639
    ## bzrlib.trace.enable_default_logging()
 
640
    bzrlib.trace.log_startup(argv)
688
641
    bzrlib.ui.ui_factory = TextUIFactory()
689
 
    argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
690
 
    ret = run_bzr_catch_errors(argv)
 
642
    ret = run_bzr_catch_errors(argv[1:])
691
643
    mutter("return code %d", ret)
692
644
    return ret
693
645
 
694
646
 
695
647
def run_bzr_catch_errors(argv):
696
648
    try:
697
 
        return run_bzr(argv)
698
 
        # do this here inside the exception wrappers to catch EPIPE
699
 
        sys.stdout.flush()
 
649
        try:
 
650
            return run_bzr(argv)
 
651
        finally:
 
652
            # do this here inside the exception wrappers to catch EPIPE
 
653
            sys.stdout.flush()
700
654
    except Exception, e:
701
655
        # used to handle AssertionError and KeyboardInterrupt
702
656
        # specially here, but hopefully they're handled ok by the logger now
703
 
        bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
704
 
        if os.environ.get('BZR_PDB'):
705
 
            print '**** entering debugger'
706
 
            import pdb
707
 
            pdb.post_mortem(sys.exc_traceback)
708
 
        return 3
 
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
709
670
 
710
671
if __name__ == '__main__':
711
672
    sys.exit(main(sys.argv))