~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

UnfuckĀ upgrade.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2008, 2009 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
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
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
 
import threading
39
 
from warnings import warn
40
35
 
41
36
import bzrlib
42
 
from bzrlib import (
43
 
    cleanup,
44
 
    debug,
45
 
    errors,
46
 
    option,
47
 
    osutils,
48
 
    trace,
49
 
    ui,
50
 
    win32utils,
51
 
    )
52
 
""")
53
 
 
54
 
from bzrlib.hooks import HookPoint, Hooks
55
 
# Compatibility - Option used to be in commands.
 
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
56
46
from bzrlib.option import Option
57
 
from bzrlib import registry
58
 
from bzrlib.symbol_versioning import (
59
 
    deprecated_function,
60
 
    deprecated_in,
61
 
    deprecated_method,
62
 
    suppress_deprecation_warnings,
63
 
    )
64
 
 
65
 
 
66
 
class CommandInfo(object):
67
 
    """Information about a command."""
68
 
 
69
 
    def __init__(self, aliases):
70
 
        """The list of aliases for the command."""
71
 
        self.aliases = aliases
72
 
 
73
 
    @classmethod
74
 
    def from_command(klass, command):
75
 
        """Factory to construct a CommandInfo from a command."""
76
 
        return klass(command.aliases)
77
 
 
78
 
 
79
 
class CommandRegistry(registry.Registry):
80
 
 
81
 
    @staticmethod
82
 
    def _get_name(command_name):
83
 
        if command_name.startswith("cmd_"):
84
 
            return _unsquish_command_name(command_name)
85
 
        else:
86
 
            return command_name
87
 
 
88
 
    def register(self, cmd, decorate=False):
89
 
        """Utility function to help register a command
90
 
 
91
 
        :param cmd: Command subclass to register
92
 
        :param decorate: If true, allow overriding an existing command
93
 
            of the same name; the old command is returned by this function.
94
 
            Otherwise it is an error to try to override an existing command.
95
 
        """
96
 
        k = cmd.__name__
97
 
        k_unsquished = self._get_name(k)
98
 
        try:
99
 
            previous = self.get(k_unsquished)
100
 
        except KeyError:
101
 
            previous = _builtin_commands().get(k_unsquished)
102
 
        info = CommandInfo.from_command(cmd)
103
 
        try:
104
 
            registry.Registry.register(self, k_unsquished, cmd,
105
 
                                       override_existing=decorate, info=info)
106
 
        except KeyError:
107
 
            trace.warning('Two plugins defined the same command: %r' % k)
108
 
            trace.warning('Not loading the one in %r' %
109
 
                sys.modules[cmd.__module__])
110
 
            trace.warning('Previously this command was registered from %r' %
111
 
                sys.modules[previous.__module__])
112
 
        return previous
113
 
 
114
 
    def register_lazy(self, command_name, aliases, module_name):
115
 
        """Register a command without loading its module.
116
 
 
117
 
        :param command_name: The primary name of the command.
118
 
        :param aliases: A list of aliases for the command.
119
 
        :module_name: The module that the command lives in.
120
 
        """
121
 
        key = self._get_name(command_name)
122
 
        registry.Registry.register_lazy(self, key, module_name, command_name,
123
 
                                        info=CommandInfo(aliases))
124
 
 
125
 
 
126
 
plugin_cmds = CommandRegistry()
 
47
 
 
48
plugin_cmds = {}
127
49
 
128
50
 
129
51
def register_command(cmd, decorate=False):
 
52
    "Utility function to help register a command"
130
53
    global plugin_cmds
131
 
    return plugin_cmds.register(cmd, decorate)
 
54
    k = cmd.__name__
 
55
    if k.startswith("cmd_"):
 
56
        k_unsquished = _unsquish_command_name(k)
 
57
    else:
 
58
        k_unsquished = k
 
59
    if not plugin_cmds.has_key(k_unsquished):
 
60
        plugin_cmds[k_unsquished] = cmd
 
61
        mutter('registered plugin command %s', k_unsquished)      
 
62
        if decorate and k_unsquished in builtin_command_names():
 
63
            return _builtin_commands()[k_unsquished]
 
64
    elif decorate:
 
65
        result = plugin_cmds[k_unsquished]
 
66
        plugin_cmds[k_unsquished] = cmd
 
67
        return result
 
68
    else:
 
69
        log_error('Two plugins defined the same command: %r' % k)
 
70
        log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
132
71
 
133
72
 
134
73
def _squish_command_name(cmd):
136
75
 
137
76
 
138
77
def _unsquish_command_name(cmd):
 
78
    assert cmd.startswith("cmd_")
139
79
    return cmd[4:].replace('_','-')
140
80
 
141
81
 
142
82
def _builtin_commands():
143
83
    import bzrlib.builtins
144
 
    return _scan_module_for_commands(bzrlib.builtins)
145
 
 
146
 
 
147
 
def _scan_module_for_commands(module):
148
84
    r = {}
149
 
    for name, obj in module.__dict__.iteritems():
 
85
    builtins = bzrlib.builtins.__dict__
 
86
    for name in builtins:
150
87
        if name.startswith("cmd_"):
151
 
            real_name = _unsquish_command_name(name)
152
 
            r[real_name] = obj
 
88
            real_name = _unsquish_command_name(name)        
 
89
            r[real_name] = builtins[name]
153
90
    return r
154
91
 
155
 
 
156
 
def _list_bzr_commands(names):
157
 
    """Find commands from bzr's core and plugins."""
158
 
    # to eliminate duplicates
159
 
    names.update(builtin_command_names())
160
 
    names.update(plugin_command_names())
161
 
    return names
162
 
 
163
 
 
164
 
def all_command_names():
165
 
    """Return a set of all command names."""
166
 
    names = set()
167
 
    for hook in Command.hooks['list_commands']:
168
 
        names = hook(names)
169
 
        if names is None:
170
 
            raise AssertionError(
171
 
                'hook %s returned None' % Command.hooks.get_hook_name(hook))
172
 
    return names
173
 
 
 
92
            
174
93
 
175
94
def builtin_command_names():
176
 
    """Return list of builtin command names.
177
 
    
178
 
    Use of all_command_names() is encouraged rather than builtin_command_names
179
 
    and/or plugin_command_names.
180
 
    """
 
95
    """Return list of builtin command names."""
181
96
    return _builtin_commands().keys()
182
 
 
 
