~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Martin Pool
  • Date: 2011-06-28 22:25:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6004.
  • Revision ID: mbp@canonical.com-20110628222528-gwf27vdagmxatljc
More explicit laziness

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
182
179
    import bzrlib.builtins
183
180
    for cmd_class in _scan_module_for_commands(bzrlib.builtins).values():
184
181
        builtin_command_registry.register(cmd_class)
185
 
    # lazy builtins
186
 
    builtin_command_registry.register_lazy('cmd_bundle_info',
187
 
        [],
188
 
        'bzrlib.bundle.commands')
 
182
    bzrlib.builtins._register_lazy_builtins()
189
183
 
190
184
 
191
185
def _scan_module_for_commands(module):
225
219
    Use of all_command_names() is encouraged rather than builtin_command_names
226
220
    and/or plugin_command_names.
227
221
    """
 
222
    _register_builtin_commands()
228
223
    return builtin_command_registry.keys()
229
224
 
230
225
 
278
273
    # Allow plugins to extend commands
279
274
    for hook in Command.hooks['extend_command']:
280
275
        hook(cmd)
 
276
    if getattr(cmd, 'invoked_as', None) is None:
 
277
        cmd.invoked_as = cmd_name
281
278
    return cmd
282
279
 
283
280
 
360
357
    summary, then a complete description of the command.  A grammar
361
358
    description will be inserted.
362
359
 
363
 
    aliases
364
 
        Other accepted names for this command.
365
 
 
366
 
    takes_args
367
 
        List of argument forms, marked with whether they are optional,
368
 
        repeated, etc.
369
 
 
370
 
                Examples:
371
 
 
372
 
                ['to_location', 'from_branch?', 'file*']
373
 
 
374
 
                'to_location' is required
375
 
                'from_branch' is optional
376
 
                'file' can be specified 0 or more times
377
 
 
378
 
    takes_options
379
 
        List of options that may be given for this command.  These can
380
 
        be either strings, referring to globally-defined options,
381
 
        or option objects.  Retrieve through options().
382
 
 
383
 
    hidden
384
 
        If true, this command isn't advertised.  This is typically
 
360
    :cvar aliases: Other accepted names for this command.
 
361
 
 
362
    :cvar takes_args: List of argument forms, marked with whether they are
 
363
        optional, repeated, etc.  Examples::
 
364
 
 
365
            ['to_location', 'from_branch?', 'file*']
 
366
 
 
367
        * 'to_location' is required
 
368
        * 'from_branch' is optional
 
369
        * 'file' can be specified 0 or more times
 
370
 
 
371
    :cvar takes_options: List of options that may be given for this command.
 
372
        These can be either strings, referring to globally-defined options, or
 
373
        option objects.  Retrieve through options().
 
374
 
 
375
    :cvar hidden: If true, this command isn't advertised.  This is typically
385
376
        for commands intended for expert users.
386
377
 
387
 
    encoding_type
388
 
        Command objects will get a 'outf' attribute, which has been
389
 
        setup to properly handle encoding of unicode strings.
390
 
        encoding_type determines what will happen when characters cannot
391
 
        be encoded
392
 
            strict - abort if we cannot decode
393
 
            replace - put in a bogus character (typically '?')
394
 
            exact - do not encode sys.stdout
395
 
 
396
 
            NOTE: by default on Windows, sys.stdout is opened as a text
397
 
            stream, therefore LF line-endings are converted to CRLF.
398
 
            When a command uses encoding_type = 'exact', then
399
 
            sys.stdout is forced to be a binary stream, and line-endings
400
 
            will not mangled.
 
378
    :cvar encoding_type: Command objects will get a 'outf' attribute, which has
 
379
        been setup to properly handle encoding of unicode strings.
 
380
        encoding_type determines what will happen when characters cannot be
 
381
        encoded:
 
382
 
 
383
        * strict - abort if we cannot decode
 
384
        * replace - put in a bogus character (typically '?')
 
385
        * exact - do not encode sys.stdout
 
386
 
 
387
        NOTE: by default on Windows, sys.stdout is opened as a text stream,
 
388
        therefore LF line-endings are converted to CRLF.  When a command uses
 
389
        encoding_type = 'exact', then sys.stdout is forced to be a binary
 
390
        stream, and line-endings will not mangled.
 
391
 
 
392
    :cvar invoked_as:
 
393
        A string indicating the real name under which this command was
 
394
        invoked, before expansion of aliases.
 
395
        (This may be None if the command was constructed and run in-process.)
401
396
 
402
397
    :cvar hooks: An instance of CommandHooks.
 
398
 
 
399
    :cvar __doc__: The help shown by 'bzr help command' for this command.
 
400
        This is set by assigning explicitly to __doc__ so that -OO can
 
401
        be used::
 
402
 
 
403
            class Foo(Command):
 
404
                __doc__ = "My help goes here"
403
405
    """
