~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Robert Collins
  • Date: 2009-02-06 03:47:05 UTC
  • mto: This revision was merged to the branch mainline in revision 3987.
  • Revision ID: robertc@robertcollins.net-20090206034705-i3xvyq06qi5svxjd
Fix bug 319790 - unshelve of deleted paths failing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2008, 2009 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
42
    debug,
45
43
    errors,
46
44
    option,
47
45
    osutils,
48
46
    trace,
49
 
    ui,
50
47
    win32utils,
51
48
    )
52
49
""")
53
50
 
54
 
from bzrlib.hooks import HookPoint, Hooks
55
 
# Compatibility - Option used to be in commands.
 
51
from bzrlib import registry
 
52
# Compatibility
56
53
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
54
 
65
55
 
66
56
class CommandInfo(object):
104
94
            registry.Registry.register(self, k_unsquished, cmd,
105
95
                                       override_existing=decorate, info=info)
106
96
        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__])
 
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__])
112
102
        return previous
113
103
 
114
104
    def register_lazy(self, command_name, aliases, module_name):
141
131
 
142
132
def _builtin_commands():
143
133
    import bzrlib.builtins
144
 
    return _scan_module_for_commands(bzrlib.builtins)
145
 
 
146
 
 
147
 
def _scan_module_for_commands(module):
148
134
    r = {}
149
 
    for name, obj in module.__dict__.iteritems():
 
135
    builtins = bzrlib.builtins.__dict__
 
136
    for name in builtins:
150
137
        if name.startswith("cmd_"):
151
138
            real_name = _unsquish_command_name(name)
152
 
            r[real_name] = obj
 
139
            r[real_name] = builtins[name]
153
140
    return r
154
 
 
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
 
 
 
141
            
174
142
 
175
143
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
 
    """
 
144
    """Return list of builtin command names."""
181
145
    return _builtin_commands().keys()
182
 
 
 
146
    
183
147
 
184
148
def plugin_command_names():
185
 
    """Returns command names from commands registered by plugins."""
186
149
    return plugin_cmds.keys()
187
150
 
188
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
 
189
166
def get_cmd_object(cmd_name, plugins_override=True):
190
 
    """Return the command object for a command.
 
167
    """Return the canonical name and command class for a command.
191
168
 
192
169
    plugins_override
193
170
        If true, plugin commands can override builtins.
199
176
 
200
177
 
201
178
def _get_cmd_object(cmd_name, plugins_override=True):
202
 
    """Get a command object.
 
179
    """Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
 
180
    from bzrlib.externalcommand import ExternalCommand
203
181
 
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
182
    # We want only 'ascii' command names, but the user may have typed
210
183
    # in a Unicode name. In that case, they should just get a
211
184
    # 'command not found' error later.
212
185
    # 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:
 
186
 
 
187
    # first look up this command under the specified name
 
188
    if plugins_override:
254
189
        try:
255
 
            return provider.plugin_for_command(cmd_name), provider
256
 
        except errors.NoPluginAvailable:
 
190
            return plugin_cmds.get(cmd_name)()
 
191
        except KeyError:
257
192
            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()
 
193
    cmds = _get_cmd_dict(plugins_override=False)
264
194
    try:
265
195
        return cmds[cmd_name]()
266
196
    except KeyError:
267
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)()
268
203
    # look for any command which claims this as an alias
269
204
    for real_cmd_name, cmd_class in cmds.iteritems():
270
205
        if cmd_name in cmd_class.aliases:
271
206
            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
 
207
 
281
208
    cmd_obj = ExternalCommand.find_command(cmd_name)
282
209
    if cmd_obj:
283
210
        return cmd_obj
284
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)
285
221
 
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
 
222
    raise KeyError
297
223
 
298
224
 
299
225
class Command(object):
353
279
            sys.stdout is forced to be a binary stream, and line-endings
354
280
            will not mangled.
355
281
 
356
 
    :cvar hooks: An instance of CommandHooks.