97
    
183
98
 
184
99
def plugin_command_names():
185
 
    """Returns command names from commands registered by plugins."""
186
100
    return plugin_cmds.keys()
187
101
 
188
102
 
 
103
def _get_cmd_dict(plugins_override=True):
 
104
    """Return name->class mapping for all commands."""
 
105
    d = _builtin_commands()
 
106
    if plugins_override:
 
107
        d.update(plugin_cmds)
 
108
    return d
 
109
 
 
110
    
 
111
def get_all_cmds(plugins_override=True):
 
112
    """Return canonical name and class for all registered commands."""
 
113
    for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
 
114
        yield k,v
 
115
 
 
116
 
189
117
def get_cmd_object(cmd_name, plugins_override=True):
190
 
    """Return the command object for a command.
 
118
    """Return the canonical name and command class for a command.
191
119
 
192
120
    plugins_override
193
121
        If true, plugin commands can override builtins.
194
122
    """
195
 
    try:
196
 
        return _get_cmd_object(cmd_name, plugins_override)
197
 
    except KeyError:
198
 
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
199
 
 
200
 
 
201
 
def _get_cmd_object(cmd_name, plugins_override=True):
202
 
    """Get a command object.
203
 
 
204
 
    :param cmd_name: The name of the command.
205
 
    :param plugins_override: Allow plugins to override builtins.
206
 
    :return: A Command object instance
207
 
    :raises KeyError: If no command is found.
208
 
    """
209
 
    # We want only 'ascii' command names, but the user may have typed
210
 
    # in a Unicode name. In that case, they should just get a
211
 
    # 'command not found' error later.
212
 
    # In the future, we may actually support Unicode command names.
213
 
    cmd = None
214
 
    # Get a command
215
 
    for hook in Command.hooks['get_command']:
216
 
        cmd = hook(cmd, cmd_name)
217
 
        if cmd is not None and not plugins_override and not cmd.plugin_name():
218
 
            # We've found a non-plugin command, don't permit it to be
219
 
            # overridden.
220
 
            break
221
 
    if cmd is None:
222
 
        for hook in Command.hooks['get_missing_command']:
223
 
            cmd = hook(cmd_name)
224
 
            if cmd is not None:
225
 
                break
226
 
    if cmd is None:
227
 
        # No command found.
228
 
        raise KeyError
229
 
    # Allow plugins to extend commands
230
 
    for hook in Command.hooks['extend_command']:
231
 
        hook(cmd)
232
 
    return cmd
233
 
 
234
 
 
235
 
def _try_plugin_provider(cmd_name):
236
 
    """Probe for a plugin provider having cmd_name."""
237
 
    try:
238
 
        plugin_metadata, provider = probe_for_provider(cmd_name)
239
 
        raise errors.CommandAvailableInPlugin(cmd_name,
240
 
            plugin_metadata, provider)
241
 
    except errors.NoPluginAvailable:
242
 
        pass
243
 
 
244
 
 
245
 
def probe_for_provider(cmd_name):
246
 
    """Look for a provider for cmd_name.
247
 
 
248
 
    :param cmd_name: The command name.
249
 
    :return: plugin_metadata, provider for getting cmd_name.
250
 
    :raises NoPluginAvailable: When no provider can supply the plugin.
251
 
    """
252
 
    # look for providers that provide this command but aren't installed
253
 
    for provider in command_providers_registry:
254
 
        try:
255
 
            return provider.plugin_for_command(cmd_name), provider
256
 
        except errors.NoPluginAvailable:
257
 
            pass
258
 
    raise errors.NoPluginAvailable(cmd_name)
259
 
 
260
 
 
261
 
def _get_bzr_command(cmd_or_None, cmd_name):
262
 
    """Get a command from bzr's core."""
263
 
    cmds = _builtin_commands()
 
123
    from bzrlib.externalcommand import ExternalCommand
 
124
 
 
125
    cmd_name = str(cmd_name)            # not unicode
 
126
 
 
127
    # first look up this command under the specified name
 
128
    cmds = _get_cmd_dict(plugins_override=plugins_override)
264
129
    try:
265
130
        return cmds[cmd_name]()
266
131
    except KeyError:
267
132
        pass
 
133
 
268
134
    # look for any command which claims this as an alias
269
135
    for real_cmd_name, cmd_class in cmds.iteritems():
270
136
        if cmd_name in cmd_class.aliases:
271
137
            return cmd_class()
272
 
    return cmd_or_None
273
 
 
274
 
 
275
 
def _get_external_command(cmd_or_None, cmd_name):
276
 
    """Lookup a command that is a shell script."""
277
 
    # Only do external command lookups when no command is found so far.
278
 
    if cmd_or_None is not None:
279
 
        return cmd_or_None
280
 
    from bzrlib.externalcommand import ExternalCommand
 
138
 
281
139
    cmd_obj = ExternalCommand.find_command(cmd_name)
282
140
    if cmd_obj:
283
141
        return cmd_obj
284
142
 
285
 
 
286
 
def _get_plugin_command(cmd_or_None, cmd_name):
287
 
    """Get a command from bzr's plugins."""
288
 
    try:
289
 
        return plugin_cmds.get(cmd_name)()
290
 
    except KeyError:
291
 
        pass
292
 
    for key in plugin_cmds.keys():
293
 
        info = plugin_cmds.get_info(key)
294
 
        if cmd_name in info.aliases:
295
 
            return plugin_cmds.get(key)()
296
 
    return cmd_or_None
 
143
    raise BzrCommandError("unknown command %r" % cmd_name)
297
144
 
298
145
 
299
146
class Command(object):
321
168
        List of argument forms, marked with whether they are optional,
322
169
        repeated, etc.
323
170
 
324
 
                Examples:
325
 
 
326
 
                ['to_location', 'from_branch?', 'file*']
327
 
 
328
 
                'to_location' is required
329
 
                'from_branch' is optional
330
 
                '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
331
178
 
332
179
    takes_options
333
180
        List of options that may be given for this command.  These can
337
184
    hidden
338
185
        If true, this command isn't advertised.  This is typically
339
186
        for commands intended for expert users.
340
 
 
341
 
    encoding_type
342
 
        Command objects will get a 'outf' attribute, which has been
343
 
        setup to properly handle encoding of unicode strings.
344
 
        encoding_type determines what will happen when characters cannot
345
 
        be encoded
346
 
            strict - abort if we cannot decode
