~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: John Arbash Meinel
  • Date: 2008-11-25 17:15:26 UTC
  • mto: This revision was merged to the branch mainline in revision 3851.
  • Revision ID: john@arbash-meinel.com-20081125171526-pi2g4m1w70pkie1f
Add a bit of help text when supplying --help.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2008 Canonical Ltd
2
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
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
35
35
lazy_import(globals(), """
36
36
import codecs
37
37
import errno
38
 
import threading
39
38
from warnings import warn
40
39
 
41
40
import bzrlib
42
41
from bzrlib import (
43
 
    cleanup,
44
 
    cmdline,
45
42
    debug,
46
43
    errors,
47
44
    option,
48
45
    osutils,
49
46
    trace,
50
 
    ui,
51
47
    win32utils,
52
48
    )
53
49
""")
54
50
 
55
 
from bzrlib.hooks import HookPoint, Hooks
56
 
# Compatibility - Option used to be in commands.
 
51
from bzrlib import registry
 
52
# Compatibility
57
53
from bzrlib.option import Option
58
 
from bzrlib.plugin import disable_plugins, load_plugins
59
 
from bzrlib import registry
60
 
from bzrlib.symbol_versioning import (
61
 
    deprecated_function,
62
 
    deprecated_in,
63
 
    deprecated_method,
64
 
    )
65
54
 
66
55
 
67
56
class CommandInfo(object):
105
94
            registry.Registry.register(self, k_unsquished, cmd,
106
95
                                       override_existing=decorate, info=info)
107
96
        except KeyError:
108
 
            trace.warning('Two plugins defined the same command: %r' % k)
109
 
            trace.warning('Not loading the one in %r' %
110
 
                sys.modules[cmd.__module__])
111
 
            trace.warning('Previously this command was registered from %r' %
112
 
                sys.modules[previous.__module__])
 
97
            trace.log_error('Two plugins defined the same command: %r' % k)
 
98
            trace.log_error('Not loading the one in %r' %
 
99
                            sys.modules[cmd.__module__])
 
100
            trace.log_error('Previously this command was registered from %r' %
 
101
                            sys.modules[previous.__module__])
113
102
        return previous
114
103
 
115
104
    def register_lazy(self, command_name, aliases, module_name):
142
131
 
143
132
def _builtin_commands():
144
133
    import bzrlib.builtins
145
 
    return _scan_module_for_commands(bzrlib.builtins)
146
 
 
147
 
 
148
 
def _scan_module_for_commands(module):
149
134
    r = {}
150
 
    for name, obj in module.__dict__.iteritems():
 
135
    builtins = bzrlib.builtins.__dict__
 
136
    for name in builtins:
151
137
        if name.startswith("cmd_"):
152
138
            real_name = _unsquish_command_name(name)
153
 
            r[real_name] = obj
 
139
            r[real_name] = builtins[name]
154
140
    return r
155
 
 
156
 
 
157
 
def _list_bzr_commands(names):
158
 
    """Find commands from bzr's core and plugins."""
159
 
    # to eliminate duplicates
160
 
    names.update(builtin_command_names())
161
 
    names.update(plugin_command_names())
162
 
    return names
163
 
 
164
 
 
165
 
def all_command_names():
166
 
    """Return a set of all command names."""
167
 
    names = set()
168
 
    for hook in Command.hooks['list_commands']:
169
 
        names = hook(names)
170
 
        if names is None:
171
 
            raise AssertionError(
172
 
                'hook %s returned None' % Command.hooks.get_hook_name(hook))
173
 
    return names
174
 
 
 
141
            
175
142
 
176
143
def builtin_command_names():
177
 
    """Return list of builtin command names.
178
 
    
179
 
    Use of all_command_names() is encouraged rather than builtin_command_names
180
 
    and/or plugin_command_names.
181
 
    """
 
144
    """Return list of builtin command names."""
182
145
    return _builtin_commands().keys()
183
 
 
 
146
    
184
147
 
185
148
def plugin_command_names():
186
 
    """Returns command names from commands registered by plugins."""
187
149
    return plugin_cmds.keys()
188
150
 
189
151
 
 
152
def _get_cmd_dict(plugins_override=True):
 
153
    """Return name->class mapping for all commands."""
 
154
    d = _builtin_commands()
 
155
    if plugins_override:
 
156
        d.update(plugin_cmds.iteritems())
 
157
    return d
 
158
 
 
159
    
 
160
def get_all_cmds(plugins_override=True):
 
161
    """Return canonical name and class for all registered commands."""
 
162
    for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
 
163
        yield k,v
 
164
 
 
165
 
190
166
def get_cmd_object(cmd_name, plugins_override=True):
191
 
    """Return the command object for a command.
 
167
    """Return the canonical name and command class for a command.
192
168
 
193
169
    plugins_override
194
170
        If true, plugin commands can override builtins.
