/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-02-11 04:02:41 UTC
  • mfrom: (5017.2.2 tariff)
  • Revision ID: pqm@pqm.ubuntu.com-20100211040241-w6n021dz0uus341n
(mbp) add import-tariff tests

Show diffs side-by-side

added added

removed removed

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