~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Martin Pool
  • Date: 2006-06-20 07:55:43 UTC
  • mfrom: (1798 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1799.
  • Revision ID: mbp@sourcefrog.net-20060620075543-b10f6575d4a4fa32
[merge] bzr.dev

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
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)
42
43
from bzrlib.option import Option
 
44
import bzrlib.osutils
43
45
from bzrlib.revisionspec import RevisionSpec
44
 
from bzrlib.symbol_versioning import *
45
 
import bzrlib.trace
 
46
from bzrlib.symbol_versioning import (deprecated_method, zero_eight)
 
47
from bzrlib import trace
46
48
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
47
49
 
48
50
plugin_cmds = {}
145
147
    if cmd_obj:
146
148
        return cmd_obj
147
149
 
148
 
    raise BzrCommandError("unknown command %r" % cmd_name)
 
150
    raise BzrCommandError('unknown command "%s"' % cmd_name)
149
151
 
150
152
 
151
153
class Command(object):
189
191
    hidden
190
192
        If true, this command isn't advertised.  This is typically
191
193
        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
 
192
204
    """
193
205
    aliases = []
194
206
    takes_args = []
195
207
    takes_options = []
 
208
    encoding_type = 'strict'
196
209
 
197
210
    hidden = False
198
211
    
213
226
            r[o.name] = o
214
227
        return r
215
228
 
 
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
 
216
249
    @deprecated_method(zero_eight)
217
250
    def run_argv(self, argv):
218
251
        """Parse command line and run.
232
265
        allowed_names = self.options().keys()
233
266
        for oname in opts:
234
267
            if oname not in allowed_names:
235
 
                raise BzrCommandError("option '--%s' is not allowed for"
236
 
                                      " command %r" % (oname, self.name()))
 
268
                raise BzrOptionError("option '--%s' is not allowed for"
 
269
                                " command %r" % (oname, self.name()))
237
270
        # mix arguments and options into one dictionary
238
271
        cmdargs = _match_argform(self.name(), self.takes_args, args)
239
272
        cmdopts = {}
243
276
        all_cmd_args = cmdargs.copy()
244
277
        all_cmd_args.update(cmdopts)
245
278
 
 
279
        self._setup_outf()
 
280
 
246
281
        return self.run(**all_cmd_args)
247
282
    
248
283
    def run(self):
268
303
    def name(self):
269
304
        return _unsquish_command_name(self.__class__.__name__)
270
305
 
 
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
 
271
317
 
272
318
def parse_spec(spec):
273
319
    """
337
383
                    else:
338
384
                        optname = a[2:]
339
385
                    if optname not in cmd_options:
340
 
                        raise BzrOptionError('unknown long option %r for'
341
 
                                             ' command %s' % 
342
 
                                             (a, command.name()))
 
386
                        raise BzrCommandError('unknown option "%s"' % a)
343
387
                else:
344
388
                    shortopt = a[1:]
345
389
                    if shortopt in Option.SHORT_OPTIONS:
354
398
                        if shortopt not in Option.SHORT_OPTIONS:
355
399
                            # We didn't find the multi-character name, and we
356
400
                            # didn't find the single char name
357
 
                            raise BzrError('unknown short option %r' % a)
 
401
                            raise BzrCommandError('unknown option "%s"' % a)
358
402
                        optname = Option.SHORT_OPTIONS[shortopt].name
359
403
 
360
404
                        if a[2:]:
371
415
                                # This option takes an argument, so pack it
372
416
                                # into the array
373
417
                                optarg = a[2:]
374
 
                
375
418
                    if optname not in cmd_options:
376
 
                        raise BzrOptionError('unknown short option %r for'
377
 
                                             ' command %s' % 
378
 
                                             (shortopt, command.name()))
 
419
                        raise BzrCommandError('unknown option "%s"' % shortopt)
379
420
                if optname in opts:
380
421
                    # XXX: Do we ever want to support this, e.g. for -r?
381
422
                    if proc_aliasarg:
382
 
                        raise BzrError('repeated option %r' % a)
 
423
                        raise BzrCommandError('repeated option %r' % a)
383
424
                    elif optname in alias_opts:
384
425
                        # Replace what's in the alias with what's in the real
385
426
                        # argument
388
429
                        proc_argv.insert(0, a)
389
430
                        continue
390
431
                    else:
391
 
                        raise BzrError('repeated option %r' % a)
 
432
                        raise BzrCommandError('repeated option %r' % a)
392
433
                    
393
434
                option_obj = cmd_options[optname]
394
435
                optargfn = option_obj.type
395
436
                if optargfn:
396
437
                    if optarg == None:
397
438
                        if not proc_argv:
398
 
                            raise BzrError('option %r needs an argument' % a)
 
439
                            raise BzrCommandError('option %r needs an argument' % a)
399
440
                        else:
400
441
                            optarg = proc_argv.pop(0)
401
442
                    opts[optname] = optargfn(optarg)
403
444
                        alias_opts[optname] = optargfn(optarg)
404
445
                else:
405
446
                    if optarg != None:
406
 
                        raise BzrError('option %r takes no argument' % optname)
 
447
                        raise BzrCommandError('option %r takes no argument' % optname)
407
448
                    opts[optname] = True
408
449
                    if proc_aliasarg:
409
450
                        alias_opts[optname] = True
440
481
                raise BzrCommandError("command %r needs one or more %s"
441
482
                        % (cmd, argname.upper()))
442
483
            argdict[argname + '_list'] = args[:-1]
443
 
            args[:-1] = []                
 
484
            args[:-1] = []
444
485
        else:
445
486
            # just a plain arg
446
487
            argname = ap
512
553
    
513
554
    argv
514
555
       The command-line arguments, without the program name from argv[0]
 
556
       These should already be decoded. All library/test code calling
 
557
       run_bzr should be passing valid strings (don't need decoding).
515
558
    
516
559
    Returns a command status or raises an exception.
517
560
 
534
577
    --lsprof
535
578
        Run under the Python lsprof profiler.
536
579
    """
537
 
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
 
580
    argv = list(argv)
538
581
 
539
582
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
540
583
                opt_no_aliases = False
636
679
def main(argv):
637
680
    import bzrlib.ui
638
681
    from bzrlib.ui.text import TextUIFactory
639
 
    ## bzrlib.trace.enable_default_logging()
640
 
    bzrlib.trace.log_startup(argv)
641
682
    bzrlib.ui.ui_factory = TextUIFactory()
642
 
    ret = run_bzr_catch_errors(argv[1:])
 
683
    argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
 
684
    ret = run_bzr_catch_errors(argv)
643
685
    mutter("return code %d", ret)
644
686
    return ret
645
687
 
654
696
    except Exception, e:
655
697
        # used to handle AssertionError and KeyboardInterrupt
656
698
        # 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
 
699
        bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
 
700
        if os.environ.get('BZR_PDB'):
 
701
            print '**** entering debugger'
 
702
            import pdb
 
703
            pdb.post_mortem(sys.exc_traceback)
 
704
        return 3
670
705
 
671
706
if __name__ == '__main__':
672
707
    sys.exit(main(sys.argv))