/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/lock.py

  • Committer: Jelmer Vernooij
  • Date: 2018-11-16 10:50:21 UTC
  • mfrom: (7164 work)
  • mto: This revision was merged to the branch mainline in revision 7165.
  • Revision ID: jelmer@jelmer.uk-20181116105021-xl419v2rh4aus1au
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
 
18
17
"""Locking using OS file locks or file existence.
19
18
 
20
19
Note: This method of locking is generally deprecated in favour of LockDir, but
34
33
unlock() method.
35
34
"""
36
35
 
 
36
from __future__ import absolute_import
 
37
 
 
38
import contextlib
37
39
import errno
38
40
import os
39
41
import sys
40
42
import warnings
41
43
 
42
 
from bzrlib import (
 
44
from . import (
43
45
    debug,
44
46
    errors,
45
47
    osutils,
46
48
    trace,
47
49
    )
48
 
from bzrlib.hooks import HookPoint, Hooks
49
 
 
 
50
from .hooks import Hooks
 
51
from .i18n import gettext
50
52
 
51
53
class LockHooks(Hooks):
52
54
 
53
55
    def __init__(self):
54
 
        Hooks.__init__(self)
55
 
        self.create_hook(HookPoint('lock_acquired',
56
 
            "Called with a bzrlib.lock.LockResult when a physical lock is "
57
 
            "acquired.", (1, 8), None))
58
 
        self.create_hook(HookPoint('lock_released',
59
 
            "Called with a bzrlib.lock.LockResult when a physical lock is "
60
 
            "released.", (1, 8), None))
61
 
        self.create_hook(HookPoint('lock_broken',
62
 
            "Called with a bzrlib.lock.LockResult when a physical lock is "
63
 
            "broken.", (1, 15), None))
 
56
        Hooks.__init__(self, "breezy.lock", "Lock.hooks")
 
57
        self.add_hook('lock_acquired',
 
58
            "Called with a breezy.lock.LockResult when a physical lock is "
 
59
            "acquired.", (1, 8))
 
60
        self.add_hook('lock_released',
 
61
            "Called with a breezy.lock.LockResult when a physical lock is "
 
62
            "released.", (1, 8))
 
63
        self.add_hook('lock_broken',
 
64
            "Called with a breezy.lock.LockResult when a physical lock is "
 
65
            "broken.", (1, 15))
64
66
 
65
67
 
66
68
class Lock(object):
88
90
                             self.lock_url, self.details)
89
91
 
90
92
 
 
93
class LogicalLockResult(object):
 
94
    """The result of a lock_read/lock_write/lock_tree_write call on lockables.
 
95
 
 
96
    :ivar unlock: A callable which will unlock the lock.
 
97
    """
 
98
 
 
99
    def __init__(self, unlock, token=None):
 
100
        self.unlock = unlock
 
101
        self.token = token
 
102
 
 
103
    def __repr__(self):
 
104
        return "LogicalLockResult(%s)" % (self.unlock)
 
105
 
 
106
    def __enter__(self):
 
107
        return self
 
108
 
 
109
    def __exit__(self, exc_type, exc_val, exc_tb):
 
110
        # If there was an error raised, prefer the original one
 
111
        try:
 
112
            self.unlock()
 
113
        except:
 
114
            if exc_type is None:
 
115
                raise
 
116
        return False
 
117
 
 
118
 
