/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: Martin Pool
  • Date: 2009-03-13 07:54:48 UTC
  • mfrom: (4144 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4189.
  • Revision ID: mbp@sourcefrog.net-20090313075448-jlz1t7baz7gzipqn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
50
50
 
51
51
from bzrlib import registry
52
52
# Compatibility
 
53
from bzrlib.hooks import HookPoint, Hooks
53
54
from bzrlib.option import Option
54
55
 
55
56
 
138
139
            real_name = _unsquish_command_name(name)
139
140
            r[real_name] = builtins[name]
140
141
    return r
141
 
            
 
142
 
142
143
 
143
144
def builtin_command_names():
144
145
    """Return list of builtin command names."""
145
146
    return _builtin_commands().keys()
146
 
    
 
147
 
147
148
 
148
149
def plugin_command_names():
149
150
    return plugin_cmds.keys()
156
157
        d.update(plugin_cmds.iteritems())
157
158
    return d
158
159
 
159
 
    
 
160
 
160
161
def get_all_cmds(plugins_override=True):
161
162
    """Return canonical name and class for all registered commands."""
162
163
    for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
170
171
        If true, plugin commands can override builtins.
171
172
    """
172
173
    try:
173
 
        return _get_cmd_object(cmd_name, plugins_override)
 
174
        cmd = _get_cmd_object(cmd_name, plugins_override)
 
175
        # Allow plugins to extend commands
 
176
        for hook in Command.hooks['extend_command']:
 
177
            hook(cmd)
 
178
        return cmd
174
179
    except KeyError:
175
180
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
176
181
 
216
221
        except errors.NoPluginAvailable:
217
222
            pass
218
223
        else:
219
 
            raise errors.CommandAvailableInPlugin(cmd_name, 
 
224
            raise errors.CommandAvailableInPlugin(cmd_name,
220
225
                                                  plugin_metadata, provider)
221
 
 
222
226
    raise KeyError
223
227
 
224
228
 
279
283
            sys.stdout is forced to be a binary stream, and line-endings
280
284
            will not mangled.
281
285
 
 
286
    :cvar hooks: An instance of CommandHooks.
282
287
    """
283
288
    aliases = []
284
289
    takes_args = []
286
291
    encoding_type = 'strict'
287
292
 
288
293
    hidden = False
289
 
    
 
294
 
290
295
    def __init__(self):
291
296
        """Construct an instance of this command."""
292
297
        if self.__doc__ == Command.__doc__:
296
301
 
297
302
    def _maybe_expand_globs(self, file_list):
298
303
        """Glob expand file_list if the platform does not do that itself.
299
 
        
 
304
 
300
305
        :return: A possibly empty list of unicode paths.
301
306
 
302
307
        Introduced in bzrlib 0.18.
328
333
    def get_help_text(self, additional_see_also=None, plain=True,
329
334
                      see_also_as_links=False):
330
335
        """Return a text string with help for this command.
331
 
        
 
336
 
332
337
        :param additional_see_also: Additional help topics to be
333
338
            cross-referenced.
334
339
        :param plain: if False, raw help (reStructuredText) is
341
346
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
342
347
 
343
348
        # Extract the summary (purpose) and sections out from the text
344
 
        purpose,sections = self._get_help_parts(doc)
 
349
        purpose,sections,order = self._get_help_parts(doc)
345
350
 
346
351
        # If a custom usage section was provided, use it
347
352
        if sections.has_key('Usage'):
379
384
        # Add the custom sections (e.g. Examples). Note that there's no need
380
385
        # to indent these as they must be indented already in the source.
381
386
        if sections:
382
 
            labels = sorted(sections.keys())
383
 
            for label in labels:
384
 
                result += ':%s:\n%s\n\n' % (label,sections[label])
 
387
            for label in order:
 
388
                if sections.has_key(label):
 
389
                    result += ':%s:\n%s\n\n' % (label,sections[label])
385
390
 
386
391
        # Add the aliases, source (plug-in) and see also links, if any
387
392
        if self.aliases:
416
421
    def _get_help_parts(text):
417
422
        """Split help text into a summary and named sections.
418
423
 
419
 
        :return: (summary,sections) where summary is the top line and
 
424
        :return: (summary,sections,order) where summary is the top line and
420
425
            sections is a dictionary of the rest indexed by section name.
 
426
            order is the order the section appear in the text.
421
427
            A section starts with a heading line of the form ":xxx:".
422
428
            Indented text on following lines is the section value.
423
429
            All text found outside a named section is assigned to the
424
430
            default section which is given the key of None.
425
431
        """
426
 
        def save_section(sections, label, section):
 
432
        def save_section(sections, order, label, section):
427
433
            if len(section) > 0:
428
434
                if sections.has_key(label):
429
435
                    sections[label] += '\n' + section
430
436
                else:
 
437
                    order.append(label)
431
438
                    sections[label] = section
432
439
 
433
440
        lines = text.rstrip().splitlines()
434
441
        summary = lines.pop(0)
435
442
        sections = {}
 
443
        order = []
436
444
        label,section = None,''
437
445
        for line in lines:
438
446
            if line.startswith(':') and line.endswith(':') and len(line) > 2:
439
 
                save_section(sections, label, section)
 
447
                save_section(sections, order, label, section)
440
448
                label,section = line[1:-1],''
441
449
            elif (label is not None) and len(line) > 1 and not line[0].isspace():
442
 
                save_section(sections, label, section)
 
450
                save_section(sections, order, label, section)
443
451
                label,section = None,line
444
452
            else:
445
453
                if len(section) > 0:
446
454
                    section += '\n' + line
447
455
                else:
448
456
                    section = line
449
 
        save_section(sections, label, section)
450
 
        return summary, sections
 
457
        save_section(sections, order, label, section)
 
458
        return summary, sections, order
451
459
 
452
460
    def get_help_topic(self):
453
461
        """Return the commands help topic - its name."""
455
463
 
456
464
    def get_see_also(self, additional_terms=None):
457
465
        """Return a list of help topics that are related to this command.
458
 
        
 
466
 
459
467
        The list is derived from the content of the _see_also attribute. Any
460
468
        duplicates are removed and the result is in lexical order.
461
469
        :param additional_terms: Additional help topics to cross-reference.
573
581
            return None
574
582
 
575
583
 
 
584
class CommandHooks(Hooks):
 
585
    """Hooks related to Command object creation/enumeration."""
 
586
 
 
587
    def __init__(self):
 
588
        """Create the default hooks.
 
589
 
 
590
        These are all empty initially, because by default nothing should get
 
591
        notified.
 
592
        """
 
593
        Hooks.__init__(self)
 
594
        self.create_hook(HookPoint('extend_command',
 
595
            "Called after creating a command object to allow modifications "
 
596
            "such as adding or removing options, docs etc. Called with the "
 
597
            "new bzrlib.commands.Command object.", (1, 13), None))
 
598
 
 
599
Command.hooks = CommandHooks()
 
600
 
 
601
 
576
602
def parse_args(command, argv, alias_argv=None):
577
603
    """Parse command line.
578
 
    
 
604
 
579
605
    Arguments and options are parsed at this level before being passed
580
606
    down to specific command handlers.  This routine knows, from a
581
607
    lookup table, something about the available options, what optargs
630
656
                               % (cmd, argname.upper()))