347
 
            replace - put in a bogus character (typically '?')
348
 
            exact - do not encode sys.stdout
349
 
 
350
 
            NOTE: by default on Windows, sys.stdout is opened as a text
351
 
            stream, therefore LF line-endings are converted to CRLF.
352
 
            When a command uses encoding_type = 'exact', then
353
 
            sys.stdout is forced to be a binary stream, and line-endings
354
 
            will not mangled.
355
 
 
356
 
    :cvar hooks: An instance of CommandHooks.
357
187
    """
358
188
    aliases = []
359
189
    takes_args = []
360
190
    takes_options = []
361
 
    encoding_type = 'strict'
362
191
 
363
192
    hidden = False
364
 
 
 
193
    
365
194
    def __init__(self):
366
195
        """Construct an instance of this command."""
367
196
        if self.__doc__ == Command.__doc__:
368
197
            warn("No help message set for %r" % self)
369
 
        # List of standard options directly supported
370
 
        self.supported_std_options = []
371
 
        self._operation = cleanup.OperationWithCleanups(self.run)
372
 
    
373
 
    def add_cleanup(self, cleanup_func, *args, **kwargs):
374
 
        """Register a function to call after self.run returns or raises.
375
 
 
376
 
        Functions will be called in LIFO order.
377
 
        """
378
 
        self._operation.add_cleanup(cleanup_func, *args, **kwargs)
379
 
 
380
 
    def cleanup_now(self):
381
 
        """Execute and empty pending cleanup functions immediately.
382
 
 
383
 
        After cleanup_now all registered cleanups are forgotten.  add_cleanup
384
 
        may be called again after cleanup_now; these cleanups will be called
385
 
        after self.run returns or raises (or when cleanup_now is next called).
386
 
 
387
 
        This is useful for releasing expensive or contentious resources (such
388
 
        as write locks) before doing further work that does not require those
389
 
        resources (such as writing results to self.outf).
390
 
        """
391
 
        self._operation.cleanup_now()
392
 
        
393
 
    @deprecated_method(deprecated_in((2, 1, 0)))
394
 
    def _maybe_expand_globs(self, file_list):
395
 
        """Glob expand file_list if the platform does not do that itself.
396
 
 
397
 
        Not used anymore, now that the bzr command-line parser globs on
398
 
        Windows.
399
 
 
400
 
        :return: A possibly empty list of unicode paths.
401
 
 
402
 
        Introduced in bzrlib 0.18.
403
 
        """
404
 
        return file_list
405
 
 
406
 
    def _usage(self):
407
 
        """Return single-line grammar for this command.
408
 
 
409
 
        Only describes arguments, not options.
410
 
        """
411
 
        s = 'bzr ' + self.name() + ' '
412
 
        for aname in self.takes_args:
413
 
            aname = aname.upper()
414
 
            if aname[-1] in ['$', '+']:
415
 
                aname = aname[:-1] + '...'
416
 
            elif aname[-1] == '?':
417
 
                aname = '[' + aname[:-1] + ']'
418
 
            elif aname[-1] == '*':
419
 
                aname = '[' + aname[:-1] + '...]'
420
 
            s += aname + ' '
421
 
        s = s[:-1]      # remove last space
422
 
        return s
423
 
 
424
 
    def get_help_text(self, additional_see_also=None, plain=True,
425
 
                      see_also_as_links=False, verbose=True):
426
 
        """Return a text string with help for this command.
427
 
 
428
 
        :param additional_see_also: Additional help topics to be
429
 
            cross-referenced.
430
 
        :param plain: if False, raw help (reStructuredText) is
431
 
            returned instead of plain text.
432
 
        :param see_also_as_links: if True, convert items in 'See also'
433
 
            list to internal links (used by bzr_man rstx generator)
434
 
        :param verbose: if True, display the full help, otherwise
435
 
            leave out the descriptive sections and just display
436
 
            usage help (e.g. Purpose, Usage, Options) with a
437
 
            message explaining how to obtain full help.
438
 
        """
439
 
        doc = self.help()
440
 
        if doc is None:
441
 
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
442
 
 
443
 
        # Extract the summary (purpose) and sections out from the text
444
 
        purpose,sections,order = self._get_help_parts(doc)
445
 
 
446
 
        # If a custom usage section was provided, use it
447
 
        if sections.has_key('Usage'):
448
 
            usage = sections.pop('Usage')
449
 
        else:
450
 
            usage = self._usage()
451
 
 
452
 
        # The header is the purpose and usage
453
 
        result = ""
454
 
        result += ':Purpose: %s\n' % purpose
455
 
        if usage.find('\n') >= 0:
456
 
            result += ':Usage:\n%s\n' % usage
457
 
        else:
458
 
            result += ':Usage:   %s\n' % usage
459
 
        result += '\n'
460
 
 
461
 
        # Add the options
462
 
        #
463
 
        # XXX: optparse implicitly rewraps the help, and not always perfectly,
464
 
        # so we get <https://bugs.launchpad.net/bzr/+bug/249908>.  -- mbp
465
 
        # 20090319
466
 
        options = option.get_optparser(self.options()).format_option_help()
467
 
        # XXX: According to the spec, ReST option lists actually don't support 
468
 
        # options like --1.9 so that causes syntax errors (in Sphinx at least).
469
 
        # As that pattern always appears in the commands that break, we trap
470
 
        # on that and then format that block of 'format' options as a literal
471
 
        # block.
472
 
        if not plain and options.find('  --1.9  ') != -1:
473
 
            options = options.replace(' format:\n', ' format::\n\n', 1)
474
 
        if options.startswith('Options:'):
475
 
            result += ':' + options
476
 
        elif options.startswith('options:'):
477
 
            # Python 2.4 version of optparse
478
 
            result += ':Options:' + options[len('options:'):]
479
 
        else:
480
 
            result += options
481
 
        result += '\n'
482
 
 
483
 
        if verbose:
484
 
            # Add the description, indenting it 2 spaces
485
 
            # to match the indentation of the options
486
 
            if sections.has_key(None):
487
 
                text = sections.pop(None)
488
 
                text = '\n  '.join(text.splitlines())
489
 
                result += ':%s:\n  %s\n\n' % ('Description',text)
490
 
 
491
 
            # Add the custom sections (e.g. Examples). Note that there's no need
492
 
            # to indent these as they must be indented already in the source.
493
 
            if sections:
494
 
                for label in order:
495
 
                    if sections.has_key(label):
496
 
                        result += ':%s:\n%s\n' % (label,sections[label])
497
 
                result += '\n'
498
 
        else:
499
 
            result += ("See bzr help %s for more details and examples.\n\n"
500
 
                % self.name())
501
 
 
502
 
        # Add the aliases, source (plug-in) and see also links, if any
503
 
        if self.aliases:
504
 
            result += ':Aliases:  '
505
 
            result += ', '.join(self.aliases) + '\n'
506
 
        plugin_name = self.plugin_name()
507
 
        if plugin_name is not None:
508
 
            result += ':From:     plugin "%s"\n' % plugin_name
509
 
        see_also = self.get_see_also(additional_see_also)
510
 
        if see_also:
511
 
            if not plain and see_also_as_links:
512
 
                see_also_links = []
513
 
                for item in see_also:
514
 
                    if item == 'topics':
515
 
                        # topics doesn't have an independent section
516
 
                        # so don't create a real link
517
 
                        see_also_links.append(item)
518
 
                    else:
519
 
                        # Use a Sphinx link for this entry
520
 
                        link_text = ":doc:`%s <%s-help>`" % (item, item)
521
 
                        see_also_links.append(link_text)
522
 
                see_also = see_also_links
523
 
            result += ':See also: '
524
 
            result += ', '.join(see_also) + '\n'
525
 
 
526
 
        # If this will be rendered as plain text, convert it
527
 
        if plain:
528
 
            import bzrlib.help_topics
529
 
            result = bzrlib.help_topics.help_as_plain_text(result)
530
 
        return result
531
 
 
532
 
    @staticmethod
533
 
    def _get_help_parts(text):
534
 
        """Split help text into a summary and named sections.