404
406
    aliases = []
405
407
    takes_args = []
406
408
    takes_options = []
407
409
    encoding_type = 'strict'
 
410
    invoked_as = None
408
411
 
409
412
    hidden = False
410
413
 
411
414
    def __init__(self):
412
415
        """Construct an instance of this command."""
413
 
        if self.__doc__ == Command.__doc__:
414
 
            warn("No help message set for %r" % self)
415
416
        # List of standard options directly supported
416
417
        self.supported_std_options = []
417
 
        self._operation = cleanup.OperationWithCleanups(self.run)
 
418
        self._setup_run()
418
419
 
419
420
    def add_cleanup(self, cleanup_func, *args, **kwargs):
420
421
        """Register a function to call after self.run returns or raises.
432
433
 
433
434
        This is useful for releasing expensive or contentious resources (such
434
435
        as write locks) before doing further work that does not require those
435
 
        resources (such as writing results to self.outf).
 
436
        resources (such as writing results to self.outf). Note though, that
 
437
        as it releases all resources, this may release locks that the command
 
438
        wants to hold, so use should be done with care.
436
439
        """
437
440
        self._operation.cleanup_now()
438
441
 
483
486
            message explaining how to obtain full help.
484
487
        """
485
488
        doc = self.help()
486
 
        if doc is None:
487
 
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
 
489
        if not doc:
 
490
            doc = "No help for this command."
488
491
 
489
492
        # Extract the summary (purpose) and sections out from the text
490
493
        purpose,sections,order = self._get_help_parts(doc)
510
513
        # so we get <https://bugs.launchpad.net/bzr/+bug/249908>.  -- mbp
511
514
        # 20090319
512
515
        options = option.get_optparser(self.options()).format_option_help()
513
 
        # XXX: According to the spec, ReST option lists actually don't support 
514
 
        # options like --1.9 so that causes syntax errors (in Sphinx at least).
515
 
        # As that pattern always appears in the commands that break, we trap
516
 
        # on that and then format that block of 'format' options as a literal
517
 
        # block.
518
 
        if not plain and options.find('  --1.9  ') != -1:
 
516
        # FIXME: According to the spec, ReST option lists actually don't
 
517
        # support options like --1.14 so that causes syntax errors (in Sphinx
 
518
        # at least).  As that pattern always appears in the commands that
 
519
        # break, we trap on that and then format that block of 'format' options
 
520
        # as a literal block. We use the most recent format still listed so we
 
521
        # don't have to do that too often -- vila 20110514
 
522
        if not plain and options.find('  --1.14  ') != -1:
519
523
            options = options.replace(' format:\n', ' format::\n\n', 1)
520
524
        if options.startswith('Options:'):
521
525
            result += ':' + options
683
687
 
684
688
        self._setup_outf()
685
689
 
686
 
        return self.run_direct(**all_cmd_args)
687
 
 
 
690
        try:
 
691
            return self.run(**all_cmd_args)
 
692
        finally:
 
693
            # reset it, so that other commands run in the same process won't
 
694
            # inherit state. Before we reset it, log any activity, so that it
 
695
            # gets properly tracked.
 
696
            ui.ui_factory.log_transport_activity(
 
697
                display=('bytes' in debug.debug_flags))
 
698
            trace.set_verbosity_level(0)
 
699
 
 
700
    def _setup_run(self):
 
701
        """Wrap the defined run method on self with a cleanup.
 
