4
4
# This module is part of GitPython and is released under
5
5
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
6
6
7
+ from fcntl import flock , LOCK_UN , LOCK_EX , LOCK_NB
7
8
import os
8
9
import re
9
10
import sys
@@ -324,12 +325,12 @@ def update(self, op_code, cur_count, max_count=None, message=''):
324
325
325
326
You may read the contents of the current line in self._cur_line"""
326
327
pass
327
-
328
+
328
329
329
330
class CallableRemoteProgress (RemoteProgress ):
330
331
"""An implementation forwarding updates to any callable"""
331
332
__slots__ = ('_callable' )
332
-
333
+
333
334
def __init__ (self , fn ):
334
335
self ._callable = fn
335
336
super (CallableRemoteProgress , self ).__init__ ()
@@ -535,9 +536,10 @@ class LockFile(object):
535
536
As we are a utility class to be derived from, we only use protected methods.
536
537
537
538
Locks will automatically be released on destruction"""
538
- __slots__ = ("_file_path" , "_owns_lock" )
539
+ __slots__ = ("_file_path" , "_owns_lock" , "_file_descriptor" )
539
540
540
541
def __init__ (self , file_path ):
542
+ self ._file_descriptor = None
541
543
self ._file_path = file_path
542
544
self ._owns_lock = False
543
545
@@ -559,17 +561,24 @@ def _obtain_lock_or_raise(self):
559
561
:raise IOError: if a lock was already present or a lock file could not be written"""
560
562
if self ._has_lock ():
561
563
return
564
+
562
565
lock_file = self ._lock_file_path ()
563
- if os .path .isfile (lock_file ):
564
- raise IOError ("Lock for file %r did already exist, delete %r in case the lock is illegal" %
565
- (self ._file_path , lock_file ))
566
+
567
+ # Create lock file
568
+ try :
569
+ open (lock_file , 'a' ).close ()
570
+ except OSError as e :
571
+ # Silence error only if file exists
572
+ if e .errno != 17 : # 17 -> File exists
573
+ raise
566
574
567
575
try :
568
- fd = os .open (lock_file , os .O_WRONLY | os . O_CREAT | os . O_EXCL , 0 )
569
- os . close (fd )
576
+ fd = os .open (lock_file , os .O_WRONLY , 0 )
577
+ flock (fd , LOCK_EX | LOCK_NB )
570
578
except OSError as e :
571
579
raise IOError (str (e ))
572
580
581
+ self ._file_descriptor = fd
573
582
self ._owns_lock = True
574
583
575
584
def _obtain_lock (self ):
@@ -582,19 +591,15 @@ def _release_lock(self):
582
591
if not self ._has_lock ():
583
592
return
584
593
585
- # if someone removed our file beforhand, lets just flag this issue
586
- # instead of failing, to make it more usable.
587
- lfp = self ._lock_file_path ()
588
- try :
589
- # on bloody windows, the file needs write permissions to be removable.
590
- # Why ...
591
- if os .name == 'nt' :
592
- os .chmod (lfp , 0o777 )
593
- # END handle win32
594
- os .remove (lfp )
595
- except OSError :
596
- pass
594
+ fd = self ._file_descriptor
595
+ lock_file = self ._lock_file_path ()
596
+
597
+ flock (fd , LOCK_UN )
598
+ os .close (fd )
599
+ os .remove (lock_file )
600
+
597
601
self ._owns_lock = False
602
+ self ._file_descriptor = None
598
603
599
604
600
605
class BlockingLockFile (LockFile ):
@@ -629,7 +634,7 @@ def _obtain_lock(self):
629
634
try :
630
635
super (BlockingLockFile , self )._obtain_lock ()
631
636
except IOError :
632
- # synity check: if the directory leading to the lockfile is not
637
+ # sanity check: if the directory leading to the lockfile is not
633
638
# readable anymore, raise an execption
634
639
curtime = time .time ()
635
640
if not os .path .isdir (os .path .dirname (self ._lock_file_path ())):
0 commit comments