~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

Don't encode unicode messages to UTF-8 in mutter() (the stream writer does it).

Use a codec wrapped log file in tests to match the real environment.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2004, 2005 by Canonical Ltd
 
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
# TODO: probably should say which arguments are candidates for glob
19
19
# expansion on windows and do that at the command level.
20
20
 
 
21
# TODO: Help messages for options.
 
22
 
21
23
# TODO: Define arguments by objects, rather than just using names.
22
24
# Those objects can specify the expected type of the argument, which
23
 
# would help with validation and shell completion.  They could also provide
24
 
# help/explanation for that argument in a structured way.
25
 
 
26
 
# TODO: Specific "examples" property on commands for consistent formatting.
 
25
# would help with validation and shell completion.
27
26
 
28
27
# TODO: "--profile=cum", to change sort order.  Is there any value in leaving
29
28
# the profile output behind so it can be interactively examined?
30
29
 
 
30
import sys
31
31
import os
32
 
import sys
33
 
 
34
 
from bzrlib.lazy_import import lazy_import
35
 
lazy_import(globals(), """
36
 
import codecs
 
32
from warnings import warn
 
33
from inspect import getdoc
37
34
import errno
38
 
from warnings import warn
39
35
 
40
36
import bzrlib
41
 
from bzrlib import (
42
 
    debug,
43
 
    errors,
44
 
    option,
45
 
    osutils,
46
 
    trace,
47
 
    )
48
 
""")
49
 
 
50
 
from bzrlib.symbol_versioning import (
51
 
    deprecated_function,
52
 
    deprecated_method,
53
 
    zero_eight,
54
 
    zero_eleven,
55
 
    )
56
 
# Compatibility
 
37
import bzrlib.trace
 
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)
 
44
from bzrlib.revisionspec import RevisionSpec
 
45
from bzrlib import BZRDIR
57
46
from bzrlib.option import Option
58
47
 
59
 
 
60
48
plugin_cmds = {}
61
49
 
62
50
 
63
51
def register_command(cmd, decorate=False):
64
 
    """Utility function to help register a command
65
 
 
66
 
    :param cmd: Command subclass to register
67
 
    :param decorate: If true, allow overriding an existing command
68
 
        of the same name; the old command is returned by this function.
69
 
        Otherwise it is an error to try to override an existing command.
70
 
    """
 
52
    "Utility function to help register a command"
71
53
    global plugin_cmds
72
54
    k = cmd.__name__
73
55
    if k.startswith("cmd_"):
74
56
        k_unsquished = _unsquish_command_name(k)
75
57
    else:
76
58
        k_unsquished = k
77
 
    if k_unsquished not in plugin_cmds:
 
59
    if not plugin_cmds.has_key(k_unsquished):
78
60
        plugin_cmds[k_unsquished] = cmd
79
 
        ## trace.mutter('registered plugin command %s', k_unsquished)
 
61
        mutter('registered plugin command %s', k_unsquished)      
80
62
        if decorate and k_unsquished in builtin_command_names():
81
63
            return _builtin_commands()[k_unsquished]
82
64
    elif decorate:
84
66
        plugin_cmds[k_unsquished] = cmd
85
67
        return result
86
68
    else:
87
 
        trace.log_error('Two plugins defined the same command: %r' % k)
88
 
        trace.log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
 
69
        log_error('Two plugins defined the same command: %r' % k)
 
70
        log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
89
71
 
90
72
 
91
73
def _squish_command_name(cmd):
103
85
    builtins = bzrlib.builtins.__dict__
104
86
    for name in builtins:
105
87
        if name.startswith("cmd_"):
106
 
            real_name = _unsquish_command_name(name)
 
88
            real_name = _unsquish_command_name(name)        
107
89
            r[real_name] = builtins[name]
108
90
    return r
 
91
 
109
92
            
110
93
 
111
94
def builtin_command_names():
137
120
    plugins_override
138
121
        If true, plugin commands can override builtins.
139
122
    """
140
 
    try:
141
 
        return _get_cmd_object(cmd_name, plugins_override)
142
 
    except KeyError:
143
 
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
144
 
 
145
 
 
146
 
def _get_cmd_object(cmd_name, plugins_override=True):
147
 
    """Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
