/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

Implement command help l10n.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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
27
27
 
28
28
from bzrlib.lazy_import import lazy_import
29
29
lazy_import(globals(), """
30
 
import codecs
31
30
import errno
32
31
import threading
33
 
from warnings import warn
34
32
 
35
33
import bzrlib
36
34
from bzrlib import (
42
40
    osutils,
43
41
    trace,
44
42
    ui,
45
 
    win32utils,
46
43
    )
47
44
""")
48
45
 
49
 
from bzrlib.hooks import HookPoint, Hooks
 
46
from bzrlib.hooks import Hooks
50
47
# Compatibility - Option used to be in commands.
51
48
from bzrlib.option import Option
52
49
from bzrlib.plugin import disable_plugins, load_plugins
222
219
    Use of all_command_names() is encouraged rather than builtin_command_names
223
220
    and/or plugin_command_names.
224
221
    """
 
222
    _register_builtin_commands()
225
223
    return builtin_command_registry.keys()
226
224
 
227
225
 
275
273
    # Allow plugins to extend commands
276
274
    for hook in Command.hooks['extend_command']:
277
275
        hook(cmd)
 
276
    if getattr(cmd, 'invoked_as', None) is None:
 
277
        cmd.invoked_as = cmd_name
278
278
    return cmd
279
279
 
280
280
 
396
396
            sys.stdout is forced to be a binary stream, and line-endings
397
397
            will not mangled.
398
398
 
 
399
    :ivar invoked_as:
 
400
        A string indicating the real name under which this command was
 
401
        invoked, before expansion of aliases. 
 
402
        (This may be None if the command was constructed and run in-process.)
 
403
 
399
404
    :cvar hooks: An instance of CommandHooks.
 
405
 
 
406
    :ivar __doc__: The help shown by 'bzr help command' for this command.
 
407
        This is set by assigning explicitly to __doc__ so that -OO can
 
408
        be used::
 
409
 
 
410
        class Foo(Command):
 
411
            __doc__ = "My help goes here"
400
412
    """
401
413
    aliases = []
402
414
    takes_args = []
403
415
    takes_options = []
404
416
    encoding_type = 'strict'
 
417
    invoked_as = None
405
418
 
406
419
    hidden = False
407
420
 
408
421
    def __init__(self):
409
422
        """Construct an instance of this command."""
410
 
        if self.__doc__ == Command.__doc__:
411
 
            warn("No help message set for %r" % self)
412
423
        # List of standard options directly supported
413
424
        self.supported_std_options = []
414
425
        self._setup_run()
481
492
            usage help (e.g. Purpose, Usage, Options) with a
482
493
            message explaining how to obtain full help.