702
 
 
703
        This is called by __init__ to make the Command be able to be run
 
704
        by just calling run(), as it could be before cleanups were added.
 
705
 
 
706
        If a different form of cleanups are in use by your Command subclass,
 
707
        you can override this method.
 
708
        """
 
709
        class_run = self.run
 
710
        def run(*args, **kwargs):
 
711
            self._operation = cleanup.OperationWithCleanups(class_run)
 
712
            try:
 
713
                return self._operation.run_simple(*args, **kwargs)
 
714
            finally:
 
715
                del self._operation
 
716
        self.run = run
 
717
 
 
718
    @deprecated_method(deprecated_in((2, 2, 0)))
688
719
    def run_direct(self, *args, **kwargs):
689
 
        """Call run directly with objects (without parsing an argv list)."""
690
 
        return self._operation.run_simple(*args, **kwargs)
 
720
        """Deprecated thunk from bzrlib 2.1."""
 
721
        return self.run(*args, **kwargs)
691
722
 
692
723
    def run(self):
693
724
        """Actually run the command.
698
729
        Return 0 or None if the command was successful, or a non-zero
699
730
        shell error code if not.  It's OK for this method to allow
700
731
        an exception to raise up.
 
732
 
 
733
        This method is automatically wrapped by Command.__init__ with a 
 
734
        cleanup operation, stored as self._operation. This can be used
 
735
        via self.add_cleanup to perform automatic cleanups at the end of
 
736
        run().
 
737
 
 
738
        The argument for run are assembled by introspection. So for instance,
 
739
        if your command takes an argument files, you would declare::
 
740
 
 
741
            def run(self, files=None):
 
742
                pass
701
743
        """
702
744
        raise NotImplementedError('no implementation of command %r'
703
745
                                  % self.name())
710
752
        return getdoc(self)
711
753
 
712
754
    def name(self):
 
755
        """Return the canonical name for this command.
 
756
 
 
757
        The name under which it was actually invoked is available in invoked_as.
 
758
        """
713
759
        return _unsquish_command_name(self.__class__.__name__)
714
760
 
715
761
    def plugin_name(self):
733
779
        These are all empty initially, because by default nothing should get
734
780
        notified.
735
781
        """
736
 
        Hooks.__init__(self)
737
 
        self.create_hook(HookPoint('extend_command',
 
782
        Hooks.__init__(self, "bzrlib.commands", "Command.hooks")
 
783
        self.add_hook('extend_command',
738
784
            "Called after creating a command object to allow modifications "
739
785
            "such as adding or removing options, docs etc. Called with the "
740
 
            "new bzrlib.commands.Command object.", (1, 13), None))
741
 
        self.create_hook(HookPoint('get_command',
 
786
            "new bzrlib.commands.Command object.", (1, 13))
 
787
        self.add_hook('get_command',
742
788
            "Called when creating a single command. Called with "
743
789
            "(cmd_or_None, command_name). get_command should either return "
744
790
            "the cmd_or_None parameter, or a replacement Command object that "
745
791
            "should be used for the command. Note that the Command.hooks "
746
792
            "hooks are core infrastructure. Many users will prefer to use "
747
793
            "bzrlib.commands.register_command or plugin_cmds.register_lazy.",
748
 
            (1, 17), None))
749
 
        self.create_hook(HookPoint('get_missing_command',
 
794
            (1, 17))
 
795
        self.add_hook('get_missing_command',
750
796
            "Called when creating a single command if no command could be "
751
797
            "found. Called with (command_name). get_missing_command should "
752
798
            "either return None, or a Command object to be used for the "
753
 
            "command.", (1, 17), None))
754
 
        self.create_hook(HookPoint('list_commands',
 
799
            "command.", (1, 17))
 
800
        self.add_hook('list_commands',
755
801
            "Called when enumerating commands. Called with a set of "
756
802
            "cmd_name strings for all the commands found so far. This set "
757
803
            " is safe to mutate - e.g. to remove a command. "
758
804
            "list_commands should return the updated set of command names.",
759
 
            (1, 17), None))
 
805
            (1, 17))