148
123
    from bzrlib.externalcommand import ExternalCommand
149
124
 
150
 
    # We want only 'ascii' command names, but the user may have typed
151
 
    # in a Unicode name. In that case, they should just get a
152
 
    # 'command not found' error later.
153
 
    # In the future, we may actually support Unicode command names.
 
125
    cmd_name = str(cmd_name)            # not unicode
154
126
 
155
127
    # first look up this command under the specified name
156
128
    cmds = _get_cmd_dict(plugins_override=plugins_override)
167
139
    cmd_obj = ExternalCommand.find_command(cmd_name)
168
140
    if cmd_obj:
169
141
        return cmd_obj
170
 
    raise KeyError
 
142
 
 
143
    raise BzrCommandError("unknown command %r" % cmd_name)
171
144
 
172
145
 
173
146
class Command(object):
195
168
        List of argument forms, marked with whether they are optional,
196
169
        repeated, etc.
197
170
 
198
 
                Examples:
199
 
 
200
 
                ['to_location', 'from_branch?', 'file*']
201
 
 
202
 
                'to_location' is required
203
 
                'from_branch' is optional
204
 
                'file' can be specified 0 or more times
 
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
205
178
 
206
179
    takes_options
207
180
        List of options that may be given for this command.  These can
211
184
    hidden
212
185
        If true, this command isn't advertised.  This is typically
213
186
        for commands intended for expert users.
214
 
 
215
 
    encoding_type
216
 
        Command objects will get a 'outf' attribute, which has been
217
 
        setup to properly handle encoding of unicode strings.
218
 
        encoding_type determines what will happen when characters cannot
219
 
        be encoded
220
 
            strict - abort if we cannot decode
221
 
            replace - put in a bogus character (typically '?')
222
 
            exact - do not encode sys.stdout
223
 
 
224
 
            NOTE: by default on Windows, sys.stdout is opened as a text
225
 
            stream, therefore LF line-endings are converted to CRLF.
226
 
            When a command uses encoding_type = 'exact', then
227
 
            sys.stdout is forced to be a binary stream, and line-endings
228
 
            will not mangled.
229
 
 
230
187
    """
231
188
    aliases = []
232
189
    takes_args = []
233
190
    takes_options = []
234
 
    encoding_type = 'strict'
235
191
 
236
192
    hidden = False
237
193
    
240
196
        if self.__doc__ == Command.__doc__:
241
197
            warn("No help message set for %r" % self)
242
198
 
243
 
    def _usage(self):
244
 
        """Return single-line grammar for this command.
245
 
 
246
 
        Only describes arguments, not options.
247
 
        """
248
 
        s = 'bzr ' + self.name() + ' '
249
 
        for aname in self.takes_args:
250
 
            aname = aname.upper()
251
 
            if aname[-1] in ['$', '+']:
252
 
                aname = aname[:-1] + '...'
253
 
            elif aname[-1] == '?':
254
 
                aname = '[' + aname[:-1] + ']'
255
 
            elif aname[-1] == '*':
256
 
                aname = '[' + aname[:-1] + '...]'
257
 
            s += aname + ' '
258
 
                
259
 
        assert s[-1] == ' '
260
 
        s = s[:-1]
261
 
        return s
262
 
 
263
 
    def get_help_text(self, additional_see_also=None):
264
 
        """Return a text string with help for this command.
265
 
        
266
 
        :param additional_see_also: Additional help topics to be
267
 
            cross-referenced.
268
 
        """
269
 
        doc = self.help()
270
 
        if doc is None:
271
 
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
272
 
 
273
 
        result = ""
274
 
        result += 'usage: %s\n' % self._usage()
275
 
 
276
 
        if self.aliases:
277
 
            result += 'aliases: '
278
 
            result += ', '.join(self.aliases) + '\n'
279
 
 
280
 
        result += '\n'
281
 
 
282
 
        plugin_name = self.plugin_name()
283
 
        if plugin_name is not None:
284
 
            result += '(From plugin "%s")' % plugin_name
285
 
            result += '\n\n'
286
 
 
287
 
        result += doc
288
 
        if result[-1] != '\n':
289
 
            result += '\n'
290
 
        result += '\n'
291
 
        result += option.get_optparser(self.options()).format_option_help()
292
 
        see_also = self.get_see_also(additional_see_also)
293
 
        if see_also:
294
 
            result += '\nSee also: '
295
 
            result += ', '.join(see_also)
296
 
            result += '\n'
297
 
        return result
298
 
 
299
 
    def get_help_topic(self):
300
 
        """Return the commands help topic - its name."""
301
 
        return self.name()
302
 
 
303
 
    def get_see_also(self, additional_terms=None):
304
 
        """Return a list of help topics that are related to this ommand.