535
 
 
536
 
        :return: (summary,sections,order) where summary is the top line and
537
 
            sections is a dictionary of the rest indexed by section name.
538
 
            order is the order the section appear in the text.
539
 
            A section starts with a heading line of the form ":xxx:".
540
 
            Indented text on following lines is the section value.
541
 
            All text found outside a named section is assigned to the
542
 
            default section which is given the key of None.
543
 
        """
544
 
        def save_section(sections, order, label, section):
545
 
            if len(section) > 0:
546
 
                if sections.has_key(label):
547
 
                    sections[label] += '\n' + section
548
 
                else:
549
 
                    order.append(label)
550
 
                    sections[label] = section
551
 
 
552
 
        lines = text.rstrip().splitlines()
553
 
        summary = lines.pop(0)
554
 
        sections = {}
555
 
        order = []
556
 
        label,section = None,''
557
 
        for line in lines:
558
 
            if line.startswith(':') and line.endswith(':') and len(line) > 2:
559
 
                save_section(sections, order, label, section)
560
 
                label,section = line[1:-1],''
561
 
            elif (label is not None) and len(line) > 1 and not line[0].isspace():
562
 
                save_section(sections, order, label, section)
563
 
                label,section = None,line
564
 
            else:
565
 
                if len(section) > 0:
566
 
                    section += '\n' + line
567
 
                else:
568
 
                    section = line
569
 
        save_section(sections, order, label, section)
570
 
        return summary, sections, order
571
 
 
572
 
    def get_help_topic(self):
573
 
        """Return the commands help topic - its name."""
574
 
        return self.name()
575
 
 
576
 
    def get_see_also(self, additional_terms=None):
577
 
        """Return a list of help topics that are related to this command.
578
 
 
579
 
        The list is derived from the content of the _see_also attribute. Any
580
 
        duplicates are removed and the result is in lexical order.
581
 
        :param additional_terms: Additional help topics to cross-reference.
582
 
        :return: A list of help topics.
583
 
        """
584
 
        see_also = set(getattr(self, '_see_also', []))
585
 
        if additional_terms:
586
 
            see_also.update(additional_terms)
587
 
        return sorted(see_also)
588
198
 
589
199
    def options(self):
590
200
        """Return dict of valid options for this command.
591
201
 
592
202
        Maps from long option name to option object."""
593
 
        r = Option.STD_OPTIONS.copy()
594
 
        std_names = r.keys()
 
203
        r = dict()
 
204
        r['help'] = Option.OPTIONS['help']
595
205
        for o in self.takes_options:
596
 
            if isinstance(o, basestring):
597
 
                o = option.Option.OPTIONS[o]
 
206
            if not isinstance(o, Option):
 
207
                o = Option.OPTIONS[o]
598
208
            r[o.name] = o
599
 
            if o.name in std_names:
600
 
                self.supported_std_options.append(o.name)
601
209
        return r
602
210
 
603
 
    def _setup_outf(self):
604
 
        """Return a file linked to stdout, which has proper encoding."""
605
 
        self.outf = ui.ui_factory.make_output_stream(
606
 
            encoding_type=self.encoding_type)
607
 
 
608
 
    def run_argv_aliases(self, argv, alias_argv=None):
609
 
        """Parse the command line and run with extra aliases in alias_argv."""
610
 
        args, opts = parse_args(self, argv, alias_argv)
611
 
 
612
 
        # Process the standard options
 
211
    def run_argv(self, argv):
 
212
        """Parse command line and run."""
 
213
        args, opts = parse_args(self, argv)
613
214
        if 'help' in opts:  # e.g. bzr add --help
614
 
            sys.stdout.write(self.get_help_text())
615
 
            return 0
616
 
        if 'usage' in opts:  # e.g. bzr add --usage
617
 
            sys.stdout.write(self.get_help_text(verbose=False))
618
 
            return 0
619
 
        trace.set_verbosity_level(option._verbosity_level)
620
 
        if 'verbose' in self.supported_std_options:
621
 
            opts['verbose'] = trace.is_verbose()
622
 
        elif opts.has_key('verbose'):
623
 
            del opts['verbose']
624
 
        if 'quiet' in self.supported_std_options:
625
 
            opts['quiet'] = trace.is_quiet()
626
 
        elif opts.has_key('quiet'):
627
 
            del opts['quiet']
628
 
 
 
215
            from bzrlib.help import help_on_command
 
216
            help_on_command(self.name())
 
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()))
629
224
        # mix arguments and options into one dictionary
630
225
        cmdargs = _match_argform(self.name(), self.takes_args, args)
631
226
        cmdopts = {}
635
230
        all_cmd_args = cmdargs.copy()
636
231
        all_cmd_args.update(cmdopts)
637
232
 
638
 
        self._setup_outf()
639
 
 
640
 
        return self.run_direct(**all_cmd_args)
641
 
 
642
 
    def run_direct(self, *args, **kwargs):
643
 
        """Call run directly with objects (without parsing an argv list)."""
644
 
        return self._operation.run_simple(*args, **kwargs)
645
 
 
 
233
        return self.run(**all_cmd_args)
 
234
    
646
235
    def run(self):
647
236
        """Actually run the command.