631
657
            else:
632
658
                argdict[argname] = args.pop(0)
633
 
            
 
659
 
634
660
    if args:
635
661
        raise errors.BzrCommandError("extra argument to command %s: %s"
636
662
                                     % (cmd, args[0]))
645
671
    tracer = trace.Trace(count=1, trace=0)
646
672
    sys.settrace(tracer.globaltrace)
647
673
 
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)
 
674
    try:
 
675
        return exception_to_return_code(the_callable, *args, **kwargs)
 
676
    finally:
 
677
        sys.settrace(None)
 
678
        results = tracer.results()
 
679
        results.write_results(show_missing=1, summary=False,
 
680
                              coverdir=dirname)
654
681
 
655
682
 
656
683
def apply_profiled(the_callable, *args, **kwargs):
661
688
    try:
662
689
        prof = hotshot.Profile(pfname)
663
690
        try:
664
 
            ret = prof.runcall(the_callable, *args, **kwargs) or 0
 
691
            ret = prof.runcall(exception_to_return_code, the_callable, *args,
 
692
                **kwargs) or 0
665
693
        finally:
666
694
            prof.close()
667
695
        stats = hotshot.stats.load(pfname)
676
704
        os.remove(pfname)
677
705
 
678
706
 
 
707
def exception_to_return_code(the_callable, *args, **kwargs):
 