357
282
    """
358
283
    aliases = []
359
284
    takes_args = []
361
286
    encoding_type = 'strict'
362
287
 
363
288
    hidden = False
364
 
 
 
289
    
365
290
    def __init__(self):
366
291
        """Construct an instance of this command."""
367
292
        if self.__doc__ == Command.__doc__:
368
293
            warn("No help message set for %r" % self)
369
294
        # List of standard options directly supported
370
295
        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)))
 
296
 
394
297
    def _maybe_expand_globs(self, file_list):
395
298
        """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
 
 
 
299
        
400
300
        :return: A possibly empty list of unicode paths.
401
301
 
402
302
        Introduced in bzrlib 0.18.
403
303
        """
404
 
        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)
405
309
 
406
310
    def _usage(self):
407
311
        """Return single-line grammar for this command.
422
326
        return s
423
327
 
424
328
    def get_help_text(self, additional_see_also=None, plain=True,
425
 
                      see_also_as_links=False, verbose=True):
 
329
                      see_also_as_links=False):
426
330
        """Return a text string with help for this command.
427
 
 
 
331
        
428
332
        :param additional_see_also: Additional help topics to be
429
333
            cross-referenced.
430
334
        :param plain: if False, raw help (reStructuredText) is
431
335
            returned instead of plain text.
432
336
        :param see_also_as_links: if True, convert items in 'See also'
433
337
            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
338
        """
439
339
        doc = self.help()
440
340
        if doc is None:
441
341
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
442
342
 
443
343
        # Extract the summary (purpose) and sections out from the text
444
 
        purpose,sections,order = self._get_help_parts(doc)
 
344
        purpose,sections = self._get_help_parts(doc)
445
345
 
446
346
        # If a custom usage section was provided, use it
447
347
        if sections.has_key('Usage'):
459
359
        result += '\n'
460
360
 
461
361
        # 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
362
        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
363
        if options.startswith('Options:'):
475
364
            result += ':' + options
476
365
        elif options.startswith('options:'):
480
369
            result += options
481
370
        result += '\n'
482
371
 
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)
 
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)
490
378
 
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())
 
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])
501
385
 
502
386
        # Add the aliases, source (plug-in) and see also links, if any
503
387
        if self.aliases:
516
400
                        # so don't create a real link
517
401
                        see_also_links.append(item)
518
402
                    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)
 
403
                        # Use a reST link for this entry
 
404
                        see_also_links.append("`%s`_" % (item,))
522
405
                see_also = see_also_links
523
406
            result += ':See also: '
524
407
            result += ', '.join(see_also) + '\n'
533
416
    def _get_help_parts(text):
534
417
        """Split help text into a summary and named sections.
535
418
 
536
 
        :return: (summary,sections,order) where summary is the top line and
 
419
        :return: (summary,sections) where summary is the top line and
537
420
            sections is a dictionary of the rest indexed by section name.
538
 
            order is the order the section appear in the text.
539
421
            A section starts with a heading line of the form ":xxx:".
540
422
            Indented text on following lines is the section value.
541
423
            All text found outside a named section is assigned to the
542
424
            default section which is given the key of None.
543
425
        """
544
 
        def save_section(sections, order, label, section):
 
426
        def save_section(sections, label, section):
545
427
            if len(section) > 0:
546
428
                if sections.has_key(label):
547
429
                    sections[label] += '\n' + section
548
430
                else:
549
 
                    order.append(label)
550
431
                    sections[label] = section
551
432
 
552
433
        lines = text.rstrip().splitlines()
553
434
        summary = lines.pop(0)
554
435
        sections = {}
555
 
        order = []
556
436
        label,section = None,''
557
437
        for line in lines:
558
438
            if line.startswith(':') and line.endswith(':') and len(line) > 2:
559
 
                save_section(sections, order, label, section)
 
439
                save_section(sections, label, section)
560
440
                label,section = line[1:-1],''
561
441
            elif (label is not None) and len(line) > 1 and not line[0].isspace():
562
 
                save_section(sections, order, label, section)
 
442
                save_section(sections, label, section)
563
443
                label,section = None,line
564
444
            else:
565
445
                if len(section) > 0:
566
446
                    section += '\n' + line
567
447
                else:
568
448
                    section = line
569
 
        save_section(sections, order, label, section)
570
 
        return summary, sections, order
 
449
        save_section(sections, label, section)
 
450
        return summary, sections
571
451
 
572
452
    def get_help_topic(self):
573
453
        """Return the commands help topic - its name."""
575
455
 
576
456
    def get_see_also(self, additional_terms=None):
577
457
        """Return a list of help topics that are related to this command.
578
 
 
 
458
        
579
459
        The list is derived from the content of the _see_also attribute. Any
580
460
        duplicates are removed and the result is in lexical order.
581
461
        :param additional_terms: Additional help topics to cross-reference.
602
482
 
603
483
    def _setup_outf(self):
604
484
        """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)
 
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
607
505
 
608
506
    def run_argv_aliases(self, argv, alias_argv=None):
609
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 = []
610
512
        args, opts = parse_args(self, argv, alias_argv)
611
513
 
612
514
        # Process the standard options
613
515
        if 'help' in opts:  # e.g. bzr add --help
614
516
            sys.stdout.write(self.get_help_text())
615
517
            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
518
        trace.set_verbosity_level(option._verbosity_level)
620
519
        if 'verbose' in self.supported_std_options:
621
520
            opts['verbose'] = trace.is_verbose()
637
536
 
638
537
        self._setup_outf()
639
538
 
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)
 
539
        return self.run(**all_cmd_args)
645
540
 
646
541
    def run(self):
647
542
        """Actually run the command.
678
573
            return None
679
574
 
680
575
 
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
576
def parse_args(command, argv, alias_argv=None):
719
577
    """Parse command line.
720
 
 
 
578
    
721
579
    Arguments and options are parsed at this level before being passed
722
580
    down to specific command handlers.  This routine knows, from a
723
581
    lookup table, something about the available options, what optargs
772
630
                               % (cmd, argname.upper()))
773
631
            else:
774
632
                argdict[argname] = args.pop(0)
775
 
 
 
633
            
776
634
    if args:
777
635
        raise errors.BzrCommandError("extra argument to command %s: %s"
778
636
                                     % (cmd, args[0]))
786
644
 
787
645
    tracer = trace.Trace(count=1, trace=0)
788
646
    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)
 
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)
798
654
 
799
655
 
800
656
def apply_profiled(the_callable, *args, **kwargs):
805
661
    try:
806
662
        prof = hotshot.Profile(pfname)
807
663
        try:
808
 
            ret = prof.runcall(exception_to_return_code, the_callable, *args,
809
 
                **kwargs) or 0
 
664
            ret = prof.runcall(the_callable, *args, **kwargs) or 0
810
665
        finally:
811
666
            prof.close()
812
667
        stats = hotshot.stats.load(pfname)
821
676
        os.remove(pfname)
822
677
 
823
678
 
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
679
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
866
680
    from bzrlib.lsprof import profile
867
 
    ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
 
681
    ret, stats = profile(the_callable, *args, **kwargs)
868
682
    stats.sort()
869
683
    if filename is None:
870
684
        stats.pprint()
905
719
       The command-line arguments, without the program name from argv[0]
906
720
       These should already be decoded. All library/test code calling