648
237
 
653
242
        shell error code if not.  It's OK for this method to allow
654
243
        an exception to raise up.
655
244
        """
656
 
        raise NotImplementedError('no implementation of command %r'
657
 
                                  % self.name())
 
245
        raise NotImplementedError()
 
246
 
658
247
 
659
248
    def help(self):
660
249
        """Return help message for this class."""
661
 
        from inspect import getdoc
662
250
        if self.__doc__ is Command.__doc__:
663
251
            return None
664
252
        return getdoc(self)
666
254
    def name(self):
667
255
        return _unsquish_command_name(self.__class__.__name__)
668
256
 
669
 
    def plugin_name(self):
670
 
        """Get the name of the plugin that provides this command.
671
257
 
672
 
        :return: The name of the plugin or None if the command is builtin.
673
 
        """
674
 
        mod_parts = self.__module__.split('.')
675
 
        if len(mod_parts) >= 3 and mod_parts[1] == 'plugins':
676
 
            return mod_parts[2]
 
258
def parse_spec(spec):
 
259
    """
 
260
    >>> parse_spec(None)
 
261
    [None, None]
 
262
    >>> parse_spec("./")
 
263
    ['./', None]
 
264
    >>> parse_spec("../@")
 
265
    ['..', -1]
 
266
    >>> parse_spec("../f/@35")
 
267
    ['../f', 35]
 
268
    >>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
 