483
494
        """
 
495
        from bzrlib.i18n import gettext   # gettext() for fixed string
 
496
        cmd_gettext = self.get_gettext()  # gettext() for command help
484
497
        doc = self.help()
485
 
        if doc is None:
486
 
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
 
498
        if doc:
 
499
            # NOTE: If cmd_gettext translates ':Usage:\n', the section will
 
500
            # be shown after "Description" section.
 
501
            # Additionally, ZzzTranslation translates ':Label...' into
 
502
            # 'zz{{:Label...}}'. So all sections are broken and shown in
 
503
            # the "Description" section.
 
504
            doc = cmd_gettext(doc)
 
505
        else:
 
506
            doc = gettext("No help for this command.")
487
507
 
488
508
        # Extract the summary (purpose) and sections out from the text
489
509
        purpose,sections,order = self._get_help_parts(doc)
496
516
 
497
517
        # The header is the purpose and usage
498
518
        result = ""
499
 
        result += ':Purpose: %s\n' % purpose
 
519
        result += ':%s: %s\n' % (gettext('Purpose'), purpose)
500
520
        if usage.find('\n') >= 0:
501
 
            result += ':Usage:\n%s\n' % usage
 
521
            result += ':%s:\n%s\n' % (gettext('Usage'), usage)
502
522
        else:
503
 
            result += ':Usage:   %s\n' % usage
 
523
            result += ':%s:   %s\n' % (gettext('Usage'), usage)
504
524
        result += '\n'
505
525
 
506
526
        # Add the options
508
528
        # XXX: optparse implicitly rewraps the help, and not always perfectly,
509
529
        # so we get <https://bugs.launchpad.net/bzr/+bug/249908>.  -- mbp
510
530
        # 20090319
511
 
        options = option.get_optparser(self.options()).format_option_help()
512
 
        # XXX: According to the spec, ReST option lists actually don't support 
513
 
        # options like --1.9 so that causes syntax errors (in Sphinx at least).
514
 
        # As that pattern always appears in the commands that break, we trap
515
 
        # on that and then format that block of 'format' options as a literal
516
 
        # block.
517
 
        if not plain and options.find('  --1.9  ') != -1:
 
531
        options = option.get_optparser(self.options(), True)
 
532
        options = options.format_option_help()
 
533
        # FIXME: According to the spec, ReST option lists actually don't
 
534
        # support options like --1.14 so that causes syntax errors (in Sphinx
 
535
        # at least).  As that pattern always appears in the commands that
 
536
        # break, we trap on that and then format that block of 'format' options
 
537
        # as a literal block. We use the most recent format still listed so we
 
538
        # don't have to do that too often -- vila 20110514
 
539
        if not plain and options.find('  --1.14  ') != -1:
518
540
            options = options.replace(' format:\n', ' format::\n\n', 1)
519
 
        if options.startswith('Options:'):
520
 
            result += ':' + options
521
 
        elif options.startswith('options:'):
522
 
            # Python 2.4 version of optparse
523
 
            result += ':Options:' + options[len('options:'):]
 
541
        if options.startswith('Options:') or options.startswith('options:'):
 
542
            # Python 2.4 version of optparse uses 'options'.
 
543
            result += ':%s:%s' % (gettext('Options'), options[len('options:'):])
524
544
        else:
525
545
            result += options
526
546
        result += '\n'
531
551
            if sections.has_key(None):
532
552
                text = sections.pop(None)
533
553
                text = '\n  '.join(text.splitlines())
534
 
                result += ':%s:\n  %s\n\n' % ('Description',text)
 
554
                result += ':%s:\n  %s\n\n' % (gettext('Description'),text)
535
555
 
536
556
            # Add the custom sections (e.g. Examples). Note that there's no need
537
557
            # to indent these as they must be indented already in the source.
538
558
            if sections:
539
559
                for label in order:
540
 
                    if sections.has_key(label):
541
 
                        result += ':%s:\n%s\n' % (label,sections[label])
 
560
                    if label in sections:
 
561
                        result += ':%s:\n%s\n' % (label, sections[label])
542
562
                result += '\n'
543
563
        else:
544
 
            result += ("See bzr help %s for more details and examples.\n\n"
 
564
            result += (gettext("See bzr help %s for more details and examples.\n\n")
545
565
                % self.name())
546
566
 
547
567
        # Add the aliases, source (plug-in) and see also links, if any
548
568
        if self.aliases:
549
 
            result += ':Aliases:  '
 
569
            result += ':%s:  ' % gettext('Aliases')
550
570
            result += ', '.join(self.aliases) + '\n'
551
571
        plugin_name = self.plugin_name()
552
572
        if plugin_name is not None:
565
585
                        link_text = ":doc:`%s <%s-help>`" % (item, item)
566
586
                        see_also_links.append(link_text)
567
587
                see_also = see_also_links
568
 
            result += ':See also: '
 
588
            result += ':%s: ' % gettext('See also')
569
589
            result += ', '.join(see_also) + '\n'
570
590
 
571
591
        # If this will be rendered as plain text, convert it
656
676
 
657
677
        # Process the standard options
658
678
        if 'help' in opts:  # e.g. bzr add --help
659
 
            sys.stdout.write(self.get_help_text())
 
679
            self._setup_outf()
 
680
            self.outf.write(self.get_help_text())
660
681
            return 0
661
682
        if 'usage' in opts:  # e.g. bzr add --usage
662
683
            sys.stdout.write(self.get_help_text(verbose=False))
682
703
 
683
704
        self._setup_outf()
684
705
 
685
 
        return self.run(**all_cmd_args)
 
706
        try:
 
707
            return self.run(**all_cmd_args)
 
708
        finally:
 
709
            # reset it, so that other commands run in the same process won't
 
710
            # inherit state. Before we reset it, log any activity, so that it
 
711
            # gets properly tracked.
 
712
            ui.ui_factory.log_transport_activity(
 
713
                display=('bytes' in debug.debug_flags))
 
714
            trace.set_verbosity_level(0)
686
715
 
687
716
    def _setup_run(self):
688
717
        """Wrap the defined run method on self with a cleanup.
