Code

30957c0b14ef0c07aa1e07cb06ae47a2b0a134b4
[roundup.git] / roundup / backends / portalocker.py
1 # portalocker.py - Cross-platform (posix/nt) API for flock-style file locking.
2 #                  Requires python 1.5.2 or better.
4 # ID line added by richard for Roundup file tracking
5 # $Id: portalocker.py,v 1.9 2006-09-09 05:42:45 richard Exp $
7 """Cross-platform (posix/nt) API for flock-style file locking.
9 Synopsis::
11    import portalocker
12    file = open("somefile", "r+")
13    portalocker.lock(file, portalocker.LOCK_EX)
14    file.seek(12)
15    file.write("foo")
16    file.close()
18 If you know what you're doing, you may choose to::
20    portalocker.unlock(file)
22 before closing the file, but why?
24 Methods::
26    lock( file, flags )
27    unlock( file )
29 Constants::
31    LOCK_EX
32    LOCK_SH
33    LOCK_NB
35 I learned the win32 technique for locking files from sample code
36 provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
37 that accompanies the win32 modules.
39 :Author: Jonathan Feinberg <jdf@pobox.com>
40 :Version: Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp 
41           **un-cvsified by richard so the version doesn't change**
42 """
43 __docformat__ = 'restructuredtext'
45 import os
47 if os.name == 'nt':
48     import win32con
49     import win32file
50     import pywintypes
51     LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
52     LOCK_SH = 0 # the default
53     LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
54     # is there any reason not to reuse the following structure?
55     __overlapped = pywintypes.OVERLAPPED()
56 elif os.name == 'posix':
57     import fcntl
58     LOCK_EX = fcntl.LOCK_EX
59     LOCK_SH = fcntl.LOCK_SH
60     LOCK_NB = fcntl.LOCK_NB
61 else:
62     raise RuntimeError("PortaLocker only defined for nt and posix platforms")
64 if os.name == 'nt':
65     # eugh, we want 0xffff0000 here, but python 2.3 won't let us :(
66     FFFF0000 = -65536
67     def lock(file, flags):
68         hfile = win32file._get_osfhandle(file.fileno())
69         # LockFileEx is not supported on all Win32 platforms (Win95, Win98,
70         # WinME).
71         # If it's not supported, win32file will raise an exception.
72         # Try LockFileEx first, as it has more functionality and handles
73         # blocking locks more efficiently.
74         try:
75             win32file.LockFileEx(hfile, flags, 0, FFFF0000, __overlapped)
76         except win32file.error, e:
77             import winerror
78             # Propagate upwards all exceptions other than not-implemented.
79             if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
80                 raise e
81             
82             # LockFileEx is not supported. Use LockFile.
83             # LockFile does not support shared locking -- always exclusive.
84             # Care: the low/high length params are reversed compared to
85             # LockFileEx.
86             if not flags & LOCK_EX:
87                 import warnings
88                 warnings.warn("PortaLocker does not support shared "
89                     "locking on Win9x", RuntimeWarning)
90             # LockFile only supports immediate-fail locking.
91             if flags & LOCK_NB:
92                 win32file.LockFile(hfile, 0, 0, FFFF0000, 0)
93             else:
94                 # Emulate a blocking lock with a polling loop.
95                 import time
96                 while 1:
97                     # Attempt a lock.
98                     try:
99                         win32file.LockFile(hfile, 0, 0, FFFF0000, 0)
100                         break
101                     except win32file.error, e:
102                         # Propagate upwards all exceptions other than lock
103                         # violation.
104                         if e[0] != winerror.ERROR_LOCK_VIOLATION:
105                             raise e
106                     # Sleep and poll again.
107                     time.sleep(0.1)
108         # TODO: should this return the result of the lock?
109                     
110     def unlock(file):
111         hfile = win32file._get_osfhandle(file.fileno())
112         # UnlockFileEx is not supported on all Win32 platforms (Win95, Win98,
113         # WinME).
114         # If it's not supported, win32file will raise an api_error exception.
115         try:
116             win32file.UnlockFileEx(hfile, 0, FFFF0000, __overlapped)
117         except win32file.error, e:
118             import winerror
119             # Propagate upwards all exceptions other than not-implemented.
120             if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
121                 raise e
122             
123             # UnlockFileEx is not supported. Use UnlockFile.
124             # Care: the low/high length params are reversed compared to
125             # UnLockFileEx.
126             win32file.UnlockFile(hfile, 0, 0, FFFF0000, 0)
128 elif os.name =='posix':
129     def lock(file, flags):
130         fcntl.flock(file.fileno(), flags)
131         # TODO: should this return the result of the lock?
133     def unlock(file):
134         fcntl.flock(file.fileno(), fcntl.LOCK_UN)
136 if __name__ == '__main__':
137     from time import time, strftime, localtime
138     import sys
139     import portalocker
141     log = open('log.txt', "a+")
142     portalocker.lock(log, portalocker.LOCK_EX)
144     timestamp = strftime("%m/%d/%Y %H:%M:%S\n", localtime(time()))
145     log.write( timestamp )
147     print "Wrote lines. Hit enter to release lock."
148     dummy = sys.stdin.readline()
150     log.close()