199
175
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
200
176
 
201
177
 
202
 
def _get_cmd_object(cmd_name, plugins_override=True, check_missing=True):
203
 
    """Get a command object.
 
178
def _get_cmd_object(cmd_name, plugins_override=True):
 
179
    """Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
 
180
    from bzrlib.externalcommand import ExternalCommand
204
181
 
205
 
    :param cmd_name: The name of the command.
206
 
    :param plugins_override: Allow plugins to override builtins.
207
 
    :param check_missing: Look up commands not found in the regular index via
208
 
        the get_missing_command hook.
209
 
    :return: A Command object instance
210
 
    :raises KeyError: If no command is found.
211
 
    """
212
182
    # We want only 'ascii' command names, but the user may have typed
213
183
    # in a Unicode name. In that case, they should just get a
214
184
    # 'command not found' error later.
215
185
    # In the future, we may actually support Unicode command names.
216
 
    cmd = None
217
 
    # Get a command
218
 
    for hook in Command.hooks['get_command']:
219
 
        cmd = hook(cmd, cmd_name)
220
 
        if cmd is not None and not plugins_override and not cmd.plugin_name():
221
 
            # We've found a non-plugin command, don't permit it to be
222
 
            # overridden.
223
 
            break
224
 
    if cmd is None and check_missing:
225
 
        for hook in Command.hooks['get_missing_command']:
226
 
            cmd = hook(cmd_name)
227
 
            if cmd is not None:
228
 
                break
229
 
    if cmd is None:
230
 
        # No command found.
231
 
        raise KeyError
232
 
    # Allow plugins to extend commands
233
 
    for hook in Command.hooks['extend_command']:
234
 
        hook(cmd)
235
 
    return cmd
236
 
 
237
 
 
238
 
def _try_plugin_provider(cmd_name):
239
 
    """Probe for a plugin provider having cmd_name."""
240
 
    try:
241
 
        plugin_metadata, provider = probe_for_provider(cmd_name)
242
 
        raise errors.CommandAvailableInPlugin(cmd_name,
243
 
            plugin_metadata, provider)
244
 
    except errors.NoPluginAvailable:
245
 
        pass
246
 
 
247
 
 
248
 
def probe_for_provider(cmd_name):
249
 
    """Look for a provider for cmd_name.
250
 
 
251
 
    :param cmd_name: The command name.
252
 
    :return: plugin_metadata, provider for getting cmd_name.
253
 
    :raises NoPluginAvailable: When no provider can supply the plugin.
254
 
    """
255
 
    # look for providers that provide this command but aren't installed
256
 
    for provider in command_providers_registry:
 
186
 
 
187
    # first look up this command under the specified name
 
188
    if plugins_override:
257
189
        try:
258
 
            return provider.plugin_for_command(cmd_name), provider
259
 
        except errors.NoPluginAvailable:
 
190
            return plugin_cmds.get(cmd_name)()
 
191
        except KeyError:
260
192
            pass
261
 
    raise errors.NoPluginAvailable(cmd_name)
262
 
 
263
 
 
264
 
def _get_bzr_command(cmd_or_None, cmd_name):
265
 
    """Get a command from bzr's core."""
266
 
    cmds = _builtin_commands()
 
193
    cmds = _get_cmd_dict(plugins_override=False)
267
194
    try:
268
195
        return cmds[cmd_name]()
269
196
    except KeyError:
270
197
        pass
 
198
    if plugins_override:
 
199
        for key in plugin_cmds.keys():
 
200
            info = plugin_cmds.get_info(key)
 
201
            if cmd_name in info.aliases:
 
202
                return plugin_cmds.get(key)()
271
203
    # look for any command which claims this as an alias
272
204
    for real_cmd_name, cmd_class in cmds.iteritems():
273
205
        if cmd_name in cmd_class.aliases:
274
206
            return cmd_class()
275
 
    return cmd_or_None
276
 
 
277
 
 
278
 
def _get_external_command(cmd_or_None, cmd_name):
279
 
    """Lookup a command that is a shell script."""
280
 
    # Only do external command lookups when no command is found so far.
281
 
    if cmd_or_None is not None:
282
 
        return cmd_or_None
283
 
    from bzrlib.externalcommand import ExternalCommand
 
207
 
284
208
    cmd_obj = ExternalCommand.find_command(cmd_name)
285
209
    if cmd_obj:
286
210
        return cmd_obj
287
211
 
 
212
    # look for plugins that provide this command but aren't installed
 
213
    for provider in command_providers_registry:
 
214
        try:
 
215
            plugin_metadata = provider.plugin_for_command(cmd_name)
 
216
        except errors.NoPluginAvailable:
 
217
            pass
 
218
        else:
 
219
            raise errors.CommandAvailableInPlugin(cmd_name, 
 
220
                                                  plugin_metadata, provider)