305
 
        
306
 
        The list is derived from the content of the _see_also attribute. Any
307
 
        duplicates are removed and the result is in lexical order.
308
 
        :param additional_terms: Additional help topics to cross-reference.
309
 
        :return: A list of help topics.
310
 
        """
311
 
        see_also = set(getattr(self, '_see_also', []))
312
 
        if additional_terms:
313
 
            see_also.update(additional_terms)
314
 
        return sorted(see_also)
315
 
 
316
199
    def options(self):
317
200
        """Return dict of valid options for this command.
318
201
 
319
202
        Maps from long option name to option object."""
320
203
        r = dict()
321
 
        r['help'] = option.Option.OPTIONS['help']
 
204
        r['help'] = Option.OPTIONS['help']
322
205
        for o in self.takes_options:
323
 
            if isinstance(o, basestring):
324
 
                o = option.Option.OPTIONS[o]
 
206
            if not isinstance(o, Option):
 
207
                o = Option.OPTIONS[o]
325
208
            r[o.name] = o
326
209
        return r
327
210
 
328
 
    def _setup_outf(self):
329
 
        """Return a file linked to stdout, which has proper encoding."""
330
 
        assert self.encoding_type in ['strict', 'exact', 'replace']
331
 
 
332
 
        # Originally I was using self.stdout, but that looks
333
 
        # *way* too much like sys.stdout
334
 
        if self.encoding_type == 'exact':
335
 
            # force sys.stdout to be binary stream on win32
336
 
            if sys.platform == 'win32':
337
 
                fileno = getattr(sys.stdout, 'fileno', None)
338
 
                if fileno:
339
 
                    import msvcrt
340
 
                    msvcrt.setmode(fileno(), os.O_BINARY)
341
 
            self.outf = sys.stdout
342
 
            return
343
 
 
344
 
        output_encoding = osutils.get_terminal_encoding()
345
 
 
346
 
        # use 'replace' so that we don't abort if trying to write out
347
 
        # in e.g. the default C locale.
348
 
        self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
349
 
        # For whatever reason codecs.getwriter() does not advertise its encoding
350
 
        # it just returns the encoding of the wrapped file, which is completely
351
 
        # bogus. So set the attribute, so we can find the correct encoding later.
352
 
        self.outf.encoding = output_encoding
353
 
 
354
 
    def run_argv_aliases(self, argv, alias_argv=None):
355
 
        """Parse the command line and run with extra aliases in alias_argv."""
356
 
        if argv is None:
357
 
            warn("Passing None for [] is deprecated from bzrlib 0.10",
358
 
                 DeprecationWarning, stacklevel=2)
359
 
            argv = []
360
 
        args, opts = parse_args(self, argv, alias_argv)
 
211
    def run_argv(self, argv):
 
212
        """Parse command line and run."""
 
213
        args, opts = parse_args(self, argv)
361
214
        if 'help' in opts:  # e.g. bzr add --help
362
 
            sys.stdout.write(self.get_help_text())
 
215
            from bzrlib.help import help_on_command
 
216
            help_on_command(self.name())
363
217
            return 0
 
218
        # XXX: This should be handled by the parser
 
219
        allowed_names = self.options().keys()
 
220
        for oname in opts:
 
221
            if oname not in allowed_names:
 
222
                raise BzrCommandError("option '--%s' is not allowed for command %r"
 
223
                                      % (oname, self.name()))
364
224
        # mix arguments and options into one dictionary
365
225
        cmdargs = _match_argform(self.name(), self.takes_args, args)
366
226
        cmdopts = {}
370
230
        all_cmd_args = cmdargs.copy()
371
231
        all_cmd_args.update(cmdopts)
372
232
 
373
 
        self._setup_outf()
374
 
 
375
233
        return self.run(**all_cmd_args)
376
234
    
377
235
    def run(self):
384
242
        shell error code if not.  It's OK for this method to allow
385
243
        an exception to raise up.
386
244
        """