269
    ['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
 
270
    """
 
271
    if spec is None:
 
272
        return [None, None]
 
273
    if '/@' in spec:
 
274
        parsed = spec.split('/@')
 
275
        assert len(parsed) == 2
 
276
        if parsed[1] == "":
 
277
            parsed[1] = -1
677
278
        else:
678
 
            return None
679
 
 
680
 
 
681
 
class CommandHooks(Hooks):
682
 
    """Hooks related to Command object creation/enumeration."""
683
 
 
684
 
    def __init__(self):
685
 
        """Create the default hooks.
686
 
 
687
 
        These are all empty initially, because by default nothing should get
688
 
        notified.
689
 
        """
690
 
        Hooks.__init__(self)
691
 
        self.create_hook(HookPoint('extend_command',
692
 
            "Called after creating a command object to allow modifications "
693
 
            "such as adding or removing options, docs etc. Called with the "
694
 
            "new bzrlib.commands.Command object.", (1, 13), None))
695
 
        self.create_hook(HookPoint('get_command',
696
 
            "Called when creating a single command. Called with "
697
 
            "(cmd_or_None, command_name). get_command should either return "
698
 
            "the cmd_or_None parameter, or a replacement Command object that "
699
 
            "should be used for the command. Note that the Command.hooks "
700
 
            "hooks are core infrastructure. Many users will prefer to use "
701
 
            "bzrlib.commands.register_command or plugin_cmds.register_lazy.",
702
 
            (1, 17), None))
703
 
        self.create_hook(HookPoint('get_missing_command',
704
 
            "Called when creating a single command if no command could be "
705
 
            "found. Called with (command_name). get_missing_command should "
706
 
            "either return None, or a Command object to be used for the "
707
 
            "command.", (1, 17), None))
708
 
        self.create_hook(HookPoint('list_commands',
709
 
            "Called when enumerating commands. Called with a set of "
710
 
            "cmd_name strings for all the commands found so far. This set "
711
 
            " is safe to mutate - e.g. to remove a command. "
712
 
            "list_commands should return the updated set of command names.",
713
 
            (1, 17), None))
714
 
 
715
 
Command.hooks = CommandHooks()
716
 
 
717
 
 
718
 
def parse_args(command, argv, alias_argv=None):
 
279
            try:
 
280
                parsed[1] = int(parsed[1])
 
281
            except ValueError:
 
282
                pass # We can allow stuff like ./@revid:blahblahblah
 
283
            else:
 
284
                assert parsed[1] >=0
 
285
    else:
 
286
        parsed = [spec, None]
 
287
    return parsed
 
288
 
 
289
def parse_args(command, argv):
719
290
    """Parse command line.
720
 
 
 
291
    
721
292
    Arguments and options are parsed at this level before being passed
722
293
    down to specific command handlers.  This routine knows, from a
723
294
    lookup table, something about the available options, what optargs
724
295
    they take, and which commands will accept them.
725
296
    """
726
 
    # TODO: make it a method of the Command?
727
 
    parser = option.get_optparser(command.options())
728
 
    if alias_argv is not None:
729
 
        args = alias_argv + argv
730
 
    else:
731
 
        args = argv
732
 
 
733
 
    options, args = parser.parse_args(args)
734
 
    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
735
 
                 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)
736
379
    return args, opts
737
380
 
738
381
 
753
396
                argdict[argname + '_list'] = None
754
397
        elif ap[-1] == '+':
755
398
            if not args:
756
 
                raise errors.BzrCommandError("command %r needs one or more %s"
757
 
                                             % (cmd, argname.upper()))
 
399
                raise BzrCommandError("command %r needs one or more %s"
 
400
                        % (cmd, argname.upper()))
758
401
            else:
759
402
                argdict[argname + '_list'] = args[:]
760
403
                args = []
761
404
        elif ap[-1] == '$': # all but one
762
405
            if len(args) < 2:
763
 
                raise errors.BzrCommandError("command %r needs one or more %s"
764
 
                                             % (cmd, argname.upper()))
 
406
                raise BzrCommandError("command %r needs one or more %s"
 
407
                        % (cmd, argname.upper()))
765
408
            argdict[argname + '_list'] = args[:-1]
766
 
            args[:-1] = []
 
409
            args[:-1] = []                
767
410
        else:
768
411
            # just a plain arg
769
412
            argname = ap
770
413
            if not args:
771
 
                raise errors.BzrCommandError("command %r requires argument %s"
772
 
                               % (cmd, argname.upper()))
 
414
                raise BzrCommandError("command %r requires argument %s"
 
415
                        % (cmd, argname.upper()))
773
416
            else:
774
417
                argdict[argname] = args.pop(0)
775
 
 
 
418
            
776
419
    if args:
777
 
        raise errors.BzrCommandError("extra argument to command %s: %s"
778
 
                                     % (cmd, args[0]))
 
420
        raise BzrCommandError("extra argument to command %s: %s"
 
421
                              % (cmd, args[0]))
779
422
 
780
423
    return argdict
781
424
 
782
 
def apply_coveraged(dirname, the_callable, *args, **kwargs):
783
 
    # Cannot use "import trace", as that would import bzrlib.trace instead of
784
 
    # the standard library's trace.
785
 
    trace = __import__('trace')
786
 
 
787
 
    tracer = trace.Trace(count=1, trace=0)
788
 
    sys.settrace(tracer.globaltrace)
789
 
    threading.settrace(tracer.globaltrace)
790
 
 
791
 
    try:
792
 
        return exception_to_return_code(the_callable, *args, **kwargs)
793
 
    finally:
794
 
        sys.settrace(None)
795
 
        results = tracer.results()
796
 
        results.write_results(show_missing=1, summary=False,
797
 
                              coverdir=dirname)
798
425
 
799
426
 
800
427
def apply_profiled(the_callable, *args, **kwargs):
805
432
    try:
806
433
        prof = hotshot.Profile(pfname)
807
434
        try:
808
 
            ret = prof.runcall(exception_to_return_code, the_callable, *args,
809
 
                **kwargs) or 0
 
435
            ret = prof.runcall(the_callable, *args, **kwargs) or 0
810
436
        finally:
811
437
            prof.close()
812
438
        stats = hotshot.stats.load(pfname)
821
447
        os.remove(pfname)
822
448
 
823
449
 
824
 
def exception_to_return_code(the_callable, *args, **kwargs):
825
 
    """UI level helper for profiling and coverage.
826
 
 
827
 
    This transforms exceptions into a return value of 3. As such its only
828
 
    relevant to the UI layer, and should never be called where catching
829
 
    exceptions may be desirable.
830
 
    """
831
 
    try:
832
 
        return the_callable(*args, **kwargs)
833
 
    except (KeyboardInterrupt, Exception), e:
834
 
        # used to handle AssertionError and KeyboardInterrupt
835
 
        # specially here, but hopefully they're handled ok by the logger now
836
 
        exc_info = sys.exc_info()
837
 
        exitcode = trace.report_exception(exc_info, sys.stderr)
838
 
        if os.environ.get('BZR_PDB'):
839
 
            print '**** entering debugger'
840
 
            tb = exc_info[2]
841
 
            import pdb
842
 
            if sys.version_info[:2] < (2, 6):
843
 
                # XXX: we want to do
844
 
                #    pdb.post_mortem(tb)
845
 
                # but because pdb.post_mortem gives bad results for tracebacks
846
 
                # from inside generators, we do it manually.
847
 
                # (http://bugs.python.org/issue4150, fixed in Python 2.6)
848
 
 
849
 
                # Setup pdb on the traceback
850
 
                p = pdb.Pdb()
851
 
                p.reset()
852
 
                p.setup(tb.tb_frame, tb)
853
 
                # Point the debugger at the deepest frame of the stack
854
 
                p.curindex = len(p.stack) - 1
855
 
                p.curframe = p.stack[p.curindex][0]
856
 
                # Start the pdb prompt.
857
 
                p.print_stack_entry(p.stack[p.curindex])
858
 
                p.execRcLines()
859
 
                p.cmdloop()
860
 
            else:
861
 
                pdb.post_mortem(tb)
862
 
        return exitcode
863
 
 
864
 
 
865
 
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
 
450
def apply_lsprofiled(the_callable, *args, **kwargs):
866
451
    from bzrlib.lsprof import profile
867
 
    ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
 
452
    ret,stats = profile(the_callable,*args,**kwargs)
868
453
    stats.sort()
869
 
    if filename is None:
870
 
        stats.pprint()
871
 
    else:
872
 
        stats.save(filename)
873
 
        trace.note('Profile data written to "%s".', filename)
 
454
    stats.pprint()
874
455
    return ret
875
456
 
876
 
 
877
 
def shlex_split_unicode(unsplit):
878
 
    import shlex
879
 
    return [u.decode('utf-8') for u in shlex.split(unsplit.encode('utf-8'))]
880
 
 
881
 
 
882
 
def get_alias(cmd, config=None):
883
 
    """Return an expanded alias, or None if no alias exists.
884
 
 
885
 
    cmd
886
 
        Command to be checked for an alias.
887
 
    config
888
 
        Used to specify an alternative config to use,
889
 
        which is especially useful for testing.
890
 
        If it is unspecified, the global config will be used.
891
 
    """
892
 
    if config is None:
893
 
        import bzrlib.config
894
 
        config = bzrlib.config.GlobalConfig()
895
 
    alias = config.get_alias(cmd)
896
 
    if (alias):
897
 
        return shlex_split_unicode(alias)
898
 
    return None
899
 
 
900
 
 
901
457
def run_bzr(argv):
902
458
    """Execute a command.
903
459
 
 
460
    This is similar to main(), but without all the trappings for
 
461
    logging and error handling.  
 
462
    
904
463
    argv
905
464
       The command-line arguments, without the program name from argv[0]
906
 
       These should already be decoded. All library/test code calling
907
 
       run_bzr should be passing valid strings (don't need decoding).
908
 
 
 
465
    
909
466
    Returns a command status or raises an exception.
910
467
 
911
468
    Special master options: these must come before the command because
914
471
    --no-plugins
915
472
        Do not load plugin modules at all
916
473
 
917
 
    --no-aliases
918
 
        Do not allow aliases
919
 
 
920
474
    --builtin
921
475
        Only use builtin commands.  (Plugins are still allowed to change
922
476
        other behaviour.)
926
480
 
927
481
    --lsprof
928
482
        Run under the Python lsprof profiler.
929
 
 
930
 
    --coverage
931
 
        Generate line coverage report in the specified directory.
932
 
 
933
 
    --concurrency
934
 
        Specify the number of processes that can be run concurrently (selftest).
935
483
    """
936
 
    trace.mutter("bazaar version: " + bzrlib.__version__)
937
 
    argv = list(argv)
938
 
    trace.mutter("bzr arguments: %r", argv)
 
484
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
939
485
 
940
 
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
941
 
                opt_no_aliases = False
942
 
    opt_lsprof_file = opt_coverage_dir = None
 
486
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = False
943
487
 
944
488
    # --no-plugins is handled specially at a very early stage. We need
945
489
    # to load plugins before doing other command parsing so that they
946
490
    # can override commands, but this needs to happen first.
947
491
 
948
 
    argv_copy = []
949
 
    i = 0
950
 
    while i < len(argv):
951
 
        a = argv[i]
 
492
    for a in argv:
952
493
        if a == '--profile':
953
494
            opt_profile = True
954
495
        elif a == '--lsprof':
955
496
            opt_lsprof = True
956
 
        elif a == '--lsprof-file':
957
 
            opt_lsprof = True
958
 
            opt_lsprof_file = argv[i + 1]
959
 
            i += 1
960
497
        elif a == '--no-plugins':
961
498
            opt_no_plugins = True
962
 
        elif a == '--no-aliases':
963
 
            opt_no_aliases = True
964
499
        elif a == '--builtin':
965
500
            opt_builtin = True
966
 
        elif a == '--concurrency':
967
 
            os.environ['BZR_CONCURRENCY'] = argv[i + 1]
968
 
            i += 1
969
 
        elif a == '--coverage':
970
 
            opt_coverage_dir = argv[i + 1]
971
 
            i += 1
972
 
        elif a.startswith('-D'):
973
 
            debug.debug_flags.add(a[2:])
974
 
        else:
975
 
            argv_copy.append(a)
976
 
        i += 1
977
 
 
978
 
    debug.set_debug_flags_from_config()
979
 
 
980
 
    argv = argv_copy
981
 
    if (not argv):
982
 
        from bzrlib.builtins import cmd_help
983
 
        cmd_help().run_argv_aliases([])
 
501
        elif a in ('--quiet', '-q'):
 
502
            be_quiet()
 
503
        else:
 
504
            continue
 
505
        argv.remove(a)
 
506
 
 
507
    if (not argv) or (argv[0] == '--help'):
 
508
        from bzrlib.help import help
 
509
        if len(argv) > 1:
 
510
            help(argv[1])
 
511
        else:
 
512
            help()
984
513
        return 0
985
514
 
986
515
    if argv[0] == '--version':
987
 
        from bzrlib.builtins import cmd_version
988
 
        cmd_version().run_argv_aliases([])
 
516
        from bzrlib.builtins import show_version
 
517
        show_version()
989
518
        return 0
990
 
 
 
519
        
991
520
    if not opt_no_plugins:
992
521
        from bzrlib.plugin import load_plugins
993
522
        load_plugins()
994
 
    else:
995
 
        from bzrlib.plugin import disable_plugins
996
 
        disable_plugins()
997
 
 
998
 
    alias_argv = None
999
 
 
1000
 
    if not opt_no_aliases:
1001
 
        alias_argv = get_alias(argv[0])
1002
 
        if alias_argv:
1003
 
            user_encoding = osutils.get_user_encoding()
1004
 
            alias_argv = [a.decode(user_encoding) for a in alias_argv]
1005
 
            argv[0] = alias_argv.pop(0)
1006
 
 
1007
 
    cmd = argv.pop(0)
1008
 
    # We want only 'ascii' command names, but the user may have typed
1009
 
    # in a Unicode name. In that case, they should just get a
1010
 
    # 'command not found' error later.
 
523
 
 
524
    cmd = str(argv.pop(0))
1011
525
 
1012
526
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
1013
 
    run = cmd_obj.run_argv_aliases
1014
 
    run_argv = [argv, alias_argv]
1015
527
 
1016
528
    try:
1017
 
        # We can be called recursively (tests for example), but we don't want
1018
 
        # the verbosity level to propagate.
1019
 
        saved_verbosity_level = option._verbosity_level
1020
 
        option._verbosity_level = 0
1021
529
        if opt_lsprof:
1022
 
            if opt_coverage_dir:
1023
 
                trace.warning(
1024
 
                    '--coverage ignored, because --lsprof is in use.')
1025
 
            ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
 
530
            ret = apply_lsprofiled(cmd_obj.run_argv, argv)
1026
531
        elif opt_profile:
1027
 
            if opt_coverage_dir:
1028
 
                trace.warning(
1029
 
                    '--coverage ignored, because --profile is in use.')
1030
 
            ret = apply_profiled(run, *run_argv)
1031
 
        elif opt_coverage_dir:
1032
 
            ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
 
532
            ret = apply_profiled(cmd_obj.run_argv, argv)
1033
533
        else:
1034
 
            ret = run(*run_argv)
 
534
            ret = cmd_obj.run_argv(argv)
1035
535
        return ret or 0
1036
536
    finally:
1037
 
        # reset, in case we may do other commands later within the same
1038
 
        # process. Commands that want to execute sub-commands must propagate
1039
 
        # --verbose in their own way.
1040
 
        if 'memory' in debug.debug_flags:
1041
 
            trace.debug_memory('Process status after command:', short=False)
1042
 
        option._verbosity_level = saved_verbosity_level
1043
 
 
 
537
        # reset, in case we may do other commands later within the same process
 
538
        be_quiet(False)
1044
539
 
1045
540
def display_command(func):
1046
541
    """Decorator that suppresses pipe/interrupt errors."""
1050
545
            sys.stdout.flush()
1051
546
            return result
1052
547
        except IOError, e:
1053
 
            if getattr(e, 'errno', None) is None:
 
548
            if not hasattr(e, 'errno'):
1054
549
                raise
1055
550
            if e.errno != errno.EPIPE:
1056
 
                # Win32 raises IOError with errno=0 on a broken pipe
1057
 
                if sys.platform != 'win32' or (e.errno not in (0, errno.EINVAL)):
1058
 
                    raise
 
551
                raise
1059
552
            pass
1060
553
        except KeyboardInterrupt:
1061
554
            pass
1062
555
    return ignore_pipe
1063
556
 
1064
557
 
1065
 
def install_bzr_command_hooks():
1066
 
    """Install the hooks to supply bzr's own commands."""
1067
 
    if _list_bzr_commands in Command.hooks["list_commands"]:
1068
 
        return
1069
 
    Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
1070
 
        "bzr commands")
1071
 
    Command.hooks.install_named_hook("get_command", _get_bzr_command,
1072
 
        "bzr commands")
1073
 
    Command.hooks.install_named_hook("get_command", _get_plugin_command,
1074
 
        "bzr plugin commands")
1075
 
    Command.hooks.install_named_hook("get_command", _get_external_command,
1076
 
        "bzr external command lookup")
1077
 
    Command.hooks.install_named_hook("get_missing_command", _try_plugin_provider,
1078
 
        "bzr plugin-provider-db check")
1079
 
 
1080
 
 
1081
 
def main(argv=None):
1082
 
    """Main entry point of command-line interface.
1083
 
 
1084
 
    :param argv: list of unicode command-line arguments similar to sys.argv.
1085
 
        argv[0] is script name usually, it will be ignored.
1086
 
        Don't pass here sys.argv because this list contains plain strings
1087
 
        and not unicode; pass None instead.
1088
 
 
1089
 
    :return: exit code of bzr command.
1090
 
    """
 
558
def main(argv):
1091
559
    import bzrlib.ui
1092
 
    bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
1093
 
        sys.stdin, sys.stdout, sys.stderr)