91
119
def cant_unlock_not_held(locked_object):
92
120
    """An attempt to unlock failed because the object was not locked.
93
121
 
139
167
        try:
140
168
            self.f = open(self.filename, filemode)
141
169
            return self.f
142
 
        except IOError, e:
 
170
        except IOError as e:
143
171
            if e.errno in (errno.EACCES, errno.EPERM):
144
172
                raise errors.LockFailed(self.filename, str(e))
145
173
            if e.errno != errno.ENOENT:
157
185
            self.f.close()
158
186
            self.f = None
159
187
 
160
 
    def __del__(self):
161
 
        if self.f:
162
 
            from warnings import warn
163
 
            warn("lock on %r not released" % self.f)
164
 
            self.unlock()
165
 
 
166
188
    def unlock(self):
167
189
        raise NotImplementedError()
168
190
 
207
229
                # LOCK_NB will cause IOError to be raised if we can't grab a
208
230
                # lock right away.
209
231
                fcntl.lockf(self.f, fcntl.LOCK_EX | fcntl.LOCK_NB)
210
 
            except IOError, e:
 
232
            except IOError as e:
211
233
                if e.errno in (errno.EAGAIN, errno.EACCES):
212
234
                    # We couldn't grab the lock
213
235
                    self.unlock()
242
264
                # LOCK_NB will cause IOError to be raised if we can't grab a
243
265
                # lock right away.
244
266
                fcntl.lockf(self.f, fcntl.LOCK_SH | fcntl.LOCK_NB)
245
 
            except IOError, e:
 
267
            except IOError as e:
246
268
                # we should be more precise about whats a locking
247
269
                # error and whats a random-other error
248
270
                raise errors.LockContention(self.filename, e)
303
325
            # done by _fcntl_ReadLock
304
326
            try:
305
327
                new_f = open(self.filename, 'rb+')
306
 
            except IOError, e:
 
328
            except IOError as e:
307
329
                if e.errno in (errno.EACCES, errno.EPERM):
308
330
                    raise errors.LockFailed(self.filename, str(e))
309
331
                raise
311
333
                # LOCK_NB will cause IOError to be raised if we can't grab a
312
334
                # lock right away.
313
335
                fcntl.lockf(new_f, fcntl.LOCK_EX | fcntl.LOCK_NB)
314
 
            except IOError, e:
 
336
            except IOError as e:
315
337
                # TODO: Raise a more specific error based on the type of error
316
338
                raise errors.LockContention(self.filename, e)
317
339
            _fcntl_WriteLock._open_locks.add(self.filename)
335
357
 
336
358
 
337
359
if have_pywin32 and sys.platform == 'win32':
338
 
    if os.path.supports_unicode_filenames:
339
 
        # for Windows NT/2K/XP/etc
340
 
        win32file_CreateFile = win32file.CreateFileW
341
 
    else:
342
 
        # for Windows 98
343
 
        win32file_CreateFile = win32file.CreateFile
 
360
    win32file_CreateFile = win32file.CreateFileW
344
361
 
345
362
    class _w32c_FileLock(_OSLock):
346
363
 
350
367
                self._handle = win32file_CreateFile(filename, access, share,
351
368
                    None, win32file.OPEN_ALWAYS,
352
369
                    win32file.FILE_ATTRIBUTE_NORMAL, None)
353
 
            except pywintypes.error, e:
 
370
            except pywintypes.error as e:
354
371
                if e.args[0] == winerror.ERROR_ACCESS_DENIED:
355
372
                    raise errors.LockFailed(filename, e)
356
373
                if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
410
427
 
411
428
 
412
429
if have_ctypes_win32:
413
 
    from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
 
430
    from ctypes.wintypes import DWORD, LPWSTR
414
431
    LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
415
432
    HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
416
 
    if os.path.supports_unicode_filenames:
417
 
        _function_name = "CreateFileW"
418
 
        LPTSTR = LPCWSTR
419
 
    else:
420
 
        _function_name = "CreateFileA"
421
 
        class LPTSTR(LPCSTR):
422
 
            def __new__(cls, obj):
423
 
                return LPCSTR.__new__(cls, obj.encode("mbcs"))
 
433
    _function_name = "CreateFileW"
424
434
 
425
435
    # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
426
436
    _CreateFile = ctypes.WINFUNCTYPE(
427
437
            HANDLE,                # return value
428
 
            LPTSTR,                # lpFileName
 
438
            LPWSTR,                # lpFileName
429
439
            DWORD,                 # dwDesiredAccess
430
440
            DWORD,                 # dwShareMode
431
441
            LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
527
537
    locked the same way), and -Drelock is set, then this will trace.note a
528
538
    message about it.
529
539
    """
530
 
    
 
540
 
531
541
    _prev_lock = None
532
542
 
533
543
    def _note_lock(self, lock_type):
536
546
                type_name = 'read'
537
547
            else:
538
548
                type_name = 'write'
539
 
            trace.note('%r was %s locked again', self, type_name)
 
549
            trace.note(gettext('{0!r} was {1} locked again'), self, type_name)
540
550
        self._prev_lock = lock_type
541
551
 
 
552
@contextlib.contextmanager
 
553
def write_locked(lockable):
 
554
    lockable.lock_write()
 
555
    try:
 
556
        yield lockable
 
557
    finally:
 
558
        lockable.unlock()