387
 
        raise NotImplementedError('no implementation of command %r'
388
 
                                  % self.name())
 
245
        raise NotImplementedError()
 
246
 
389
247
 
390
248
    def help(self):
391
249
        """Return help message for this class."""
392
 
        from inspect import getdoc
393
250
        if self.__doc__ is Command.__doc__:
394
251
            return None
395
252
        return getdoc(self)
397
254
    def name(self):
398
255
        return _unsquish_command_name(self.__class__.__name__)
399
256
 
400
 
    def plugin_name(self):
401
 
        """Get the name of the plugin that provides this command.
402
 
 
403
 
        :return: The name of the plugin or None if the command is builtin.
404
 
        """
405
 
        mod_parts = self.__module__.split('.')
406
 
        if len(mod_parts) >= 3 and mod_parts[1] == 'plugins':
407
 
            return mod_parts[2]
408
 
        else:
409
 
            return None
410
 
 
411
 
 
412
 
# Technically, this function hasn't been use in a *really* long time
413
 
# but we are only deprecating it now.
414
 
@deprecated_function(zero_eleven)
 
257
 
415
258
def parse_spec(spec):
416
259
    """
417
260
    >>> parse_spec(None)
443
286
        parsed = [spec, None]
444
287
    return parsed
445
288
 
446
 
def parse_args(command, argv, alias_argv=None):
 
289
def parse_args(command, argv):
447
290
    """Parse command line.
448
291
    
449
292
    Arguments and options are parsed at this level before being passed
451
294
    lookup table, something about the available options, what optargs
452
295
    they take, and which commands will accept them.