708
    """UI level helper for profiling and coverage.
 
709
 
 
710
    This transforms exceptions into a return value of 3. As such its only
 
711
    relevant to the UI layer, and should never be called where catching
 
712
    exceptions may be desirable.
 
713
    """
 
714
    try:
 
715
        return the_callable(*args, **kwargs)
 
716
    except (KeyboardInterrupt, Exception), e:
 
717
        # used to handle AssertionError and KeyboardInterrupt
 
718
        # specially here, but hopefully they're handled ok by the logger now
 
719
        exc_info = sys.exc_info()
 
720
        exitcode = trace.report_exception(exc_info, sys.stderr)
 
721
        if os.environ.get('BZR_PDB'):
 
722
            print '**** entering debugger'
 
723
            tb = exc_info[2]
 
724
            import pdb
 
725
            if sys.version_info[:2] < (2, 6):
 
726
                # XXX: we want to do
 
727
                #    pdb.post_mortem(tb)
 
728
                # but because pdb.post_mortem gives bad results for tracebacks
 
729
                # from inside generators, we do it manually.
 
730
                # (http://bugs.python.org/issue4150, fixed in Python 2.6)
 
731
 
 
732
                # Setup pdb on the traceback
 
733
                p = pdb.Pdb()
 
734
                p.reset()
 
735
                p.setup(tb.tb_frame, tb)
 
736
                # Point the debugger at the deepest frame of the stack
 
737
                p.curindex = len(p.stack) - 1
 
738
                p.curframe = p.stack[p.curindex][0]
 
739
                # Start the pdb prompt.
 
740
                p.print_stack_entry(p.stack[p.curindex])
 
741
                p.execRcLines()
 
742
                p.cmdloop()
 
743
            else:
 
744
                pdb.post_mortem(tb)
 
745
        return exitcode
 
746
 
 
747
 
679
748
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
680
749
    from bzrlib.lsprof import profile
681
 
    ret, stats = profile(the_callable, *args, **kwargs)
 
750
    ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
682
751
    stats.sort()
683
752
    if filename is None:
684
753
        stats.pprint()
719
788
       The command-line arguments, without the program name from argv[0]
720
789
       These should already be decoded. All library/test code calling
721
790
       run_bzr should be passing valid strings (don't need decoding).
722
 
    
 
791
 
723
792
    Returns a command status or raises an exception.
724
793
 
725
794
    Special master options: these must come before the command because
782
851
            argv_copy.append(a)
783
852
        i += 1
784
853
 
 
854
    debug.set_debug_flags_from_config()
 
855
 
785
856
    argv = argv_copy
786
857
    if (not argv):
787
858
        from bzrlib.builtins import cmd_help
846
917
        # --verbose in their own way.
847
918
        option._verbosity_level = saved_verbosity_level
848
919
 
 
920
 
849
921
def display_command(func):
850
922
    """Decorator that suppresses pipe/interrupt errors."""
851
923
    def ignore_pipe(*args, **kwargs):
887
959
 
888
960
 
889
961
def run_bzr_catch_errors(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
 
962
    """Run a bzr command with parameters as described by argv.
 
963
 
 
964
    This function assumed that that UI layer is setup, that symbol deprecations
 
965
    are already applied, and that unicode decoding has already been performed on argv.
 
966
    """
 
967
    return exception_to_return_code(run_bzr, argv)
903
968
 
904
969
 
905
970
def run_bzr_catch_user_errors(argv):
947
1012
 
948
1013
    def plugin_for_command(self, cmd_name):
949
1014
        '''Takes a command and returns the information for that plugin
950
 
        
951
 
        :return: A dictionary with all the available information 
 
1015
 
 
1016
        :return: A dictionary with all the available information
952
1017
        for the requested plugin
953
1018
        '''
954
1019
        raise NotImplementedError