738
767
            return None
739
768
        return getdoc(self)
740
769
 
 
770
    @staticmethod
 
771
    def get_gettext():
 
772
        """Returns the gettext function used to translate this command's help.
 
773
 
 
774
        NOTE: Commands provided by plugins should override this to use own
 
775
        i18n system.
 
776
        """
 
777
        from bzrlib.i18n import gettext
 
778
        return gettext
 
779
 
741
780
    def name(self):
 
781
        """Return the canonical name for this command.
 
782
 
 
783
        The name under which it was actually invoked is available in invoked_as.
 
784
        """
742
785
        return _unsquish_command_name(self.__class__.__name__)
743
786
 
744
787
    def plugin_name(self):
762
805
        These are all empty initially, because by default nothing should get
763
806
        notified.
764
807
        """
765
 
        Hooks.__init__(self)
766
 
        self.create_hook(HookPoint('extend_command',
 
808
        Hooks.__init__(self, "bzrlib.commands", "Command.hooks")
 
809
        self.add_hook('extend_command',
767
810
            "Called after creating a command object to allow modifications "
768
811
            "such as adding or removing options, docs etc. Called with the "
769
 
            "new bzrlib.commands.Command object.", (1, 13), None))
770
 
        self.create_hook(HookPoint('get_command',
 
812
            "new bzrlib.commands.Command object.", (1, 13))
 
813
        self.add_hook('get_command',
771
814
            "Called when creating a single command. Called with "
772
815
            "(cmd_or_None, command_name). get_command should either return "
773
816
            "the cmd_or_None parameter, or a replacement Command object that "
774
817
            "should be used for the command. Note that the Command.hooks "
775
818
            "hooks are core infrastructure. Many users will prefer to use "
776
819
            "bzrlib.commands.register_command or plugin_cmds.register_lazy.",
777
 
            (1, 17), None))
778
 
        self.create_hook(HookPoint('get_missing_command',
 
820
            (1, 17))
 
821
        self.add_hook('get_missing_command',
779
822
            "Called when creating a single command if no command could be "
780
823
            "found. Called with (command_name). get_missing_command should "
781
824
            "either return None, or a Command object to be used for the "
782
 
            "command.", (1, 17), None))
783
 
        self.create_hook(HookPoint('list_commands',
 
825
            "command.", (1, 17))
 
826
        self.add_hook('list_commands',
784
827
            "Called when enumerating commands. Called with a set of "
785
828
            "cmd_name strings for all the commands found so far. This set "
786
829
            " is safe to mutate - e.g. to remove a command. "
787
830
            "list_commands should return the updated set of command names.",
788
 
            (1, 17), None))
 
831
            (1, 17))
789
832
 
790
833
Command.hooks = CommandHooks()
791
834
 
805
848
    else:
806
849
        args = argv
807
850
 
808
 
    options, args = parser.parse_args(args)
 
851
    # for python 2.5 and later, optparse raises this exception if a non-ascii
 
852
    # option name is given.  See http://bugs.python.org/issue2931
 
853
    try:
 
854
        options, args = parser.parse_args(args)
 
855
    except UnicodeEncodeError,e:
 
856
        raise errors.BzrCommandError('Only ASCII permitted in option names')
 
857
 
809
858
    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
810
859
                 v is not option.OptionParser.DEFAULT_VALUE])
811
860
    return args, opts
1015
1064
        Specify the number of processes that can be run concurrently (selftest).
1016
1065
    """