288
221
 
289
 
def _get_plugin_command(cmd_or_None, cmd_name):
290
 
    """Get a command from bzr's plugins."""
291
 
    try:
292
 
        return plugin_cmds.get(cmd_name)()
293
 
    except KeyError:
294
 
        pass
295
 
    for key in plugin_cmds.keys():
296
 
        info = plugin_cmds.get_info(key)
297
 
        if cmd_name in info.aliases:
298
 
            return plugin_cmds.get(key)()
299
 
    return cmd_or_None
 
222
    raise KeyError
300
223
 
301
224
 
302
225
class Command(object):
356
279
            sys.stdout is forced to be a binary stream, and line-endings
357
280
            will not mangled.
358
281
 
359
 
    :cvar hooks: An instance of CommandHooks.
360
282
    """
361
283
    aliases = []
362
284
    takes_args = []
364
286
    encoding_type = 'strict'
365
287
 
366
288
    hidden = False
367
 
 
 
289
    
368
290
    def __init__(self):
369
291
        """Construct an instance of this command."""
370
292
        if self.__doc__ == Command.__doc__:
371
293
            warn("No help message set for %r" % self)
372
294
        # List of standard options directly supported
373
295
        self.supported_std_options = []
374
 
        self._operation = cleanup.OperationWithCleanups(self.run)
375
 
 
376
 
    def add_cleanup(self, cleanup_func, *args, **kwargs):
377
 
        """Register a function to call after self.run returns or raises.
378
 
 
379
 
        Functions will be called in LIFO order.
380
 
        """
381
 
        self._operation.add_cleanup(cleanup_func, *args, **kwargs)
382
 
 
383
 
    def cleanup_now(self):
384
 
        """Execute and empty pending cleanup functions immediately.
385
 
 
386
 
        After cleanup_now all registered cleanups are forgotten.  add_cleanup
387
 
        may be called again after cleanup_now; these cleanups will be called
388
 
        after self.run returns or raises (or when cleanup_now is next called).
389
 
 
390
 
        This is useful for releasing expensive or contentious resources (such
391
 
        as write locks) before doing further work that does not require those
392
 
        resources (such as writing results to self.outf).
393
 
        """
394
 
        self._operation.cleanup_now()
395
 
 
396
 
    @deprecated_method(deprecated_in((2, 1, 0)))
 
296
 
397
297
    def _maybe_expand_globs(self, file_list):
398
298
        """Glob expand file_list if the platform does not do that itself.
399
 
 
400
 
        Not used anymore, now that the bzr command-line parser globs on
401
 
        Windows.
402
 
 
 
299
        
403
300
        :return: A possibly empty list of unicode paths.
404
301
 
405
302
        Introduced in bzrlib 0.18.
406
303
        """
407
 
        return file_list
 
304
        if not file_list:
 
305
            file_list = []
 
306
        if sys.platform == 'win32':
 
307
            file_list = win32utils.glob_expand(file_list)
 
308
        return list(file_list)
408
309
 
409
310
    def _usage(self):
410
311
        """Return single-line grammar for this command.
425
326
        return s
426
327
 
427
328
    def get_help_text(self, additional_see_also=None, plain=True,
428
 
                      see_also_as_links=False, verbose=True):
 
329
                      see_also_as_links=False):
429
330
        """Return a text string with help for this command.
430
 
 
 
331
        
431
332
        :param additional_see_also: Additional help topics to be
432
333
            cross-referenced.
433
334
        :param plain: if False, raw help (reStructuredText) is
434
335
            returned instead of plain text.
435
336
        :param see_also_as_links: if True, convert items in 'See also'
436
337
            list to internal links (used by bzr_man rstx generator)
437
 
        :param verbose: if True, display the full help, otherwise
438
 
            leave out the descriptive sections and just display
439
 
            usage help (e.g. Purpose, Usage, Options) with a
440
 
            message explaining how to obtain full help.
441
338
        """
442
339
        doc = self.help()
443
340
        if doc is None:
444
341
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
445
342
 
446
343
        # Extract the summary (purpose) and sections out from the text
447
 
        purpose,sections,order = self._get_help_parts(doc)
 
344
        purpose,sections = self._get_help_parts(doc)
448
345
 
449
346
        # If a custom usage section was provided, use it
450
347
        if sections.has_key('Usage'):
462
359
        result += '\n'
463
360
 
464
361
        # Add the options
465
 
        #
466
 
        # XXX: optparse implicitly rewraps the help, and not always perfectly,
467
 
        # so we get <https://bugs.launchpad.net/bzr/+bug/249908>.  -- mbp
468
 
        # 20090319
469
362
        options = option.get_optparser(self.options()).format_option_help()
470
 
        # XXX: According to the spec, ReST option lists actually don't support 
471
 
        # options like --1.9 so that causes syntax errors (in Sphinx at least).
