integrated portalocker with htmltmpl
This commit is contained in:
parent
6bf282eab6
commit
2107817687
@ -44,6 +44,7 @@ import cgi # for HTML escaping of variables
|
||||
import urllib # for URL escaping of variables
|
||||
import cPickle # for template compilation
|
||||
import gettext
|
||||
import portalocker # for locking
|
||||
|
||||
INCLUDE_DIR = "inc"
|
||||
|
||||
@ -57,25 +58,6 @@ PARAM_ESCAPE = 2
|
||||
PARAM_GLOBAL = 3
|
||||
PARAM_GETTEXT_STRING = 1
|
||||
|
||||
# Find a way to lock files. Currently implemented only for UNIX and windows.
|
||||
LOCKTYPE_FCNTL = 1
|
||||
LOCKTYPE_MSVCRT = 2
|
||||
LOCKTYPE = None
|
||||
try:
|
||||
import fcntl
|
||||
except:
|
||||
try:
|
||||
import msvcrt
|
||||
except:
|
||||
LOCKTYPE = None
|
||||
else:
|
||||
LOCKTYPE = LOCKTYPE_MSVCRT
|
||||
else:
|
||||
LOCKTYPE = LOCKTYPE_FCNTL
|
||||
LOCK_EX = 1
|
||||
LOCK_SH = 2
|
||||
LOCK_UN = 3
|
||||
|
||||
##############################################
|
||||
# CLASS: TemplateManager #
|
||||
##############################################
|
||||
@ -129,13 +111,6 @@ class TemplateManager:
|
||||
|
||||
The <em>TemplateError</em>exception is raised when the precompiled
|
||||
template cannot be saved. Precompilation is enabled by default.
|
||||
|
||||
Precompilation is available only on UNIX and Windows platforms,
|
||||
because proper file locking which is necessary to ensure
|
||||
multitask safe behaviour is platform specific and is not
|
||||
implemented for other platforms. Attempts to enable precompilation
|
||||
on the other platforms result in raise of the
|
||||
<em>TemplateError</em> exception.
|
||||
|
||||
@param comments Enable or disable template comments.
|
||||
This optional parameter can be used to enable or disable
|
||||
@ -159,13 +134,6 @@ class TemplateManager:
|
||||
self._gettext = gettext
|
||||
self._debug = debug
|
||||
|
||||
# Find what module to use to lock files.
|
||||
# File locking is necessary for the 'precompile' feature to be
|
||||
# multitask/thread safe. Currently it works only on UNIX
|
||||
# and Windows. Anyone willing to implement it on Mac ?
|
||||
if precompile and not LOCKTYPE:
|
||||
raise TemplateError, "Template precompilation is not "\
|
||||
"available on this platform."
|
||||
self.DEB("INIT DONE")
|
||||
|
||||
def prepare(self, file):
|
||||
@ -260,33 +228,6 @@ class TemplateManager:
|
||||
"""
|
||||
if self._debug: print >> sys.stderr, str
|
||||
|
||||
def lock_file(self, file, lock):
|
||||
""" Provide platform independent file locking.
|
||||
@hidden
|
||||
"""
|
||||
fd = file.fileno()
|
||||
if LOCKTYPE == LOCKTYPE_FCNTL:
|
||||
if lock == LOCK_SH:
|
||||
fcntl.flock(fd, fcntl.LOCK_SH)
|
||||
elif lock == LOCK_EX:
|
||||
fcntl.flock(fd, fcntl.LOCK_EX)
|
||||
elif lock == LOCK_UN:
|
||||
fcntl.flock(fd, fcntl.LOCK_UN)
|
||||
else:
|
||||
raise TemplateError, "BUG: bad lock in lock_file"
|
||||
elif LOCKTYPE == LOCKTYPE_MSVCRT:
|
||||
if lock == LOCK_SH:
|
||||
# msvcrt does not support shared locks :-(
|
||||
msvcrt.locking(fd, msvcrt.LK_LOCK, 1)
|
||||
elif lock == LOCK_EX:
|
||||
msvcrt.locking(fd, msvcrt.LK_LOCK, 1)
|
||||
elif lock == LOCK_UN:
|
||||
msvcrt.locking(fd, msvcrt.LK_UNLCK, 1)
|
||||
else:
|
||||
raise TemplateError, "BUG: bad lock in lock_file"
|
||||
else:
|
||||
raise TemplateError, "BUG: bad locktype in lock_file"
|
||||
|
||||
def compile(self, file):
|
||||
""" Compile the template.
|
||||
@hidden
|
||||
@ -322,7 +263,7 @@ class TemplateManager:
|
||||
file = None
|
||||
try:
|
||||
file = open(filename, "rb")
|
||||
self.lock_file(file, LOCK_SH)
|
||||
portalocker.lock(file, portalocker.LOCK_SH)
|
||||
precompiled = cPickle.load(file)
|
||||
except IOError, (errno, errstr):
|
||||
raise TemplateError, "IO error in load precompiled "\
|
||||
@ -338,7 +279,7 @@ class TemplateManager:
|
||||
return precompiled
|
||||
finally:
|
||||
if file:
|
||||
self.lock_file(file, LOCK_UN)
|
||||
portalocker.unlock(file)
|
||||
file.close()
|
||||
if remove_bad and os.path.isfile(filename):
|
||||
# X: We may lose the original exception here, raising OSError.
|
||||
@ -369,7 +310,7 @@ class TemplateManager:
|
||||
file = None
|
||||
try:
|
||||
file = open(filename, "wb") # may truncate existing file
|
||||
self.lock_file(file, LOCK_EX)
|
||||
portalocker.lock(file, portalocker.LOCK_EX)
|
||||
BINARY = 1
|
||||
READABLE = 0
|
||||
if self._debug:
|
||||
@ -393,7 +334,7 @@ class TemplateManager:
|
||||
self.DEB("SAVING PRECOMPILED")
|
||||
finally:
|
||||
if file:
|
||||
self.lock_file(file, LOCK_UN)
|
||||
portalocker.unlock(file)
|
||||
file.close()
|
||||
if remove_bad and os.path.isfile(filename):
|
||||
# X: We may lose the original exception here, raising OSError.
|
||||
|
93
planet/portalocker.py
Normal file
93
planet/portalocker.py
Normal file
@ -0,0 +1,93 @@
|
||||
# portalocker.py - Cross-platform (posix/nt) API for flock-style file locking.
|
||||
# Requires python 1.5.2 or better.
|
||||
# See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65203/index_txt
|
||||
# Except where otherwise noted, recipes in the Python Cookbook are
|
||||
# published under the Python license.
|
||||
|
||||
"""Cross-platform (posix/nt) API for flock-style file locking.
|
||||
|
||||
Synopsis:
|
||||
|
||||
import portalocker
|
||||
file = open("somefile", "r+")
|
||||
portalocker.lock(file, portalocker.LOCK_EX)
|
||||
file.seek(12)
|
||||
file.write("foo")
|
||||
file.close()
|
||||
|
||||
If you know what you're doing, you may choose to
|
||||
|
||||
portalocker.unlock(file)
|
||||
|
||||
before closing the file, but why?
|
||||
|
||||
Methods:
|
||||
|
||||
lock( file, flags )
|
||||
unlock( file )
|
||||
|
||||
Constants:
|
||||
|
||||
LOCK_EX
|
||||
LOCK_SH
|
||||
LOCK_NB
|
||||
|
||||
I learned the win32 technique for locking files from sample code
|
||||
provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
|
||||
that accompanies the win32 modules.
|
||||
|
||||
Author: Jonathan Feinberg <jdf@pobox.com>
|
||||
Version: $Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp $
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
if os.name == 'nt':
|
||||
import win32con
|
||||
import win32file
|
||||
import pywintypes
|
||||
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
|
||||
LOCK_SH = 0 # the default
|
||||
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
|
||||
# is there any reason not to reuse the following structure?
|
||||
__overlapped = pywintypes.OVERLAPPED()
|
||||
elif os.name == 'posix':
|
||||
import fcntl
|
||||
LOCK_EX = fcntl.LOCK_EX
|
||||
LOCK_SH = fcntl.LOCK_SH
|
||||
LOCK_NB = fcntl.LOCK_NB
|
||||
else:
|
||||
raise RuntimeError("PortaLocker only defined for nt and posix platforms")
|
||||
|
||||
if os.name == 'nt':
|
||||
def lock(file, flags):
|
||||
hfile = win32file._get_osfhandle(file.fileno())
|
||||
win32file.LockFileEx(hfile, flags, 0, -0x10000, __overlapped)
|
||||
|
||||
def unlock(file):
|
||||
hfile = win32file._get_osfhandle(file.fileno())
|
||||
win32file.UnlockFileEx(hfile, 0, -0x10000, __overlapped)
|
||||
|
||||
elif os.name =='posix':
|
||||
def lock(file, flags):
|
||||
fcntl.flock(file.fileno(), flags)
|
||||
|
||||
def unlock(file):
|
||||
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from time import time, strftime, localtime
|
||||
import sys
|
||||
import portalocker
|
||||
|
||||
log = open('log.txt', "a+")
|
||||
portalocker.lock(log, portalocker.LOCK_EX)
|
||||
|
||||
timestamp = strftime("%m/%d/%Y %H:%M:%S\n", localtime(time()))
|
||||
log.write( timestamp )
|
||||
|
||||
print "Wrote lines. Hit enter to release lock."
|
||||
dummy = sys.stdin.readline()
|
||||
|
||||
log.close()
|
||||
|
@ -225,7 +225,7 @@ def template_info(source):
|
||||
|
||||
def run(script, doc, output_file=None, options={}):
|
||||
""" process an HTMLTMPL file """
|
||||
manager = htmltmpl.TemplateManager(precompile=(sys.platform.find('win')<0))
|
||||
manager = htmltmpl.TemplateManager()
|
||||
template = manager.prepare(script)
|
||||
tp = htmltmpl.TemplateProcessor(html_escape=0)
|
||||
for key,value in template_info(doc).items():
|
||||
|
@ -32,7 +32,7 @@ class ApplyTest(unittest.TestCase):
|
||||
for file in ['index.html', 'default.css', 'images/foaf.png']:
|
||||
path = os.path.join(workdir, file)
|
||||
self.assertTrue(os.path.exists(path))
|
||||
self.assertTrue(os.stat(path).st_size > 0)
|
||||
self.assertTrue(os.stat(path).st_size > 0, file + ' has size 0')
|
||||
|
||||
# verify that index.html is well formed, has content, and xml:lang
|
||||
html = open(os.path.join(workdir, 'index.html'))
|
||||
|
Loading…
x
Reference in New Issue
Block a user