907
721
       run_bzr should be passing valid strings (don't need decoding).
908
 
 
 
722
    
909
723
    Returns a command status or raises an exception.
910
724
 
911
725
    Special master options: these must come before the command because
929
743
 
930
744
    --coverage
931
745
        Generate line coverage report in the specified directory.
932
 
 
933
 
    --concurrency
934
 
        Specify the number of processes that can be run concurrently (selftest).
935
746
    """
936
 
    trace.mutter("bazaar version: " + bzrlib.__version__)
937
747
    argv = list(argv)
938
748
    trace.mutter("bzr arguments: %r", argv)
939
749
 
963
773
            opt_no_aliases = True
964
774
        elif a == '--builtin':
965
775
            opt_builtin = True
966
 
        elif a == '--concurrency':
967
 
            os.environ['BZR_CONCURRENCY'] = argv[i + 1]
968
 
            i += 1
969
776
        elif a == '--coverage':
970
777
            opt_coverage_dir = argv[i + 1]
971
778
            i += 1
975
782
            argv_copy.append(a)
976
783
        i += 1
977
784
 
978
 
    debug.set_debug_flags_from_config()
979
 
 
980
785
    argv = argv_copy
981
786
    if (not argv):
982
787
        from bzrlib.builtins import cmd_help
1032
837
            ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
1033
838
        else:
1034
839
            ret = run(*run_argv)
 
840
        if 'memory' in debug.debug_flags:
 
841
            trace.debug_memory('Process status after command:', short=False)
1035
842
        return ret or 0
1036
843
    finally:
1037
844
        # reset, in case we may do other commands later within the same
1038
845
        # process. Commands that want to execute sub-commands must propagate
1039
846
        # --verbose in their own way.
1040
 
        if 'memory' in debug.debug_flags:
1041
 
            trace.debug_memory('Process status after command:', short=False)
1042
847
        option._verbosity_level = saved_verbosity_level
1043
848
 
1044
 
 
1045
849
def display_command(func):
1046
850
    """Decorator that suppresses pipe/interrupt errors."""
1047
851
    def ignore_pipe(*args, **kwargs):
1062
866
    return ignore_pipe
1063
867
 
1064
868
 
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
 
    """
 
869
def main(argv):
1091
870
    import bzrlib.ui
1092
871
    bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
1093
872
        sys.stdin, sys.stdout, sys.stderr)
1094
873
 
1095
874
    # Is this a final release version? If so, we should suppress warnings
1096
875
    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
 
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))
1112
884
    ret = run_bzr_catch_errors(argv)
1113
 
    bzrlib.ui.ui_factory.log_transport_activity(
1114
 
        display=('bytes' in debug.debug_flags))
1115
885
    trace.mutter("return code %d", ret)
1116
 
    osutils.report_extension_load_failures()
1117
886
    return ret
1118
887
 
1119
888
 
1120
889
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)
 
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
        exc_info = sys.exc_info()
 
898
        exitcode = trace.report_exception(exc_info, sys.stderr)
 
899
        if os.environ.get('BZR_PDB'):
 
900
            print '**** entering debugger'
 
901
            tb = exc_info[2]
 
902
            import pdb
 
903
            if sys.version_info[:2] < (2, 6):
 
904
                # XXX: we want to do
 
905
                #    pdb.post_mortem(tb)
 
906
                # but because pdb.post_mortem gives bad results for tracebacks
 
907
                # from inside generators, we do it manually.
 
908
                # (http://bugs.python.org/issue4150, fixed in Python 2.6)
 
909
                
 
910
                # Setup pdb on the traceback
 
911
                p = pdb.Pdb()
 
912
                p.reset()
 
913
                p.setup(tb.tb_frame, tb)
 
914
                # Point the debugger at the deepest frame of the stack
 
915
                p.curindex = len(p.stack) - 1
 
916
                p.curframe = p.stack[p.curindex]
 
917
                # Start the pdb prompt.
 
918
                p.print_stack_entry(p.stack[p.curindex])
 
919
                p.execRcLines()
 
920
                p.cmdloop()
 
921
            else:
 
922
                pdb.post_mortem(tb)
 
923
        return exitcode
1128
924
 
1129
925
 
1130
926
def run_bzr_catch_user_errors(argv):
1133
929
    This is used for the test suite, and might be useful for other programs
1134
930
    that want to wrap the commandline interface.
1135
931
    """
1136
 
    install_bzr_command_hooks()
1137
932
    try:
1138
933
        return run_bzr(argv)
1139
934
    except Exception, e:
1173
968
 
1174
969
    def plugin_for_command(self, cmd_name):
1175
970
        '''Takes a command and returns the information for that plugin
1176
 
 
1177
 
        :return: A dictionary with all the available information
 
971
        
 
972
        :return: A dictionary with all the available information 
1178
973
        for the requested plugin
1179
974
        '''
1180
975
        raise NotImplementedError