472
 
        # As that pattern always appears in the commands that break, we trap
473
 
        # on that and then format that block of 'format' options as a literal
474
 
        # block.
475
 
        if not plain and options.find('  --1.9  ') != -1:
476
 
            options = options.replace(' format:\n', ' format::\n\n', 1)
477
363
        if options.startswith('Options:'):
478
364
            result += ':' + options
479
365
        elif options.startswith('options:'):
483
369
            result += options
484
370
        result += '\n'
485
371
 
486
 
        if verbose:
487
 
            # Add the description, indenting it 2 spaces
488
 
            # to match the indentation of the options
489
 
            if sections.has_key(None):
490
 
                text = sections.pop(None)
491
 
                text = '\n  '.join(text.splitlines())
492
 
                result += ':%s:\n  %s\n\n' % ('Description',text)
 
372
        # Add the description, indenting it 2 spaces
 
373
        # to match the indentation of the options
 
374
        if sections.has_key(None):
 
375
            text = sections.pop(None)
 
376
            text = '\n  '.join(text.splitlines())
 
377
            result += ':%s:\n  %s\n\n' % ('Description',text)
493
378
 
494
 
            # Add the custom sections (e.g. Examples). Note that there's no need
495
 
            # to indent these as they must be indented already in the source.
496
 
            if sections:
497
 
                for label in order:
498
 
                    if sections.has_key(label):
499
 
                        result += ':%s:\n%s\n' % (label,sections[label])
500
 
                result += '\n'
501
 
        else:
502
 
            result += ("See bzr help %s for more details and examples.\n\n"
503
 
                % self.name())
 
379
        # Add the custom sections (e.g. Examples). Note that there's no need
 
380
        # to indent these as they must be indented already in the source.
 
381
        if sections:
 
382
            labels = sorted(sections.keys())
 
383
            for label in labels:
 
384
                result += ':%s:\n%s\n\n' % (label,sections[label])
504
385
 
505
386
        # Add the aliases, source (plug-in) and see also links, if any
506
387
        if self.aliases:
519
400
                        # so don't create a real link
520
401
                        see_also_links.append(item)
521
402
                    else:
522
 
                        # Use a Sphinx link for this entry
523
 
                        link_text = ":doc:`%s <%s-help>`" % (item, item)
524
 
                        see_also_links.append(link_text)
 
403
                        # Use a reST link for this entry
 
404
                        see_also_links.append("`%s`_" % (item,))
525
405
                see_also = see_also_links
526
406
            result += ':See also: '
527
407
            result += ', '.join(see_also) + '\n'
536
416
    def _get_help_parts(text):
537
417
        """Split help text into a summary and named sections.
538
418
 
539
 
        :return: (summary,sections,order) where summary is the top line and
 
419
        :return: (summary,sections) where summary is the top line and
540
420
            sections is a dictionary of the rest indexed by section name.
541
 
            order is the order the section appear in the text.
542
421
            A section starts with a heading line of the form ":xxx:".
543
422
            Indented text on following lines is the section value.
544
423
            All text found outside a named section is assigned to the
545
424
            default section which is given the key of None.
546
425
        """
547
 
        def save_section(sections, order, label, section):
 
426
        def save_section(sections, label, section):
548
427
            if len(section) > 0:
549
428
                if sections.has_key(label):
550
429
                    sections[label] += '\n' + section
551
430
                else:
552
 
                    order.append(label)
553
431
                    sections[label] = section
554
432
 
555
433
        lines = text.rstrip().splitlines()
556
434
        summary = lines.pop(0)
557
435
        sections = {}
558
 
        order = []
559
436
        label,section = None,''
560
437
        for line in lines:
561
438
            if line.startswith(':') and line.endswith(':') and len(line) > 2:
562
 
                save_section(sections, order, label, section)
 
439
                save_section(sections, label, section)
563
440
                label,section = line[1:-1],''
564
441
            elif (label is not None) and len(line) > 1 and not line[0].isspace():
565
 
                save_section(sections, order, label, section)
 
442
                save_section(sections, label, section)
566
443
                label,section = None,line
567
444
            else:
568
445
                if len(section) > 0:
569
446
                    section += '\n' + line
570
447
                else:
571
448
                    section = line
572
 
        save_section(sections, order, label, section)
573
 
        return summary, sections, order
 
449
        save_section(sections, label, section)
 
450
        return summary, sections
574
451
 
575
452
    def get_help_topic(self):
576
453
        """Return the commands help topic - its name."""
578
455
 
579
456
    def get_see_also(self, additional_terms=None):
