/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: John Arbash Meinel
  • Date: 2011-04-20 14:27:19 UTC
  • mto: This revision was merged to the branch mainline in revision 5837.
  • Revision ID: john@arbash-meinel.com-20110420142719-advs1k5vztqzbrgv
Fix bug #767177. Be more agressive with file.close() calls.

Our test suite gets a number of thread leaks and failures because it happens to get async
SFTPFile.close() calls. (if an SFTPFile closes due to __del__ it is done as an async request,
while if you call SFTPFile.close() it is done as a synchronous request.)
We have a couple other cases, probably. Namely SFTPTransport.get() also does an async
prefetch of the content, so if you don't .read() you'll also leak threads that think they
are doing work that you want.

The biggest change here, though, is using a try/finally in a generator, which is not 
python2.4 compatible.

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()
482
493
            message explaining how to obtain full help.
483
494
        """
484
495
        doc = self.help()
485
 
        if doc is None:
486
 
            raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
 
496
        if not doc:
 
497
            doc = "No help for this command."
487
498
 
488
499
        # Extract the summary (purpose) and sections out from the text
489
500
        purpose,sections,order = self._get_help_parts(doc)
682
693
 
683
694
        self._setup_outf()
684
695
 
685
 
        return self.run(**all_cmd_args)
 
696
        try:
 
697
            return self.run(**all_cmd_args)
 
698
        finally:
 
699
            # reset it, so that other commands run in the same process won't
 
700
            # inherit state. Before we reset it, log any activity, so that it
 
701
            # gets properly tracked.
 
702
            ui.ui_factory.log_transport_activity(
 
703
                display=('bytes' in debug.debug_flags))
 
704
            trace.set_verbosity_level(0)
686
705
 
687
706
    def _setup_run(self):
688
707
        """Wrap the defined run method on self with a cleanup.
739
758
        return getdoc(self)
740
759
 
741
760
    def name(self):
 
761
        """Return the canonical name for this command.
 
762
 
 
763
        The name under which it was actually invoked is available in invoked_as.
 
764
        """
742
765
        return _unsquish_command_name(self.__class__.__name__)
743
766
 
744
767
    def plugin_name(self):
762
785
        These are all empty initially, because by default nothing should get
763
786
        notified.
764
787
        """
765
 
        Hooks.__init__(self)
766
 
        self.create_hook(HookPoint('extend_command',
 
788
        Hooks.__init__(self, "bzrlib.commands", "Command.hooks")
 
789
        self.add_hook('extend_command',
767
790
            "Called after creating a command object to allow modifications "
768
791
            "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',
 
792
            "new bzrlib.commands.Command object.", (1, 13))
 
793
        self.add_hook('get_command',
771
794
            "Called when creating a single command. Called with "
772
795
            "(cmd_or_None, command_name). get_command should either return "
773
796
            "the cmd_or_None parameter, or a replacement Command object that "
774
797
            "should be used for the command. Note that the Command.hooks "
775
798
            "hooks are core infrastructure. Many users will prefer to use "
776
799
            "bzrlib.commands.register_command or plugin_cmds.register_lazy.",
777
 
            (1, 17), None))
778
 
        self.create_hook(HookPoint('get_missing_command',
 
800
            (1, 17))
 
801
        self.add_hook('get_missing_command',
779
802
            "Called when creating a single command if no command could be "
780
803
            "found. Called with (command_name). get_missing_command should "
781
804
            "either return None, or a Command object to be used for the "
782
 
            "command.", (1, 17), None))
783
 
        self.create_hook(HookPoint('list_commands',
 
805
            "command.", (1, 17))
 
806
        self.add_hook('list_commands',
784
807
            "Called when enumerating commands. Called with a set of "
785
808
            "cmd_name strings for all the commands found so far. This set "
786
809
            " is safe to mutate - e.g. to remove a command. "
787
810
            "list_commands should return the updated set of command names.",
788
 
            (1, 17), None))
 
811
            (1, 17))
789
812
 
790
813
Command.hooks = CommandHooks()
791
814
 
805
828
    else:
806
829
        args = argv
807
830
 
808
 
    options, args = parser.parse_args(args)
 
831
    # for python 2.5 and later, optparse raises this exception if a non-ascii
 
832
    # option name is given.  See http://bugs.python.org/issue2931
 
833
    try:
 
834
        options, args = parser.parse_args(args)
 
835
    except UnicodeEncodeError,e:
 
836
        raise errors.BzrCommandError('Only ASCII permitted in option names')
 
837
 
809
838
    opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
810
839
                 v is not option.OptionParser.DEFAULT_VALUE])
811
840
    return args, opts
1015
1044
        Specify the number of processes that can be run concurrently (selftest).
1016
1045
    """
1017
1046
    trace.mutter("bazaar version: " + bzrlib.__version__)
1018
 
    argv = list(argv)
 
1047
    argv = _specified_or_unicode_argv(argv)
1019
1048
    trace.mutter("bzr arguments: %r", argv)
1020
1049
 
1021
1050
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
1050
1079
        elif a == '--coverage':
1051
1080
            opt_coverage_dir = argv[i + 1]
1052
1081
            i += 1
 
1082
        elif a == '--profile-imports':
 
1083
            pass # already handled in startup script Bug #588277
1053
1084
        elif a.startswith('-D'):
1054
1085
            debug.debug_flags.add(a[2:])
1055
1086
        else:
1077
1108
    if not opt_no_aliases:
1078
1109
        alias_argv = get_alias(argv[0])
1079
1110
        if alias_argv:
1080
 
            user_encoding = osutils.get_user_encoding()
1081
 
            alias_argv = [a.decode(user_encoding) for a in alias_argv]
1082
1111
            argv[0] = alias_argv.pop(0)
1083
1112
 
1084
1113
    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
1114
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
1090
1115
    run = cmd_obj.run_argv_aliases
1091
1116
    run_argv = [argv, alias_argv]
1165
1190
        new_argv = []
1166
1191
        try:
1167
1192
            # ensure all arguments are unicode strings
1168
 
            for a in argv[1:]:
 
1193
            for a in argv:
1169
1194
                if isinstance(a, unicode):
1170
1195
                    new_argv.append(a)
1171
1196
                else:
1187
1212
 
1188
1213
    :return: exit code of bzr command.
1189
1214
    """
1190
 
    argv = _specified_or_unicode_argv(argv)
 
1215
    if argv is not None:
 
1216
        argv = argv[1:]
1191
1217
    _register_builtin_commands()
1192
1218
    ret = run_bzr_catch_errors(argv)
1193
 
    bzrlib.ui.ui_factory.log_transport_activity(
1194
 
        display=('bytes' in debug.debug_flags))
1195
1219
    trace.mutter("return code %d", ret)
1196
1220
    return ret
1197
1221