Code

*** empty log message ***
[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.7 2003-08-26 00:29:20 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 import os
45 if os.name == 'nt':
46     import win32con
47     import win32file
48     import pywintypes
49     LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
50     LOCK_SH = 0 # the default
51     LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
52     # is there any reason not to reuse the following structure?
53     __overlapped = pywintypes.OVERLAPPED()
54 elif os.name == 'posix':
55     import fcntl
56     LOCK_EX = fcntl.LOCK_EX
57     LOCK_SH = fcntl.LOCK_SH
58     LOCK_NB = fcntl.LOCK_NB
59 else:
60     raise RuntimeError("PortaLocker only defined for nt and posix platforms")
62 if os.name == 'nt':
63     # eugh, we want 0xffff0000 here, but python 2.3 won't let us :(
64     FFFF0000 = -65536
65     def lock(file, flags):
66         hfile = win32file._get_osfhandle(file.fileno())
67         # LockFileEx is not supported on all Win32 platforms (Win95, Win98, WinME).
68         # If it's not supported, win32file will raise an exception.
69         # Try LockFileEx first, as it has more functionality and handles
70         # blocking locks more efficiently.
71         try:
72             win32file.LockFileEx(hfile, flags, 0, FFFF0000, __overlapped)
73         except win32file.error, e:
74             import winerror
75             # Propagate upwards all exceptions other than not-implemented.
76             if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
77                 raise e
78             
79             # LockFileEx is not supported. Use LockFile.
80             # LockFile does not support shared locking -- always exclusive.
81             # Care: the low/high length params are reversed compared to LockFileEx.
82             if not flags & LOCK_EX:
83                 import warnings
84                 warnings.warn("PortaLocker does not support shared locking on Win9x", RuntimeWarning)
85             # LockFile only supports immediate-fail locking.
86             if flags & LOCK_NB:
87                 win32file.LockFile(hfile, 0, 0, FFFF0000, 0)
88             else:
89                 # Emulate a blocking lock with a polling loop.
90                 import time
91                 while 1:
92                     # Attempt a lock.
93                     try:
94                         win32file.LockFile(hfile, 0, 0, FFFF0000, 0)
95                         break
96                     except win32file.error, e:
97                         # Propagate upwards all exceptions other than lock violation.
98                         if e[0] != winerror.ERROR_LOCK_VIOLATION:
99                             raise e
100                     # Sleep and poll again.
101                     time.sleep(0.1)
102         # TODO: should this return the result of the lock?
103                     
104     def unlock(file):
105         hfile = win32file._get_osfhandle(file.fileno())
106         # UnlockFileEx is not supported on all Win32 platforms (Win95, Win98, WinME).
107         # If it's not supported, win32file will raise an api_error exception.
108         try:
109             win32file.UnlockFileEx(hfile, 0, FFFF0000, __overlapped)
110         except win32file.error, e:
111             import winerror
112             # Propagate upwards all exceptions other than not-implemented.
113             if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
114                 raise e
115             
116             # UnlockFileEx is not supported. Use UnlockFile.
117             # Care: the low/high length params are reversed compared to UnLockFileEx.
118             win32file.UnlockFile(hfile, 0, 0, FFFF0000, 0)
120 elif os.name =='posix':
121     def lock(file, flags):
122         fcntl.flock(file.fileno(), flags)
123         # TODO: should this return the result of the lock?
125     def unlock(file):
126         fcntl.flock(file.fileno(), fcntl.LOCK_UN)
128 if __name__ == '__main__':
129     from time import time, strftime, localtime
130     import sys
131     import portalocker
133     log = open('log.txt', "a+")
134     portalocker.lock(log, portalocker.LOCK_EX)
136     timestamp = strftime("%m/%d/%Y %H:%M:%S\n", localtime(time()))
137     log.write( timestamp )
139     print "Wrote lines. Hit enter to release lock."
140     dummy = sys.stdin.readline()
142     log.close()