580
457
        """Return a list of help topics that are related to this command.
581
 
 
 
458
        
582
459
        The list is derived from the content of the _see_also attribute. Any
583
460
        duplicates are removed and the result is in lexical order.
584
461
        :param additional_terms: Additional help topics to cross-reference.
605
482
 
606
483
    def _setup_outf(self):
607
484
        """Return a file linked to stdout, which has proper encoding."""
608
 
        self.outf = ui.ui_factory.make_output_stream(
609
 
            encoding_type=self.encoding_type)
 
485
        # Originally I was using self.stdout, but that looks
 
486
        # *way* too much like sys.stdout
 
487
        if self.encoding_type == 'exact':
 
488
            # force sys.stdout to be binary stream on win32
 
489
            if sys.platform == 'win32':
 
490
                fileno = getattr(sys.stdout, 'fileno', None)
 
491
                if fileno:
 
492
                    import msvcrt
 
493
                    msvcrt.setmode(fileno(), os.O_BINARY)
 
494
            self.outf = sys.stdout
 
495
            return
 
496
 
 
497
        output_encoding = osutils.get_terminal_encoding()
 
498
 
 
499
        self.outf = codecs.getwriter(output_encoding)(sys.stdout,
 
500
                        errors=self.encoding_type)
 
501
        # For whatever reason codecs.getwriter() does not advertise its encoding
 
502
        # it just returns the encoding of the wrapped file, which is completely
 
503
        # bogus. So set the attribute, so we can find the correct encoding later.
 
504
        self.outf.encoding = output_encoding
610
505
 
611
506
    def run_argv_aliases(self, argv, alias_argv=None):
612
507
        """Parse the command line and run with extra aliases in alias_argv."""
 
508
        if argv is None:
 
509
            warn("Passing None for [] is deprecated from bzrlib 0.10",
 
510
                 DeprecationWarning, stacklevel=2)
 
511
            argv = []
613
512
        args, opts = parse_args(self, argv, alias_argv)
614
513
 
615
514
        # Process the standard options
616
515
        if 'help' in opts:  # e.g. bzr add --help
617
516
            sys.stdout.write(self.get_help_text())
618
517
            return 0
619
 
        if 'usage' in opts:  # e.g. bzr add --usage
620
 
            sys.stdout.write(self.get_help_text(verbose=False))
621
 
            return 0
622
518
        trace.set_verbosity_level(option._verbosity_level)
623
519
        if 'verbose' in self.supported_std_options:
624
520
            opts['verbose'] = trace.is_verbose()
640
536
 
641
537
        self._setup_outf()
642
538
 
643
 
        return self.run_direct(**all_cmd_args)
644
 
 
645
 
    def run_direct(self, *args, **kwargs):
646
 
        """Call run directly with objects (without parsing an argv list)."""
647
 
        return self._operation.run_simple(*args, **kwargs)
 
539
        return self.run(**all_cmd_args)
648
540
 
649
541
    def run(self):
650
542
        """Actually run the command.
681
573
            return None
682
574
 
683
575
 
684
 
class CommandHooks(Hooks):
685
 
    """Hooks related to Command object creation/enumeration."""
686
 
 
687
 
    def __init__(self):
688
 
        """Create the default hooks.
689
 
 
690
 
        These are all empty initially, because by default nothing should get
691
 
        notified.
692
 
        """
693
 
        Hooks.__init__(self)
694
 
        self.create_hook(HookPoint('extend_command',
695
 
            "Called after creating a command object to allow modifications "
696
 
            "such as adding or removing options, docs etc. Called with the "
697
 
            "new bzrlib.commands.Command object.", (1, 13), None))
698
 
        self.create_hook(HookPoint('get_command',
699
 
            "Called when creating a single command. Called with "
700
 
            "(cmd_or_None, command_name). get_command should either return "
701
 
            "the cmd_or_None parameter, or a replacement Command object that "
702
 
            "should be used for the command. Note that the Command.hooks "
703
 
            "hooks are core infrastructure. Many users will prefer to use "
704
 
            "bzrlib.commands.register_command or plugin_cmds.register_lazy.",
705
 
            (1, 17), None))
706
 
        self.create_hook(HookPoint('get_missing_command',
707
 
            "Called when creating a single command if no command could be "
708
 
            "found. Called with (command_name). get_missing_command should "
709
 
            "either return None, or a Command object to be used for the "
710
 
            "command.", (1, 17), None))
711
 
        self.create_hook(HookPoint('list_commands',
712
 
            "Called when enumerating commands. Called with a set of "
713
 
            "cmd_name strings for all the commands found so far. This set "
714
 
            " is safe to mutate - e.g. to remove a command. "
715
 
            "list_commands should return the updated set of command names.",
716
 
            (1, 17), None))
717
 
 
718
 
