44# This module is part of GitPython and is released under
55# the BSD License: http://www.opensource.org/licenses/bsd-license.php
66
7+ from fcntl import flock , LOCK_UN , LOCK_EX , LOCK_NB
78import os
89import re
910import sys
@@ -324,12 +325,12 @@ def update(self, op_code, cur_count, max_count=None, message=''):
324325
325326 You may read the contents of the current line in self._cur_line"""
326327 pass
327-
328+
328329
329330class CallableRemoteProgress (RemoteProgress ):
330331 """An implementation forwarding updates to any callable"""
331332 __slots__ = ('_callable' )
332-
333+
333334 def __init__ (self , fn ):
334335 self ._callable = fn
335336 super (CallableRemoteProgress , self ).__init__ ()
@@ -535,9 +536,10 @@ class LockFile(object):
535536 As we are a utility class to be derived from, we only use protected methods.
536537
537538 Locks will automatically be released on destruction"""
538- __slots__ = ("_file_path" , "_owns_lock" )
539+ __slots__ = ("_file_path" , "_owns_lock" , "_file_descriptor" )
539540
540541 def __init__ (self , file_path ):
542+ self ._file_descriptor = None
541543 self ._file_path = file_path
542544 self ._owns_lock = False
543545
@@ -559,17 +561,24 @@ def _obtain_lock_or_raise(self):
559561 :raise IOError: if a lock was already present or a lock file could not be written"""
560562 if self ._has_lock ():
561563 return
564+
562565 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
566574
567575 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 )
570578 except OSError as e :
571579 raise IOError (str (e ))
572580
581+ self ._file_descriptor = fd
573582 self ._owns_lock = True
574583
575584 def _obtain_lock (self ):
@@ -582,19 +591,15 @@ def _release_lock(self):
582591 if not self ._has_lock ():
583592 return
584593
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+
597601 self ._owns_lock = False
602+ self ._file_descriptor = None
598603
599604
600605class BlockingLockFile (LockFile ):
@@ -629,7 +634,7 @@ def _obtain_lock(self):
629634 try :
630635 super (BlockingLockFile , self )._obtain_lock ()
631636 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
633638 # readable anymore, raise an execption
634639 curtime = time .time ()
635640 if not os .path .isdir (os .path .dirname (self ._lock_file_path ())):
0 commit comments