1017
1066
    trace.mutter("bazaar version: " + bzrlib.__version__)
1018
 
    argv = list(argv)
 
1067
    argv = _specified_or_unicode_argv(argv)
1019
1068
    trace.mutter("bzr arguments: %r", argv)
1020
1069
 
1021
 
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
1022
 
                opt_no_aliases = False
 
1070
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
 
1071
            opt_no_i18n = opt_no_aliases = False
1023
1072
    opt_lsprof_file = opt_coverage_dir = None
1024
1073
 
1025
1074
    # --no-plugins is handled specially at a very early stage. We need
1042
1091
            opt_no_plugins = True
1043
1092
        elif a == '--no-aliases':
1044
1093
            opt_no_aliases = True
 
1094
        elif a == '--no-i18n':
 
1095
            opt_no_i18n = True
1045
1096
        elif a == '--builtin':
1046
1097
            opt_builtin = True
1047
1098
        elif a == '--concurrency':
1050
1101
        elif a == '--coverage':
1051
1102
            opt_coverage_dir = argv[i + 1]
1052
1103
            i += 1
 
1104
        elif a == '--profile-imports':
 
1105
            pass # already handled in startup script Bug #588277
1053
1106
        elif a.startswith('-D'):
1054
1107
            debug.debug_flags.add(a[2:])
1055
1108
        else:
1057
1110
        i += 1
1058
1111
 
1059
1112
    debug.set_debug_flags_from_config()
 
1113
    if not opt_no_i18n:
 
1114
        from bzrlib import i18n
 
1115
        if 'i18n' in debug.debug_flags:
 
1116
            i18n.install_zzz()
 
1117
        else:
 
1118
            i18n.install()
1060
1119
 
1061
1120
    if not opt_no_plugins:
1062
1121
        load_plugins()
1077
1136
    if not opt_no_aliases:
1078
1137
        alias_argv = get_alias(argv[0])
1079
1138
        if alias_argv:
1080
 
            user_encoding = osutils.get_user_encoding()
1081
 
            alias_argv = [a.decode(user_encoding) for a in alias_argv]
1082
1139
            argv[0] = alias_argv.pop(0)
1083
1140
 
1084
1141
    cmd = argv.pop(0)
1085
 
    # We want only 'ascii' command names, but the user may have typed
1086
 
    # in a Unicode name. In that case, they should just get a
1087
 
    # 'command not found' error later.
1088
 
 
1089
1142
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
1090
1143
    run = cmd_obj.run_argv_aliases
1091
1144
    run_argv = [argv, alias_argv]
1165
1218
        new_argv = []
1166
1219
        try:
1167
1220
            # ensure all arguments are unicode strings
1168
 
            for a in argv[1:]:
 
1221
            for a in argv:
1169
1222
                if isinstance(a, unicode):
1170
1223
                    new_argv.append(a)
1171
1224
                else:
1187
1240
 
1188
1241
    :return: exit code of bzr command.
1189
1242
    """
1190
 
    argv = _specified_or_unicode_argv(argv)
 
1243
    if argv is not None:
 
1244
        argv = argv[1:]
1191
1245
    _register_builtin_commands()
1192
1246
    ret = run_bzr_catch_errors(argv)
1193
 
    bzrlib.ui.ui_factory.log_transport_activity(
1194
 
        display=('bytes' in debug.debug_flags))
1195
1247
    trace.mutter("return code %d", ret)
1196
1248
    return ret
1197
1249