Command.hooks = CommandHooks()
719
 
 
720
 
 
721
576
def parse_args(command, argv, alias_argv=None):
722
577
    """Parse command line.
723
 
 
 
578
    
724
579
    Arguments and options are parsed at this level before being passed
725
580
    down to specific command handlers.  This routine knows, from a
726
581
    lookup table, something about the available options, what optargs
775
630
                               % (cmd, argname.upper()))
776
631
            else:
777
632
                argdict[argname] = args.pop(0)
778
 
 
 
633
            
779
634
    if args:
780
635
        raise errors.BzrCommandError("extra argument to command %s: %s"
781
636
                                     % (cmd, args[0]))
789
644
 
790
645
    tracer = trace.Trace(count=1, trace=0)
791
646
    sys.settrace(tracer.globaltrace)
792
 
    threading.settrace(tracer.globaltrace)
793
 
 
794
 
    try:
795
 
        return exception_to_return_code(the_callable, *args, **kwargs)
796
 
    finally:
797
 
        sys.settrace(None)
798
 
        results = tracer.results()
799
 
        results.write_results(show_missing=1, summary=False,
800
 
                              coverdir=dirname)
 
647
 
 
648
    ret = the_callable(*args, **kwargs)
 
649
 
 
650
    sys.settrace(None)
 
651
    results = tracer.results()
 
652
    results.write_results(show_missing=1, summary=False,
 
653
                          coverdir=dirname)
801
654
 
802
655
 
803
656
def apply_profiled(the_callable, *args, **kwargs):
808
661
    try:
809
662
        prof = hotshot.Profile(pfname)
810
663
        try:
811
 
            ret = prof.runcall(exception_to_return_code, the_callable, *args,
812
 
                **kwargs) or 0
 
664
            ret = prof.runcall(the_callable, *args, **kwargs) or 0
813
665
        finally:
814
666
            prof.close()
815
667
        stats = hotshot.stats.load(pfname)
824
676
        os.remove(pfname)
825
677
 
826
678
 
827
 
def exception_to_return_code(the_callable, *args, **kwargs):
828
 
    """UI level helper for profiling and coverage.
829
 
 
830
 
    This transforms exceptions into a return value of 3. As such its only
831
 
    relevant to the UI layer, and should never be called where catching
832
 
    exceptions may be desirable.
833
 
    """
834
 
    try:
835
 
        return the_callable(*args, **kwargs)
836
 
    except (KeyboardInterrupt, Exception), e:
837
 
        # used to handle AssertionError and KeyboardInterrupt
838
 
        # specially here, but hopefully they're handled ok by the logger now
839
 
        exc_info = sys.exc_info()
840
 
        exitcode = trace.report_exception(exc_info, sys.stderr)
841
 
        if os.environ.get('BZR_PDB'):
842
 
            print '**** entering debugger'
843
 
            tb = exc_info[2]
844
 
            import pdb
845
 
            if sys.version_info[:2] < (2, 6):
846
 
                # XXX: we want to do
847
 
                #    pdb.post_mortem(tb)
848
 
                # but because pdb.post_mortem gives bad results for tracebacks
849
 
                # from inside generators, we do it manually.
850
 
                # (http://bugs.python.org/issue4150, fixed in Python 2.6)
851
 
 
852
 
                # Setup pdb on the traceback
853
 
                p = pdb.Pdb()
854
 
                p.reset()
855
 
                p.setup(tb.tb_frame, tb)
856
 
                # Point the debugger at the deepest frame of the stack
857
 
                p.curindex = len(p.stack) - 1
858
 
                p.curframe = p.stack[p.curindex][0]
859
 
                # Start the pdb prompt.
860
 
                p.print_stack_entry(p.stack[p.curindex])
861
 
                p.execRcLines()
862
 
                p.cmdloop()
863
 
            else:
864
 
                pdb.post_mortem(tb)
865
 
        return exitcode
866
 
 
867
 
 
868
679
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
869
680
    from bzrlib.lsprof import profile
870
 
    ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
 
681
    ret, stats = profile(the_callable, *args, **kwargs)
871
682
    stats.sort()
872
683
    if filename is None:
873
684
        stats.pprint()
877
688
    return ret
878
689
 
879
690
 
880
 
@deprecated_function(deprecated_in((2, 2, 0)))
881
691
def shlex_split_unicode(unsplit):
882
 
    return cmdline.split(unsplit)
 
692
    import shlex
 
693
    return [u.decode('utf-8') for u in shlex.split(unsplit.encode('utf-8'))]
883
694
 
884
695
 
885
696
def get_alias(cmd, config=None):
897
708
        config = bzrlib.config.GlobalConfig()
898
709
    alias = config.get_alias(cmd)
899
710
    if (alias):
900
 
        return cmdline.split(alias)
 
711
        return shlex_split_unicode(alias)
901
712
    return None
902
713
 
903
714
 
904
 
def run_bzr(argv, load_plugins=load_plugins, disable_plugins=disable_plugins):
 
715
def run_bzr(argv):
905
716
    """Execute a command.
906
717
 
907
 
    :param argv: The command-line arguments, without the program name from
908
 
        argv[0] These should already be decoded. All library/test code calling