453
296
    """
454
 
    # TODO: make it a method of the Command?
455
 
    parser = option.get_optparser(command.options())
456
 
    if alias_argv is not None:
457
 
        args = alias_argv + argv
458
 
    else:
459
 
        args = argv
460
 
 
461
 
    options, args = parser.parse_args(args)
462
 
    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
463
 
                 v is not option.OptionParser.DEFAULT_VALUE])
 
297
    # TODO: chop up this beast; make it a method of the Command
 
298
    args = []
 
299
    opts = {}
 
300
 
 
301
    cmd_options = command.options()
 
302
    argsover = False
 
303
    while argv:
 
304
        a = argv.pop(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] == '-':
 
313
            # option names must not be unicode
 
314
            a = str(a)
 
315
            optarg = None
 
316
            if a[1] == '-':
 
317
                mutter("  got option %r", a)
 
318
                if '=' in a:
 
319
                    optname, optarg = a[2:].split('=', 1)
 
320
                else:
 
321
                    optname = a[2:]
 
322
                if optname not in cmd_options:
 
323
                    raise BzrOptionError('unknown long option %r for command %s'
 
324
                        % (a, command.name()))
 
325
            else:
 
326
                shortopt = a[1:]
 
327
                if shortopt in Option.SHORT_OPTIONS:
 
328
                    # Multi-character options must have a space to delimit
 
329
                    # their value
 
330
                    # ^^^ what does this mean? mbp 20051014
 
331
                    optname = Option.SHORT_OPTIONS[shortopt].name
 
332
                else:
 
333
                    # Single character short options, can be chained,
 
334
                    # and have their value appended to their name
 
335
                    shortopt = a[1:2]
 
336
                    if shortopt not in Option.SHORT_OPTIONS:
 
337
                        # We didn't find the multi-character name, and we
 
338
                        # didn't find the single char name
 
339
                        raise BzrError('unknown short option %r' % a)
 
340
                    optname = Option.SHORT_OPTIONS[shortopt].name
 
341
 
 
342
                    if a[2:]:
 
343
                        # There are extra things on this option
 
344
                        # see if it is the value, or if it is another
 
345
                        # short option
 
346
                        optargfn = Option.OPTIONS[optname].type
 
347
                        if optargfn is None:
 
348
                            # This option does not take an argument, so the
 
349
                            # next entry is another short option, pack it back
 
350
                            # into the list
 
351
                            argv.insert(0, '-' + a[2:])
 
352
                        else:
 
353
                            # This option takes an argument, so pack it
 
354
                            # into the array
 
355
                            optarg = a[2:]
 
356
            
 
357
                if optname not in cmd_options:
 
358
                    raise BzrOptionError('unknown short option %r for command'
 
359
                        ' %s' % (shortopt, command.name()))
 
360
            if optname in opts:
 
361
                # XXX: Do we ever want to support this, e.g. for -r?
 
362
                raise BzrError('repeated option %r' % a)
 
363
                
 
364
            option_obj = cmd_options[optname]
 
365
            optargfn = option_obj.type
 
366
            if optargfn:
 
367
                if optarg == None:
 
368
                    if not argv:
 
369
                        raise BzrError('option %r needs an argument' % a)
 
370
                    else:
 
371
                        optarg = argv.pop(0)
 
372
                opts[optname] = optargfn(optarg)
 
373
            else:
 
374
                if optarg != None:
 
375
                    raise BzrError('option %r takes no argument' % optname)
 
376
                opts[optname] = True
 
377
        else:
 
378
            args.append(a)
464
379
    return args, opts
465
380
 
466
381
 
481
396
                argdict[argname + '_list'] = None
482
397
        elif ap[-1] == '+':
483
398
            if not args:
484
 
                raise errors.BzrCommandError("command %r needs one or more %s"
485
 
                                             % (cmd, argname.upper()))
 
399
                raise BzrCommandError("command %r needs one or more %s"
 
400
                        % (cmd, argname.upper()))
486
401
            else:
487
402
                argdict[argname + '_list'] = args[:]
488
403
                args = []
489
404
        elif ap[-1] == '$': # all but one
490
405
            if len(args) < 2:
491
 
                raise errors.BzrCommandError("command %r needs one or more %s"
492
 
                                             % (cmd, argname.upper()))
 
406
                raise BzrCommandError("command %r needs one or more %s"
 
407
                        % (cmd, argname.upper()))
493
408
            argdict[argname + '_list'] = args[:-1]
494
 
            args[:-1] = []
 
409
            args[:-1] = []                
495
410
        else:
496
411
            # just a plain arg
497
412
            argname = ap
498
413
            if not args:
499
 
                raise errors.BzrCommandError("command %r requires argument %s"
500
 
                               % (cmd, argname.upper()))
 
414
                raise BzrCommandError("command %r requires argument %s"
 
415
                        % (cmd, argname.upper()))
501
416
            else:
502
417
                argdict[argname] = args.pop(0)
503
418
            
504
419
    if args:
505
 
        raise errors.BzrCommandError("extra argument to command %s: %s"
506
 
                                     % (cmd, args[0]))
 
420
        raise BzrCommandError("extra argument to command %s: %s"
 
421
                              % (cmd, args[0]))
507
422
 
508
423
    return argdict
509
424
 
532
447
        os.remove(pfname)
533
448
 
534
449
 
535
 
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
536
 
    from bzrlib.lsprof import profile
537
 
    import cPickle
538
 
    ret, stats = profile(the_callable, *args, **kwargs)
539
 
    stats.sort()
540
 
    if filename is None:
541
 
        stats.pprint()
542
 
    else:
543
 
        stats.freeze()
544
 
        cPickle.dump(stats, open(filename, 'w'), 2)
545
 
        print 'Profile data written to %r.' % filename
546
 
    return ret
547
 
 
548
 
 
549
 
def get_alias(cmd, config=None):
550
 
    """Return an expanded alias, or None if no alias exists.
551
 
 
552
 
    cmd
553
 
        Command to be checked for an alias.
554
 
    config
555
 
        Used to specify an alternative config to use,
556
 
        which is especially useful for testing.
557
 
        If it is unspecified, the global config will be used.