760
806
 
761
807
Command.hooks = CommandHooks()
762
808
 
776
822
    else:
777
823
        args = argv
778
824
 
779
 
    options, args = parser.parse_args(args)
 
825
    # for python 2.5 and later, optparse raises this exception if a non-ascii
 
826
    # option name is given.  See http://bugs.python.org/issue2931
 
827
    try:
 
828
        options, args = parser.parse_args(args)
 
829
    except UnicodeEncodeError,e:
 
830
        raise errors.BzrCommandError('Only ASCII permitted in option names')
 
831
 
780
832
    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
781
833
                 v is not option.OptionParser.DEFAULT_VALUE])
782
834
    return args, opts
986
1038
        Specify the number of processes that can be run concurrently (selftest).
987
1039
    """
988
1040
    trace.mutter("bazaar version: " + bzrlib.__version__)
989
 
    argv = list(argv)
 
1041
    argv = _specified_or_unicode_argv(argv)
990
1042
    trace.mutter("bzr arguments: %r", argv)
991
1043
 
992
1044
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
1021
1073
        elif a == '--coverage':
1022
1074
            opt_coverage_dir = argv[i + 1]
1023
1075
            i += 1
 
1076
        elif a == '--profile-imports':
 
1077
            pass # already handled in startup script Bug #588277
1024
1078
        elif a.startswith('-D'):
1025
1079
            debug.debug_flags.add(a[2:])
1026
1080
        else:
1048
1102
    if not opt_no_aliases:
1049
1103
        alias_argv = get_alias(argv[0])
1050
1104
        if alias_argv:
1051
 
            user_encoding = osutils.get_user_encoding()
1052
 
            alias_argv = [a.decode(user_encoding) for a in alias_argv]
1053
1105
            argv[0] = alias_argv.pop(0)
1054
1106
 
1055
1107
    cmd = argv.pop(0)
1056
 
    # We want only 'ascii' command names, but the user may have typed
1057
 
    # in a Unicode name. In that case, they should just get a
1058
 
    # 'command not found' error later.
1059
 
 
1060
1108
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
1061
1109
    run = cmd_obj.run_argv_aliases
1062
1110
    run_argv = [argv, alias_argv]
1136
1184
        new_argv = []
1137
1185
        try:
1138
1186
            # ensure all arguments are unicode strings
1139
 
            for a in argv[1:]:
 
1187
            for a in argv:
1140
1188
                if isinstance(a, unicode):
1141
1189
                    new_argv.append(a)
1142
1190
                else:
1158
1206
 
1159
1207
    :return: exit code of bzr command.
1160
1208
    """
1161
 
    argv = _specified_or_unicode_argv(argv)
 
1209
    if argv is not None:
 
1210
        argv = argv[1:]
1162
1211
    _register_builtin_commands()
1163
1212
    ret = run_bzr_catch_errors(argv)
1164
 
    bzrlib.ui.ui_factory.log_transport_activity(
1165
 
        display=('bytes' in debug.debug_flags))
1166
1213
    trace.mutter("return code %d", ret)
1167
1214
    return ret
1168
1215
 
1221
1268
 
1222
1269
 
1223
1270
class Provider(object):
1224
 
    '''Generic class to be overriden by plugins'''
 
1271
    """Generic class to be overriden by plugins"""
1225
1272
 
1226
1273
    def plugin_for_command(self, cmd_name):
1227
 
        '''Takes a command and returns the information for that plugin
 
1274
        """Takes a command and returns the information for that plugin
1228
1275
 
1229
1276
        :return: A dictionary with all the available information
1230
 
        for the requested plugin
1231
 
        '''
 
1277
            for the requested plugin
 
1278
        """
1232
1279
        raise NotImplementedError
1233
1280
 
1234
1281
 
1235
1282
class ProvidersRegistry(registry.Registry):
1236
 
    '''This registry exists to allow other providers to exist'''
 
1283
    """This registry exists to allow other providers to exist"""
1237
1284
 
1238
1285
    def __iter__(self):
1239
1286
        for key, provider in self.iteritems():