909
 
        run_bzr should be passing valid strings (don't need decoding).
910
 
    :param load_plugins: What function to call when triggering plugin loading.
911
 
        This function should take no arguments and cause all plugins to be
912
 
        loaded.
913
 
    :param disable_plugins: What function to call when disabling plugin
914
 
        loading. This function should take no arguments and cause all plugin
915
 
        loading to be prohibited (so that code paths in your application that
916
 
        know about some plugins possibly being present will fail to import
917
 
        those plugins even if they are installed.)
918
 
    :return: Returns a command exit code or raises an exception.
 
718
    argv
 
719
       The command-line arguments, without the program name from argv[0]
 
720
       These should already be decoded. All library/test code calling
 
721
       run_bzr should be passing valid strings (don't need decoding).
 
722
    
 
723
    Returns a command status or raises an exception.
919
724
 
920
725
    Special master options: these must come before the command because
921
726
    they control how the command is interpreted.
938
743
 
939
744
    --coverage
940
745
        Generate line coverage report in the specified directory.
941
 
 
942
 
    --concurrency
943
 
        Specify the number of processes that can be run concurrently (selftest).
944
746
    """
945
 
    trace.mutter("bazaar version: " + bzrlib.__version__)
946
747
    argv = list(argv)
947
748
    trace.mutter("bzr arguments: %r", argv)
948
749
 
972
773
            opt_no_aliases = True
973
774
        elif a == '--builtin':
974
775
            opt_builtin = True
975
 
        elif a == '--concurrency':
976
 
            os.environ['BZR_CONCURRENCY'] = argv[i + 1]
977
 
            i += 1
978
776
        elif a == '--coverage':
979
777
            opt_coverage_dir = argv[i + 1]
980
778
            i += 1
984
782
            argv_copy.append(a)
985
783
        i += 1
986
784
 
987
 
    debug.set_debug_flags_from_config()
 
785
    argv = argv_copy
 
786
    if (not argv):
 
787
        from bzrlib.builtins import cmd_help
 
788
        cmd_help().run_argv_aliases([])
 
789
        return 0
 
790
 
 
791
    if argv[0] == '--version':
 
792
        from bzrlib.builtins import cmd_version
 
793
        cmd_version().run_argv_aliases([])
 
794
        return 0
988
795
 
989
796
    if not opt_no_plugins:
 
797
        from bzrlib.plugin import load_plugins
990
798
        load_plugins()
991
799
    else:
 
800
        from bzrlib.plugin import disable_plugins
992
801
        disable_plugins()
993
802
 
994
 
    argv = argv_copy
995
 
    if (not argv):
996
 
        get_cmd_object('help').run_argv_aliases([])
997
 
        return 0
998
 
 
999
 
    if argv[0] == '--version':
1000
 
        get_cmd_object('version').run_argv_aliases([])
1001
 
        return 0
1002
 
 
1003
803
    alias_argv = None
1004
804
 
1005
805
    if not opt_no_aliases:
1037
837
            ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
1038
838
        else:
1039
839
            ret = run(*run_argv)
 
840
        if 'memory' in debug.debug_flags:
 
841
            trace.debug_memory('Process status after command:', short=False)
1040
842
        return ret or 0
1041
843
    finally:
1042
844
        # reset, in case we may do other commands later within the same
1043
845
        # process. Commands that want to execute sub-commands must propagate
1044
846
        # --verbose in their own way.
1045
 
        if 'memory' in debug.debug_flags:
1046
 
            trace.debug_memory('Process status after command:', short=False)
1047
847
        option._verbosity_level = saved_verbosity_level
1048
848
 
1049
 
 
1050
849
def display_command(func):
1051
850
    """Decorator that suppresses pipe/interrupt errors."""
1052
851
    def ignore_pipe(*args, **kwargs):
1067
866
    return ignore_pipe
1068
867
 
1069
868
 
1070
 
def install_bzr_command_hooks():
1071
 
    """Install the hooks to supply bzr's own commands."""
1072
 
    if _list_bzr_commands in Command.hooks["list_commands"]:
1073
 
        return
1074
 
    Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
1075
 
        "bzr commands")
1076
 
    Command.hooks.install_named_hook("get_command", _get_bzr_command,
1077
 
        "bzr commands")
1078
 
    Command.hooks.install_named_hook("get_command", _get_plugin_command,
1079
 
        "bzr plugin commands")
1080
 
    Command.hooks.install_named_hook("get_command", _get_external_command,
1081
 
        "bzr external command lookup")
1082
 
    Command.hooks.install_named_hook("get_missing_command", _try_plugin_provider,
1083
 
        "bzr plugin-provider-db check")
1084
 
 
1085
 
 
1086
 
 
1087
 
def _specified_or_unicode_argv(argv):
1088
 
    # For internal or testing use, argv can be passed.  Otherwise, get it from
1089
 
    # the process arguments in a unicode-safe way.
1090
 
    if argv is None:
1091
 
        return osutils.get_unicode_argv()
1092
 
    else:
1093
 
        new_argv = []
1094
 
        try:
1095
 
            # ensure all arguments are unicode strings
1096
 
            for a in argv[1:]:
1097
 
                if isinstance(a, unicode):
1098
 
                    new_argv.append(a)
1099
 
                else:
1100
 
                    new_argv.append(a.decode('ascii'))
1101
 
        except UnicodeDecodeError:
1102
 
            raise errors.BzrError("argv should be list of unicode strings.")
1103
 
        return new_argv
1104
 
 
1105
 
 
1106
 
def main(argv=None):
1107
 
    """Main entry point of command-line interface.
1108
 
 
1109
 
    Typically `bzrlib.initialize` should be called first.
1110
 
 
1111
 
    :param argv: list of unicode command-line arguments similar to sys.argv.
1112
 
        argv[0] is script name usually, it will be ignored.
1113
 
        Don't pass here sys.argv because this list contains plain strings
1114
 
        and not unicode; pass None instead.
1115
 
 
1116
 
    :return: exit code of bzr command.
1117
 
    """
1118
 
    argv = _specified_or_unicode_argv(argv)
 
869
def main(argv):
 
870
    import bzrlib.ui
 
871
    from bzrlib.ui.text import TextUIFactory
 
872
    bzrlib.ui.ui_factory = TextUIFactory()
 
873
 
 
874
    # Is this a final release version? If so, we should suppress warnings
 
875
    if bzrlib.version_info[3] == 'final':
 
876
        from bzrlib import symbol_versioning
 
877
        symbol_versioning.suppress_deprecation_warnings(override=False)
 
878
    try:
 
879
        user_encoding = osutils.get_user_encoding()
 
880
        argv = [a.decode(user_encoding) for a in argv[1:]]
 
881
    except UnicodeDecodeError:
 
882
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
 
883
                                                            "encoding." % a))