558
 
    """
559
 
    if config is None:
560
 
        import bzrlib.config
561
 
        config = bzrlib.config.GlobalConfig()
562
 
    alias = config.get_alias(cmd)
563
 
    if (alias):
564
 
        import shlex
565
 
        return [a.decode('utf-8') for a in shlex.split(alias.encode('utf-8'))]
566
 
    return None
567
 
 
568
 
 
569
450
def run_bzr(argv):
570
451
    """Execute a command.
571
452
 
574
455
    
575
456
    argv
576
457
       The command-line arguments, without the program name from argv[0]
577
 
       These should already be decoded. All library/test code calling
578
 
       run_bzr should be passing valid strings (don't need decoding).
579
458
    
580
459
    Returns a command status or raises an exception.
581
460
 
585
464
    --no-plugins
586
465
        Do not load plugin modules at all
587
466
 
588
 
    --no-aliases
589
 
        Do not allow aliases
590
 
 
591
467
    --builtin
592
468
        Only use builtin commands.  (Plugins are still allowed to change
593
469
        other behaviour.)
594
470
 
595
471
    --profile
596
 
        Run under the Python hotshot profiler.
597
 
 
598
 
    --lsprof
599
 
        Run under the Python lsprof profiler.
 
472
        Run under the Python profiler.
600
473
    """
601
 
    argv = list(argv)
602
 
    trace.mutter("bzr arguments: %r", argv)
 
474
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
603
475
 
604
 
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
605
 
                opt_no_aliases = False
606
 
    opt_lsprof_file = None
 
476
    opt_profile = opt_no_plugins = opt_builtin = False
607
477
 
608
478
    # --no-plugins is handled specially at a very early stage. We need
609
479
    # to load plugins before doing other command parsing so that they
610
480
    # can override commands, but this needs to happen first.
611
481
 
612
 
    argv_copy = []
613
 
    i = 0
614
 
    while i < len(argv):
615
 
        a = argv[i]
 
482
    for a in argv:
616
483
        if a == '--profile':
617
484
            opt_profile = True
618
 
        elif a == '--lsprof':
619
 
            opt_lsprof = True
620
 
        elif a == '--lsprof-file':
621
 
            opt_lsprof = True
622
 
            opt_lsprof_file = argv[i + 1]
623
 
            i += 1
624
485
        elif a == '--no-plugins':
625
486
            opt_no_plugins = True
626
 
        elif a == '--no-aliases':
627
 
            opt_no_aliases = True
628
487
        elif a == '--builtin':
629
488
            opt_builtin = True
630
489
        elif a in ('--quiet', '-q'):
631
 
            trace.be_quiet()
632
 
        elif a.startswith('-D'):
633
 
            debug.debug_flags.add(a[2:])
 
490
            be_quiet()
634
491
        else:
635
 
            argv_copy.append(a)
636
 
        i += 1
 
492
            continue
 
493
        argv.remove(a)
637
494
 
638
 
    argv = argv_copy
639
 
    if (not argv):
640
 
        from bzrlib.builtins import cmd_help
641
 
        cmd_help().run_argv_aliases([])
 
495
    if (not argv) or (argv[0] == '--help'):
 
496
        from bzrlib.help import help
 
497
        if len(argv) > 1:
 
498
            help(argv[1])
 
499
        else:
 
500
            help()
642
501
        return 0
643
502
 
644
503
    if argv[0] == '--version':
645
 
        from bzrlib.version import show_version
 
504
        from bzrlib.builtins import show_version
646
505
        show_version()
647
506
        return 0
648
507
        
649
508
    if not opt_no_plugins:
650
509
        from bzrlib.plugin import load_plugins
651
510
        load_plugins()
652
 
    else:
653
 
        from bzrlib.plugin import disable_plugins
654
 
        disable_plugins()
655
 
 
656
 
    alias_argv = None
657
 
 
658
 
    if not opt_no_aliases:
659
 
        alias_argv = get_alias(argv[0])
660
 
        if alias_argv:
661
 
            alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
662
 
            argv[0] = alias_argv.pop(0)
663
 
 
664
 
    cmd = argv.pop(0)
665
 
    # We want only 'ascii' command names, but the user may have typed
666
 
    # in a Unicode name. In that case, they should just get a
667
 
    # 'command not found' error later.
 
511
 
 
512
    cmd = str(argv.pop(0))
668
513
 
669
514
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
670
 
    run = cmd_obj.run_argv_aliases
671
 
    run_argv = [argv, alias_argv]
672
515
 
673
516
    try:
674
 
        if opt_lsprof:
675
 
            ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
676
 
        elif opt_profile:
677
 
            ret = apply_profiled(run, *run_argv)
 
517
        if opt_profile:
 
518
            ret = apply_profiled(cmd_obj.run_argv, argv)
678
519
        else:
679
 
            ret = run(*run_argv)
 
520
            ret = cmd_obj.run_argv(argv)
680
521
        return ret or 0
681
522
    finally:
682
523
        # reset, in case we may do other commands later within the same process
683
 
        trace.be_quiet(False)
 
524
        be_quiet(False)
684
525
 
685
526
def display_command(func):
686
527
    """Decorator that suppresses pipe/interrupt errors."""
690
531
            sys.stdout.flush()
691
532
            return result
692
533
        except IOError, e:
693
 
            if getattr(e, 'errno', None) is None:
 
534
            if not hasattr(e, 'errno'):
694
535
                raise
695
536
            if e.errno != errno.EPIPE:
696
 
                # Win32 raises IOError with errno=0 on a broken pipe
697
 
                if sys.platform != 'win32' or (e.errno not in (0, errno.EINVAL)):
698
 
                    raise
 
537
                raise
699
538
            pass
700
539
        except KeyboardInterrupt:
701
540
            pass
704
543
 
705
544
def main(argv):
706
545
    import bzrlib.ui
707
 
    from bzrlib.ui.text import TextUIFactory
708
 
    bzrlib.ui.ui_factory = TextUIFactory()
709
 
    argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
710
 
    ret = run_bzr_catch_errors(argv)
711
 
    trace.mutter("return code %d", ret)
 
546
    ## bzrlib.trace.enable_default_logging()
 
547
    bzrlib.trace.log_startup(argv)
 
548
    bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
 
549
    ret = run_bzr_catch_errors(argv[1:])
 
550
    mutter("return code %d", ret)
712
551
    return ret
713
552
 
714
553
 
719
558
        finally:
720
559
            # do this here inside the exception wrappers to catch EPIPE
721
560
            sys.stdout.flush()
722
 
    except (KeyboardInterrupt, Exception), e:
 
561
    except Exception, e:
723
562
        # used to handle AssertionError and KeyboardInterrupt
724
563
        # specially here, but hopefully they're handled ok by the logger now
725
 
        trace.report_exception(sys.exc_info(), sys.stderr)
726
 
        if os.environ.get('BZR_PDB'):
727
 
            print '**** entering debugger'
728
 
            import pdb
729
 
            pdb.post_mortem(sys.exc_traceback)
730
 
        return 3
731
 
 
732
 
 
733
 
class HelpCommandIndex(object):
734
 
    """A index for bzr help that returns commands."""
735
 
 
736
 
    def __init__(self):
737
 
        self.prefix = 'commands/'
738
 
 
739
 
    def get_topics(self, topic):
740
 
        """Search for topic amongst commands.
741
 
 
742
 
        :param topic: A topic to search for.
743
 
        :return: A list which is either empty or contains a single
744
 
            Command entry.
745
 
        """
746
 
        if topic and topic.startswith(self.prefix):
747
 
            topic = topic[len(self.prefix):]
748
 
        try:
749
 
            cmd = _get_cmd_object(topic)
750
 
        except KeyError:
751
 
            return []
 
564
        import errno
 
565
        if (isinstance(e, IOError) 
 
566
            and hasattr(e, 'errno')
 
567
            and e.errno == errno.EPIPE):
 
568
            bzrlib.trace.note('broken pipe')
 
569
            return 3
752
570
        else:
753
 
            return [cmd]
754
 
 
 
571
            bzrlib.trace.log_exception()
 
572
            if os.environ.get('BZR_PDB'):
 
573
                print '**** entering debugger'
 
574
                import pdb
 
575
                pdb.post_mortem(sys.exc_traceback)
 
576
            return 3
755
577
 
756
578
if __name__ == '__main__':
757
579
    sys.exit(main(sys.argv))