1094
 
 
1095
 
    # Is this a final release version? If so, we should suppress warnings
1096
 
    if bzrlib.version_info[3] == 'final':
1097
 
        suppress_deprecation_warnings(override=True)
1098
 
    if argv is None:
1099
 
        argv = osutils.get_unicode_argv()
1100
 
    else:
1101
 
        new_argv = []
1102
 
        try:
1103
 
            # ensure all arguments are unicode strings
1104
 
            for a in argv[1:]:
1105
 
                if isinstance(a, unicode):
1106
 
                    new_argv.append(a)
1107
 
                else:
1108
 
                    new_argv.append(a.decode('ascii'))
1109
 
        except UnicodeDecodeError:
1110
 
            raise errors.BzrError("argv should be list of unicode strings.")
1111
 
        argv = new_argv
1112
 
    ret = run_bzr_catch_errors(argv)
1113
 
    bzrlib.ui.ui_factory.log_transport_activity(
1114
 
        display=('bytes' in debug.debug_flags))
1115
 
    trace.mutter("return code %d", ret)
1116
 
    osutils.report_extension_load_failures()
 
560
    from bzrlib.ui.text import TextUIFactory
 
561
    ## bzrlib.trace.enable_default_logging()
 
562
    bzrlib.trace.log_startup(argv)
 
