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 urllib # for URL escaping of variables
|
||||||
import cPickle # for template compilation
|
import cPickle # for template compilation
|
||||||
import gettext
|
import gettext
|
||||||
|
import portalocker # for locking
|
||||||
|
|
||||||
INCLUDE_DIR = "inc"
|
INCLUDE_DIR = "inc"
|
||||||
|
|
||||||
@ -57,25 +58,6 @@ PARAM_ESCAPE = 2
|
|||||||
PARAM_GLOBAL = 3
|
PARAM_GLOBAL = 3
|
||||||
PARAM_GETTEXT_STRING = 1
|
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 #
|
# CLASS: TemplateManager #
|
||||||
##############################################
|
##############################################
|
||||||
@ -129,13 +111,6 @@ class TemplateManager:
|
|||||||
|
|
||||||
The <em>TemplateError</em>exception is raised when the precompiled
|
The <em>TemplateError</em>exception is raised when the precompiled
|
||||||
template cannot be saved. Precompilation is enabled by default.
|
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.
|
@param comments Enable or disable template comments.
|
||||||
This optional parameter can be used to enable or disable
|
This optional parameter can be used to enable or disable
|
||||||
@ -159,13 +134,6 @@ class TemplateManager:
|
|||||||
self._gettext = gettext
|
self._gettext = gettext
|
||||||
self._debug = debug
|
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")
|
self.DEB("INIT DONE")
|
||||||
|
|
||||||
def prepare(self, file):
|
def prepare(self, file):
|
||||||
@ -260,33 +228,6 @@ class TemplateManager:
|
|||||||
"""
|
"""
|
||||||
if self._debug: print >> sys.stderr, str
|
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):
|
def compile(self, file):
|
||||||
""" Compile the template.
|
""" Compile the template.
|
||||||
@hidden
|
@hidden
|
||||||
@ -322,7 +263,7 @@ class TemplateManager:
|
|||||||
file = None
|
file = None
|
||||||
try:
|
try:
|
||||||
file = open(filename, "rb")
|
file = open(filename, "rb")
|
||||||
self.lock_file(file, LOCK_SH)
|
portalocker.lock(file, portalocker.LOCK_SH)
|
||||||
precompiled = cPickle.load(file)
|
precompiled = cPickle.load(file)
|
||||||
except IOError, (errno, errstr):
|
except IOError, (errno, errstr):
|
||||||
raise TemplateError, "IO error in load precompiled "\
|
raise TemplateError, "IO error in load precompiled "\
|
||||||
@ -338,7 +279,7 @@ class TemplateManager:
|
|||||||
return precompiled
|
return precompiled
|
||||||
finally:
|
finally:
|
||||||
if file:
|
if file:
|
||||||
self.lock_file(file, LOCK_UN)
|
portalocker.unlock(file)
|
||||||
file.close()
|
file.close()
|
||||||
if remove_bad and os.path.isfile(filename):
|
if remove_bad and os.path.isfile(filename):
|
||||||
# X: We may lose the original exception here, raising OSError.
|
# X: We may lose the original exception here, raising OSError.
|
||||||
@ -369,7 +310,7 @@ class TemplateManager:
|
|||||||
file = None
|
file = None
|
||||||
try:
|
try:
|
||||||
file = open(filename, "wb") # may truncate existing file
|
file = open(filename, "wb") # may truncate existing file
|
||||||
self.lock_file(file, LOCK_EX)
|
portalocker.lock(file, portalocker.LOCK_EX)
|
||||||
BINARY = 1
|
BINARY = 1
|
||||||
READABLE = 0
|
READABLE = 0
|
||||||
if self._debug:
|
if self._debug:
|
||||||
@ -393,7 +334,7 @@ class TemplateManager:
|
|||||||
self.DEB("SAVING PRECOMPILED")
|
self.DEB("SAVING PRECOMPILED")
|
||||||
finally:
|
finally:
|
||||||
if file:
|
if file:
|
||||||
self.lock_file(file, LOCK_UN)
|
portalocker.unlock(file)
|
||||||
file.close()
|
file.close()
|
||||||
if remove_bad and os.path.isfile(filename):
|
if remove_bad and os.path.isfile(filename):
|
||||||
# X: We may lose the original exception here, raising OSError.
|
# 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={}):
|
def run(script, doc, output_file=None, options={}):
|
||||||
""" process an HTMLTMPL file """
|
""" process an HTMLTMPL file """
|
||||||
manager = htmltmpl.TemplateManager(precompile=(sys.platform.find('win')<0))
|
manager = htmltmpl.TemplateManager()
|
||||||
template = manager.prepare(script)
|
template = manager.prepare(script)
|
||||||
tp = htmltmpl.TemplateProcessor(html_escape=0)
|
tp = htmltmpl.TemplateProcessor(html_escape=0)
|
||||||
for key,value in template_info(doc).items():
|
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']:
|
for file in ['index.html', 'default.css', 'images/foaf.png']:
|
||||||
path = os.path.join(workdir, file)
|
path = os.path.join(workdir, file)
|
||||||
self.assertTrue(os.path.exists(path))
|
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
|
# verify that index.html is well formed, has content, and xml:lang
|
||||||
html = open(os.path.join(workdir, 'index.html'))
|
html = open(os.path.join(workdir, 'index.html'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user