1119
884
    ret = run_bzr_catch_errors(argv)
1120
 
    bzrlib.ui.ui_factory.log_transport_activity(
1121
 
        display=('bytes' in debug.debug_flags))
1122
885
    trace.mutter("return code %d", ret)
1123
886
    return ret
1124
887
 
1125
888
 
1126
889
def run_bzr_catch_errors(argv):
1127
 
    """Run a bzr command with parameters as described by argv.
1128
 
 
1129
 
    This function assumed that that UI layer is setup, that symbol deprecations
1130
 
    are already applied, and that unicode decoding has already been performed on argv.
1131
 
    """
1132
 
    # done here so that they're covered for every test run
1133
 
    install_bzr_command_hooks()
1134
 
    return exception_to_return_code(run_bzr, argv)
 
890
    # Note: The except clause logic below should be kept in sync with the
 
891
    # profile() routine in lsprof.py.
 
892
    try:
 
893
        return run_bzr(argv)
 
894
    except (KeyboardInterrupt, Exception), e:
 
895
        # used to handle AssertionError and KeyboardInterrupt
 
896
        # specially here, but hopefully they're handled ok by the logger now
 
897
        exitcode = trace.report_exception(sys.exc_info(), sys.stderr)
 
898
        if os.environ.get('BZR_PDB'):
 
899
            print '**** entering debugger'
 
900
            import pdb
 
901
            pdb.post_mortem(sys.exc_traceback)
 
902
        return exitcode
1135
903
 
1136
904
 
1137
905
def run_bzr_catch_user_errors(argv):
1140
908
    This is used for the test suite, and might be useful for other programs
1141
909
    that want to wrap the commandline interface.
1142
910
    """
1143
 
    # done here so that they're covered for every test run
1144
 
    install_bzr_command_hooks()
1145
911
    try:
1146
912
        return run_bzr(argv)
1147
913
    except Exception, e:
1169
935
        if topic and topic.startswith(self.prefix):
1170
936
            topic = topic[len(self.prefix):]
1171
937
        try:
1172
 
            cmd = _get_cmd_object(topic, check_missing=False)
 
938
            cmd = _get_cmd_object(topic)
1173
939
        except KeyError:
1174
940
            return []
1175
941
        else:
1181
947
 
1182
948
    def plugin_for_command(self, cmd_name):
1183
949
        '''Takes a command and returns the information for that plugin
1184
 
 
1185
 
        :return: A dictionary with all the available information
 
950
        
 
951
        :return: A dictionary with all the available information 
1186
952
        for the requested plugin
1187
953
        '''
1188
954
        raise NotImplementedError
1196
962
            yield provider
1197
963
 
1198
964
command_providers_registry = ProvidersRegistry()
 
965
 
 
966
 
 
967
if __name__ == '__main__':
 
968
    sys.exit(main(sys.argv))