563
    bzrlib.ui.ui_factory = TextUIFactory()
 
564
    ret = run_bzr_catch_errors(argv[1:])
 
565
    mutter("return code %d", ret)
1117
566
    return ret
1118
567
 
1119
568
 
1120
569
def run_bzr_catch_errors(argv):
1121
 
    """Run a bzr command with parameters as described by argv.
1122
 
 
1123
 
    This function assumed that that UI layer is setup, that symbol deprecations
1124
 
    are already applied, and that unicode decoding has already been performed on argv.
1125
 
    """
1126
 
    install_bzr_command_hooks()
1127
 
    return exception_to_return_code(run_bzr, argv)
1128
 
 
1129
 
 
1130
 
def run_bzr_catch_user_errors(argv):
1131
 
    """Run bzr and report user errors, but let internal errors propagate.
1132
 
 
1133
 
    This is used for the test suite, and might be useful for other programs
1134
 
    that want to wrap the commandline interface.
1135
 
    """
1136
 
    install_bzr_command_hooks()
1137
570
    try:
1138
 
        return run_bzr(argv)
 
571
        try:
 
572
            return run_bzr(argv)
 
573
        finally:
 
574
            # do this here inside the exception wrappers to catch EPIPE
 
575
            sys.stdout.flush()
1139
576
    except Exception, e:
1140
 
        if (isinstance(e, (OSError, IOError))
1141
 
            or not getattr(e, 'internal_error', True)):
1142
 
            trace.report_exception(sys.exc_info(), sys.stderr)
1143
 
            return 3
1144
 
        else:
1145
 
            raise
1146
 
 
1147
 
 
1148
 
class HelpCommandIndex(object):
1149
 
    """A index for bzr help that returns commands."""
1150
 
 
1151
 
    def __init__(self):
1152
 
        self.prefix = 'commands/'
1153
 
 
1154
 
    def get_topics(self, topic):
1155
 
        """Search for topic amongst commands.
1156
 
 
1157
 
        :param topic: A topic to search for.
1158
 
        :return: A list which is either empty or contains a single
1159
 
            Command entry.
1160
 
        """
1161
 
        if topic and topic.startswith(self.prefix):
1162
 
            topic = topic[len(self.prefix):]
1163
 
        try:
1164
 
            cmd = _get_cmd_object(topic)
1165
 
        except KeyError:
1166
 
            return []
1167
 
        else:
1168
 
            return [cmd]
1169
 
 
1170
 
 
1171
 
class Provider(object):
1172
 
    '''Generic class to be overriden by plugins'''
1173
 
 
1174
 
    def plugin_for_command(self, cmd_name):
1175
 
        '''Takes a command and returns the information for that plugin
1176
 
 
1177
 
        :return: A dictionary with all the available information
1178
 
        for the requested plugin
1179
 
        '''
1180
 
        raise NotImplementedError
1181
 
 
1182
 
 
1183
 
class ProvidersRegistry(registry.Registry):
1184
 
    '''This registry exists to allow other providers to exist'''
1185
 
 
1186
 
    def __iter__(self):
1187
 
        for key, provider in self.iteritems():
1188
 
            yield provider
1189
 
 
1190
 
command_providers_registry = ProvidersRegistry()
1191
 
 
 
577
        # used to handle AssertionError and KeyboardInterrupt
 
578
        # specially here, but hopefully they're handled ok by the logger now
 
579
        import errno
 
580
        if (isinstance(e, IOError) 
 
581
            and hasattr(e, 'errno')
 
582
            and e.errno == errno.EPIPE):
 
583
            bzrlib.trace.note('broken pipe')
 
584
            return 3
 
585
        else:
 
586
            bzrlib.trace.log_exception()
 
587
            if os.environ.get('BZR_PDB'):
 
588
                print '**** entering debugger'
 
589
                import pdb
 
590
                pdb.post_mortem(sys.exc_traceback)
 
591
            return 3
1192
592
 
1193
593
if __name__ == '__main__':
1194
594
    sys.exit(main(sys.argv))