/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 breezy/cleanup.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-02-03 23:21:15 UTC
  • mfrom: (7290.42.6 paramiko-compat)
  • Revision ID: breezy.the.bot@gmail.com-20200203232115-g7k11bhsfeiqcprv
Fix compatibility with newer versions of paramiko, which break on noise before keys in pem files.

Merged from https://code.launchpad.net/~jelmer/brz/paramiko-compat/+merge/378480

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2009, 2010 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
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
 
16
 
 
17
"""Helpers for managing cleanup functions and the errors they might raise.
 
18
 
 
19
This currently just contains a copy of contextlib.ExitStack, available
 
20
even on older versions of Python.
 
21
"""
 
22
 
 
23
from __future__ import absolute_import
 
24
 
 
25
from collections import deque
 
26
import sys
 
27
 
 
28
 
 
29
try:
 
30
    from contextlib import ExitStack
 
31
except ImportError:
 
32
    # Copied from the Python standard library on Python 3.4.
 
33
    # Copyright: Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
 
34
    #   2009, 2010, 2011 Python Software Foundation
 
35
    #
 
36
    # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
 
37
    # --------------------------------------------
 
38
    # .
 
39
    # 1. This LICENSE AGREEMENT is between the Python Software Foundation
 
40
    # ("PSF"), and the Individual or Organization ("Licensee") accessing and
 
41
    # otherwise using this software ("Python") in source or binary form and
 
42
    # its associated documentation.
 
43
    # .
 
44
    # 2. Subject to the terms and conditions of this License Agreement, PSF hereby
 
45
    # grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
 
46
    # analyze, test, perform and/or display publicly, prepare derivative works,
 
47
    # distribute, and otherwise use Python alone or in any derivative version,
 
48
    # provided, however, that PSF's License Agreement and PSF's notice of copyright,
 
49
    # i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
50
    # 2011 Python Software Foundation; All Rights Reserved" are retained in Python
 
51
    # alone or in any derivative version prepared by Licensee.
 
52
    # .
 
53
    # 3. In the event Licensee prepares a derivative work that is based on
 
54
    # or incorporates Python or any part thereof, and wants to make
 
55
    # the derivative work available to others as provided herein, then
 
56
    # Licensee hereby agrees to include in any such work a brief summary of
 
57
    # the changes made to Python.
 
58
    # .
 
59
    # 4. PSF is making Python available to Licensee on an "AS IS"
 
60
    # basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
 
61
    # IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
 
62
    # DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
 
63
    # FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
 
64
    # INFRINGE ANY THIRD PARTY RIGHTS.
 
65
    # .
 
66
    # 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
 
67
    # FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
 
68
    # A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
 
69
    # OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
 
70
    # .
 
71
    # 6. This License Agreement will automatically terminate upon a material
 
72
    # breach of its terms and conditions.
 
73
    # .
 
74
    # 7. Nothing in this License Agreement shall be deemed to create any
 
75
    # relationship of agency, partnership, or joint venture between PSF and
 
76
    # Licensee.  This License Agreement does not grant permission to use PSF
 
77
    # trademarks or trade name in a trademark sense to endorse or promote
 
78
    # products or services of Licensee, or any third party.
 
79
    # .
 
80
    # 8. By copying, installing or otherwise using Python, Licensee
 
81
    # agrees to be bound by the terms and conditions of this License
 
82
    # Agreement.
 
83
 
 
84
    def _reraise_with_existing_context(exc_details):
 
85
        # Use 3 argument raise in Python 2,
 
86
        # but use exec to avoid SyntaxError in Python 3
 
87
        exc_type, exc_value, exc_tb = exc_details
 
88
        exec("raise exc_type, exc_value, exc_tb")
 
89
 
 
90
 
 
91
    # Inspired by discussions on http://bugs.python.org/issue13585
 
92
    class ExitStack(object):
 
93
        """Context manager for dynamic management of a stack of exit callbacks
 
94
 
 
95
        For example:
 
96
 
 
97
            with ExitStack() as stack:
 
98
                files = [stack.enter_context(open(fname)) for fname in filenames]
 
99
                # All opened files will automatically be closed at the end of
 
100
                # the with statement, even if attempts to open files later
 
101
                # in the list raise an exception
 
102
 
 
103
        """
 
104
        def __init__(self):
 
105
            self._exit_callbacks = deque()
 
106
 
 
107
        def pop_all(self):
 
108
            """Preserve the context stack by transferring it to a new instance"""
 
109
            new_stack = type(self)()
 
110
            new_stack._exit_callbacks = self._exit_callbacks
 
111
            self._exit_callbacks = deque()
 
112
            return new_stack
 
113
 
 
114
        def _push_cm_exit(self, cm, cm_exit):
 
115
            """Helper to correctly register callbacks to __exit__ methods"""
 
116
            def _exit_wrapper(*exc_details):
 
117
                return cm_exit(cm, *exc_details)
 
118
            _exit_wrapper.__self__ = cm
 
119
            self.push(_exit_wrapper)
 
120
 
 
121
        def push(self, exit):
 
122
            """Registers a callback with the standard __exit__ method signature
 
123
 
 
124
            Can suppress exceptions the same way __exit__ methods can.
 
125
 
 
126
            Also accepts any object with an __exit__ method (registering a call
 
127
            to the method instead of the object itself)
 
128
            """
 
129
            # We use an unbound method rather than a bound method to follow
 
130
            # the standard lookup behaviour for special methods
 
131
            _cb_type = type(exit)
 
132
            try:
 
133
                exit_method = _cb_type.__exit__
 
134
            except AttributeError:
 
135
                # Not a context manager, so assume its a callable
 
136
                self._exit_callbacks.append(exit)
 
137
            else:
 
138
                self._push_cm_exit(exit, exit_method)
 
139
            return exit # Allow use as a decorator
 
140
 
 
141
        def callback(self, callback, *args, **kwds):
 
142
            """Registers an arbitrary callback and arguments.
 
143
 
 
144
            Cannot suppress exceptions.
 
145
            """
 
146
            def _exit_wrapper(exc_type, exc, tb):
 
147
                callback(*args, **kwds)
 
148
            # We changed the signature, so using @wraps is not appropriate, but
 
149
            # setting __wrapped__ may still help with introspection
 
150
            _exit_wrapper.__wrapped__ = callback
 
151
            self.push(_exit_wrapper)
 
152
            return callback # Allow use as a decorator
 
153
 
 
154
        def enter_context(self, cm):
 
155
            """Enters the supplied context manager
 
156
 
 
157
            If successful, also pushes its __exit__ method as a callback and
 
158
            returns the result of the __enter__ method.
 
159
            """
 
160
            # We look up the special methods on the type to match the with statement
 
161
            _cm_type = type(cm)
 
162
            _exit = _cm_type.__exit__
 
163
            result = _cm_type.__enter__(cm)
 
164
            self._push_cm_exit(cm, _exit)
 
165
            return result
 
166
 
 
167
        def close(self):
 
168
            """Immediately unwind the context stack"""
 
169
            self.__exit__(None, None, None)
 
170
 
 
171
        def __enter__(self):
 
172
            return self
 
173
 
 
174
        def __exit__(self, *exc_details):
 
175
            received_exc = exc_details[0] is not None
 
176
 
 
177
            # We manipulate the exception state so it behaves as though
 
178
            # we were actually nesting multiple with statements
 
179
            frame_exc = sys.exc_info()[1]
 
180
            def _make_context_fixer(frame_exc):
 
181
                return lambda new_exc, old_exc: None
 
182
            _fix_exception_context = _make_context_fixer(frame_exc)
 
183
 
 
184
            # Callbacks are invoked in LIFO order to match the behaviour of
 
185
            # nested context managers
 
186
            suppressed_exc = False
 
187
            pending_raise = False
 
188
            while self._exit_callbacks:
 
189
                cb = self._exit_callbacks.pop()
 
190
                try:
 
191
                    if cb(*exc_details):
 
192
                        suppressed_exc = True
 
193
                        pending_raise = False
 
194
                        exc_details = (None, None, None)
 
195
                except:
 
196
                    new_exc_details = sys.exc_info()
 
197
                    # simulate the stack of exceptions by setting the context
 
198
                    _fix_exception_context(new_exc_details[1], exc_details[1])
 
199
                    pending_raise = True
 
200
                    exc_details = new_exc_details
 
201
            if pending_raise:
 
202
                _reraise_with_existing_context(exc_details)
 
203
            return received_exc and suppressed_exc