zc.lockfile-1.0.2/000755 000765 000765 00000000000 12056712724 013335 5ustar00jimjim000000 000000 zc.lockfile-1.0.2/bootstrap.py000644 000765 000765 00000023522 12052771720 015725 0ustar00jimjim000000 000000 ############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. """ import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess from optparse import OptionParser if sys.platform == 'win32': def quote(c): if ' ' in c: return '"%s"' % c # work around spawn lamosity on windows else: return c else: quote = str # See zc.buildout.easy_install._has_broken_dash_S for motivation and comments. stdout, stderr = subprocess.Popen( [sys.executable, '-Sc', 'try:\n' ' import ConfigParser\n' 'except ImportError:\n' ' print 1\n' 'else:\n' ' print 0\n'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() has_broken_dash_S = bool(int(stdout.strip())) # In order to be more robust in the face of system Pythons, we want to # run without site-packages loaded. This is somewhat tricky, in # particular because Python 2.6's distutils imports site, so starting # with the -S flag is not sufficient. However, we'll start with that: if not has_broken_dash_S and 'site' in sys.modules: # We will restart with python -S. args = sys.argv[:] args[0:0] = [sys.executable, '-S'] args = map(quote, args) os.execv(sys.executable, args) # Now we are running with -S. We'll get the clean sys.path, import site # because distutils will do it later, and then reset the path and clean # out any namespace packages from site-packages that might have been # loaded by .pth files. clean_path = sys.path[:] import site sys.path[:] = clean_path for k, v in sys.modules.items(): if k in ('setuptools', 'pkg_resources') or ( hasattr(v, '__path__') and len(v.__path__)==1 and not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))): # This is a namespace package. Remove it. sys.modules.pop(k) is_jython = sys.platform.startswith('java') setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py' distribute_source = 'http://python-distribute.org/distribute_setup.py' # parsing arguments def normalize_to_url(option, opt_str, value, parser): if value: if '://' not in value: # It doesn't smell like a URL. value = 'file://%s' % ( urllib.pathname2url( os.path.abspath(os.path.expanduser(value))),) if opt_str == '--download-base' and not value.endswith('/'): # Download base needs a trailing slash to make the world happy. value += '/' else: value = None name = opt_str[2:].replace('-', '_') setattr(parser.values, name, value) usage = '''\ [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] Bootstraps a buildout-based project. Simply run this script in a directory containing a buildout.cfg, using the Python that you want bin/buildout to use. Note that by using --setup-source and --download-base to point to local resources, you can keep this script from going over the network. ''' parser = OptionParser(usage=usage) parser.add_option("-v", "--version", dest="version", help="use a specific zc.buildout version") parser.add_option("-d", "--distribute", action="store_true", dest="use_distribute", default=False, help="Use Distribute rather than Setuptools.") parser.add_option("--setup-source", action="callback", dest="setup_source", callback=normalize_to_url, nargs=1, type="string", help=("Specify a URL or file location for the setup file. " "If you use Setuptools, this will default to " + setuptools_source + "; if you use Distribute, this " "will default to " + distribute_source +".")) parser.add_option("--download-base", action="callback", dest="download_base", callback=normalize_to_url, nargs=1, type="string", help=("Specify a URL or directory for downloading " "zc.buildout and either Setuptools or Distribute. " "Defaults to PyPI.")) parser.add_option("--eggs", help=("Specify a directory for storing eggs. Defaults to " "a temporary directory that is deleted when the " "bootstrap script completes.")) parser.add_option("-t", "--accept-buildout-test-releases", dest='accept_buildout_test_releases', action="store_true", default=False, help=("Normally, if you do not specify a --version, the " "bootstrap script and buildout gets the newest " "*final* versions of zc.buildout and its recipes and " "extensions for you. If you use this flag, " "bootstrap and buildout will get the newest releases " "even if they are alphas or betas.")) parser.add_option("-c", None, action="store", dest="config_file", help=("Specify the path to the buildout configuration " "file to be used.")) options, args = parser.parse_args() # if -c was provided, we push it back into args for buildout's main function if options.config_file is not None: args += ['-c', options.config_file] if options.eggs: eggs_dir = os.path.abspath(os.path.expanduser(options.eggs)) else: eggs_dir = tempfile.mkdtemp() if options.setup_source is None: if options.use_distribute: options.setup_source = distribute_source else: options.setup_source = setuptools_source if options.accept_buildout_test_releases: args.append('buildout:accept-buildout-test-releases=true') args.append('bootstrap') try: import pkg_resources import setuptools # A flag. Sometimes pkg_resources is installed alone. if not hasattr(pkg_resources, '_distribute'): raise ImportError except ImportError: ez_code = urllib2.urlopen( options.setup_source).read().replace('\r\n', '\n') ez = {} exec ez_code in ez setup_args = dict(to_dir=eggs_dir, download_delay=0) if options.download_base: setup_args['download_base'] = options.download_base if options.use_distribute: setup_args['no_fake'] = True ez['use_setuptools'](**setup_args) if 'pkg_resources' in sys.modules: reload(sys.modules['pkg_resources']) import pkg_resources # This does not (always?) update the default working set. We will # do it. for path in sys.path: if path not in pkg_resources.working_set.entries: pkg_resources.working_set.add_entry(path) cmd = [quote(sys.executable), '-c', quote('from setuptools.command.easy_install import main; main()'), '-mqNxd', quote(eggs_dir)] if not has_broken_dash_S: cmd.insert(1, '-S') find_links = options.download_base if not find_links: find_links = os.environ.get('bootstrap-testing-find-links') if find_links: cmd.extend(['-f', quote(find_links)]) if options.use_distribute: setup_requirement = 'distribute' else: setup_requirement = 'setuptools' ws = pkg_resources.working_set setup_requirement_path = ws.find( pkg_resources.Requirement.parse(setup_requirement)).location env = dict( os.environ, PYTHONPATH=setup_requirement_path) requirement = 'zc.buildout' version = options.version if version is None and not options.accept_buildout_test_releases: # Figure out the most recent final version of zc.buildout. import setuptools.package_index _final_parts = '*final-', '*final' def _final_version(parsed_version): for part in parsed_version: if (part[:1] == '*') and (part not in _final_parts): return False return True index = setuptools.package_index.PackageIndex( search_path=[setup_requirement_path]) if find_links: index.add_find_links((find_links,)) req = pkg_resources.Requirement.parse(requirement) if index.obtain(req) is not None: best = [] bestv = None for dist in index[req.project_name]: distv = dist.parsed_version if _final_version(distv): if bestv is None or distv > bestv: best = [dist] bestv = distv elif distv == bestv: best.append(dist) if best: best.sort() version = best[-1].version if version: requirement = '=='.join((requirement, version)) cmd.append(requirement) if is_jython: import subprocess exitcode = subprocess.Popen(cmd, env=env).wait() else: # Windows prefers this, apparently; otherwise we would prefer subprocess exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) if exitcode != 0: sys.stdout.flush() sys.stderr.flush() print ("An error occurred when trying to install zc.buildout. " "Look above this message for any errors that " "were output by easy_install.") sys.exit(exitcode) ws.add_entry(eggs_dir) ws.require(requirement) import zc.buildout.buildout zc.buildout.buildout.main(args) if not options.eggs: # clean up temporary egg directory shutil.rmtree(eggs_dir) zc.lockfile-1.0.2/buildout.cfg000644 000765 000765 00000000254 12056710135 015640 0ustar00jimjim000000 000000 [buildout] develop = . parts = py [test] recipe = zc.recipe.testrunner ==1.3.0 eggs = zc.lockfile [test] [py] recipe = zc.recipe.egg eggs = ${test:eggs} interpreter = py zc.lockfile-1.0.2/CHANGES.txt000644 000765 000765 00000001220 12056712235 015136 0ustar00jimjim000000 000000 Change History *************** 1.0.2 (2012-12-02) ================== - Fixed: the fix included in 1.0.1 caused multiple pids to be written to the lock file 1.0.1 (2012-11-30) ================== - Fixed: when there was lock contention, the pid in the lock file was lost. Thanks to Daniel Moisset reporting the problem and providing a fix with tests. - Added test extra to declare test dependency on ``zope.testing``. - Using Python's ``doctest`` module instead of depreacted ``zope.testing.doctest``. 1.0.0 (2008-10-18) ================== - Fixed a small bug in error logging. 1.0.0b1 (2007-07-18) ==================== Initial release zc.lockfile-1.0.2/COPYRIGHT.txt000644 000765 000765 00000000040 12052771720 015435 0ustar00jimjim000000 000000 Zope Foundation and Contributorszc.lockfile-1.0.2/LICENSE.txt000644 000765 000765 00000004026 12052771720 015157 0ustar00jimjim000000 000000 Zope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. zc.lockfile-1.0.2/PKG-INFO000644 000765 000765 00000007340 12056712724 014436 0ustar00jimjim000000 000000 Metadata-Version: 1.0 Name: zc.lockfile Version: 1.0.2 Summary: Basic inter-process locks Home-page: http://www.python.org/pypi/zc.lockfile Author: Jim Fulton Author-email: jim@zope.com License: ZPL 2.1 Description: ************************* Basic inter-process locks ************************* The zc.lockfile package provides a basic portable implementation of interprocess locks using lock files. The purpose if not specifically to lock files, but to simply provide locks with an implementation based on file-locking primitives. Of course, these locks could be used to mediate access to *other* files. For example, the ZODB file storage implementation uses file locks to mediate access to file-storage database files. The database files and lock file files are separate files. .. contents:: Detailed Documentation ********************** Lock file support ================= The ZODB lock_file module provides support for creating file system locks. These are locks that are implemented with lock files and OS-provided locking facilities. To create a lock, instantiate a LockFile object with a file name: >>> import zc.lockfile >>> lock = zc.lockfile.LockFile('lock') If we try to lock the same name, we'll get a lock error: >>> import zope.testing.loggingsupport >>> handler = zope.testing.loggingsupport.InstalledHandler('zc.lockfile') >>> try: ... zc.lockfile.LockFile('lock') ... except zc.lockfile.LockError: ... print "Can't lock file" Can't lock file >>> for record in handler.records: # doctest: +ELLIPSIS ... print record.levelname, record.getMessage() ERROR Error locking file lock; pid=... To release the lock, use it's close method: >>> lock.close() The lock file is not removed. It is left behind: >>> import os >>> os.path.exists('lock') True Of course, now that we've released the lock, we can create it again: >>> lock = zc.lockfile.LockFile('lock') >>> lock.close() .. Cleanup >>> import os >>> os.remove('lock') Change History *************** 1.0.2 (2012-12-02) ================== - Fixed: the fix included in 1.0.1 caused multiple pids to be written to the lock file 1.0.1 (2012-11-30) ================== - Fixed: when there was lock contention, the pid in the lock file was lost. Thanks to Daniel Moisset reporting the problem and providing a fix with tests. - Added test extra to declare test dependency on ``zope.testing``. - Using Python's ``doctest`` module instead of depreacted ``zope.testing.doctest``. 1.0.0 (2008-10-18) ================== - Fixed a small bug in error logging. 1.0.0b1 (2007-07-18) ==================== Initial release Download ********************** Keywords: lock Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows zc.lockfile-1.0.2/README.txt000644 000765 000765 00000001107 12052771720 015027 0ustar00jimjim000000 000000 ************************* Basic inter-process locks ************************* The zc.lockfile package provides a basic portable implementation of interprocess locks using lock files. The purpose if not specifically to lock files, but to simply provide locks with an implementation based on file-locking primitives. Of course, these locks could be used to mediate access to *other* files. For example, the ZODB file storage implementation uses file locks to mediate access to file-storage database files. The database files and lock file files are separate files. .. contents:: zc.lockfile-1.0.2/setup.cfg000644 000765 000765 00000000073 12056712724 015156 0ustar00jimjim000000 000000 [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zc.lockfile-1.0.2/setup.py000644 000765 000765 00000003746 12056712654 015063 0ustar00jimjim000000 000000 ############################################################################## # # Copyright (c) Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## name, version = "zc.lockfile", '1.0.2' import os from setuptools import setup, find_packages def read(*rnames): return open(os.path.join(os.path.dirname(__file__), *rnames)).read() long_description=( read('README.txt') + '\n' + 'Detailed Documentation\n' '**********************\n' + '\n' + read('src', 'zc', 'lockfile', 'README.txt') + '\n' + read('CHANGES.txt') + '\n' + 'Download\n' '**********************\n' ) open('doc.txt', 'w').write(long_description) setup( name = name, version=version, author = "Jim Fulton", author_email = "jim@zope.com", description = "Basic inter-process locks", long_description=long_description, license = "ZPL 2.1", keywords = "lock", url='http://www.python.org/pypi/'+name, packages = find_packages('src'), package_dir = {'': 'src'}, namespace_packages = ['zc'], install_requires = 'setuptools', extras_require=dict( test=[ 'zope.testing', ]), include_package_data = True, zip_safe=False, classifiers = [ 'Programming Language :: Python', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', ], ) zc.lockfile-1.0.2/src/000755 000765 000765 00000000000 12056712724 014124 5ustar00jimjim000000 000000 zc.lockfile-1.0.2/src/zc/000755 000765 000765 00000000000 12056712724 014540 5ustar00jimjim000000 000000 zc.lockfile-1.0.2/src/zc.lockfile.egg-info/000755 000765 000765 00000000000 12056712724 020021 5ustar00jimjim000000 000000 zc.lockfile-1.0.2/src/zc.lockfile.egg-info/dependency_links.txt000644 000765 000765 00000000001 12056712724 024067 0ustar00jimjim000000 000000 zc.lockfile-1.0.2/src/zc.lockfile.egg-info/namespace_packages.txt000644 000765 000765 00000000003 12056712724 024345 0ustar00jimjim000000 000000 zc zc.lockfile-1.0.2/src/zc.lockfile.egg-info/not-zip-safe000644 000765 000765 00000000001 12052774225 022247 0ustar00jimjim000000 000000 zc.lockfile-1.0.2/src/zc.lockfile.egg-info/PKG-INFO000644 000765 000765 00000007340 12056712724 021122 0ustar00jimjim000000 000000 Metadata-Version: 1.0 Name: zc.lockfile Version: 1.0.2 Summary: Basic inter-process locks Home-page: http://www.python.org/pypi/zc.lockfile Author: Jim Fulton Author-email: jim@zope.com License: ZPL 2.1 Description: ************************* Basic inter-process locks ************************* The zc.lockfile package provides a basic portable implementation of interprocess locks using lock files. The purpose if not specifically to lock files, but to simply provide locks with an implementation based on file-locking primitives. Of course, these locks could be used to mediate access to *other* files. For example, the ZODB file storage implementation uses file locks to mediate access to file-storage database files. The database files and lock file files are separate files. .. contents:: Detailed Documentation ********************** Lock file support ================= The ZODB lock_file module provides support for creating file system locks. These are locks that are implemented with lock files and OS-provided locking facilities. To create a lock, instantiate a LockFile object with a file name: >>> import zc.lockfile >>> lock = zc.lockfile.LockFile('lock') If we try to lock the same name, we'll get a lock error: >>> import zope.testing.loggingsupport >>> handler = zope.testing.loggingsupport.InstalledHandler('zc.lockfile') >>> try: ... zc.lockfile.LockFile('lock') ... except zc.lockfile.LockError: ... print "Can't lock file" Can't lock file >>> for record in handler.records: # doctest: +ELLIPSIS ... print record.levelname, record.getMessage() ERROR Error locking file lock; pid=... To release the lock, use it's close method: >>> lock.close() The lock file is not removed. It is left behind: >>> import os >>> os.path.exists('lock') True Of course, now that we've released the lock, we can create it again: >>> lock = zc.lockfile.LockFile('lock') >>> lock.close() .. Cleanup >>> import os >>> os.remove('lock') Change History *************** 1.0.2 (2012-12-02) ================== - Fixed: the fix included in 1.0.1 caused multiple pids to be written to the lock file 1.0.1 (2012-11-30) ================== - Fixed: when there was lock contention, the pid in the lock file was lost. Thanks to Daniel Moisset reporting the problem and providing a fix with tests. - Added test extra to declare test dependency on ``zope.testing``. - Using Python's ``doctest`` module instead of depreacted ``zope.testing.doctest``. 1.0.0 (2008-10-18) ================== - Fixed a small bug in error logging. 1.0.0b1 (2007-07-18) ==================== Initial release Download ********************** Keywords: lock Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows zc.lockfile-1.0.2/src/zc.lockfile.egg-info/requires.txt000644 000765 000765 00000000037 12056712724 022421 0ustar00jimjim000000 000000 setuptools [test] zope.testingzc.lockfile-1.0.2/src/zc.lockfile.egg-info/SOURCES.txt000644 000765 000765 00000000716 12056712724 021711 0ustar00jimjim000000 000000 CHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt bootstrap.py buildout.cfg setup.py src/zc/__init__.py src/zc.lockfile.egg-info/PKG-INFO src/zc.lockfile.egg-info/SOURCES.txt src/zc.lockfile.egg-info/dependency_links.txt src/zc.lockfile.egg-info/namespace_packages.txt src/zc.lockfile.egg-info/not-zip-safe src/zc.lockfile.egg-info/requires.txt src/zc.lockfile.egg-info/top_level.txt src/zc/lockfile/README.txt src/zc/lockfile/__init__.py src/zc/lockfile/tests.pyzc.lockfile-1.0.2/src/zc.lockfile.egg-info/top_level.txt000644 000765 000765 00000000003 12056712724 022544 0ustar00jimjim000000 000000 zc zc.lockfile-1.0.2/src/zc/__init__.py000644 000765 000765 00000000070 12052771720 016643 0ustar00jimjim000000 000000 __import__('pkg_resources').declare_namespace(__name__) zc.lockfile-1.0.2/src/zc/lockfile/000755 000765 000765 00000000000 12056712724 016330 5ustar00jimjim000000 000000 zc.lockfile-1.0.2/src/zc/lockfile/__init__.py000644 000765 000765 00000005657 12056711252 020451 0ustar00jimjim000000 000000 ############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## import os import errno import logging logger = logging.getLogger("zc.lockfile") class LockError(Exception): """Couldn't get a lock """ try: import fcntl except ImportError: try: import msvcrt except ImportError: def _lock_file(file): raise TypeError('No file-locking support on this platform') def _unlock_file(file): raise TypeError('No file-locking support on this platform') else: # Windows def _lock_file(file): # Lock just the first byte try: msvcrt.locking(file.fileno(), msvcrt.LK_NBLCK, 1) except IOError: raise LockError("Couldn't lock %r" % file.name) def _unlock_file(file): try: file.seek(0) msvcrt.locking(file.fileno(), msvcrt.LK_UNLCK, 1) except IOError: raise LockError("Couldn't unlock %r" % file.name) else: # Unix _flags = fcntl.LOCK_EX | fcntl.LOCK_NB def _lock_file(file): try: fcntl.flock(file.fileno(), _flags) except IOError: raise LockError("Couldn't lock %r" % file.name) def _unlock_file(file): # File is automatically unlocked on close pass class LockFile: _fp = None def __init__(self, path): self._path = path try: # Try to open for writing without truncation: fp = open(path, 'r+') except IOError: # If the file doesn't exist, we'll get an IO error, try a+ # Note that there may be a race here. Multiple processes # could fail on the r+ open and open the file a+, but only # one will get the the lock and write a pid. fp = open(path, 'a+') try: _lock_file(fp) except: fp.seek(1) pid = fp.read().strip()[:20] fp.close() if not pid: pid = 'UNKNOWN' logger.exception("Error locking file %s; pid=%s", path, pid) raise self._fp = fp fp.write(" %s\n" % os.getpid()) fp.truncate() fp.flush() def close(self): if self._fp is not None: _unlock_file(self._fp) self._fp.close() self._fp = None zc.lockfile-1.0.2/src/zc/lockfile/README.txt000644 000765 000765 00000002260 12052774132 020023 0ustar00jimjim000000 000000 Lock file support ================= The ZODB lock_file module provides support for creating file system locks. These are locks that are implemented with lock files and OS-provided locking facilities. To create a lock, instantiate a LockFile object with a file name: >>> import zc.lockfile >>> lock = zc.lockfile.LockFile('lock') If we try to lock the same name, we'll get a lock error: >>> import zope.testing.loggingsupport >>> handler = zope.testing.loggingsupport.InstalledHandler('zc.lockfile') >>> try: ... zc.lockfile.LockFile('lock') ... except zc.lockfile.LockError: ... print "Can't lock file" Can't lock file >>> for record in handler.records: # doctest: +ELLIPSIS ... print record.levelname, record.getMessage() ERROR Error locking file lock; pid=... To release the lock, use it's close method: >>> lock.close() The lock file is not removed. It is left behind: >>> import os >>> os.path.exists('lock') True Of course, now that we've released the lock, we can create it again: >>> lock = zc.lockfile.LockFile('lock') >>> lock.close() .. Cleanup >>> import os >>> os.remove('lock') zc.lockfile-1.0.2/src/zc/lockfile/tests.py000644 000765 000765 00000005023 12056712540 020040 0ustar00jimjim000000 000000 ############################################################################## # # Copyright (c) 2004 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## from zope.testing import setupstack import os, sys, unittest, doctest import zc.lockfile, time, threading def inc(): while 1: try: lock = zc.lockfile.LockFile('f.lock') except zc.lockfile.LockError: continue else: break f = open('f', 'r+b') v = int(f.readline().strip()) time.sleep(0.01) v += 1 f.seek(0) f.write('%d\n' % v) f.close() lock.close() def many_threads_read_and_write(): r""" >>> open('f', 'w+b').write('0\n') >>> open('f.lock', 'w+b').write('0\n') >>> n = 50 >>> threads = [threading.Thread(target=inc) for i in range(n)] >>> _ = [thread.start() for thread in threads] >>> _ = [thread.join() for thread in threads] >>> saved = int(open('f', 'rb').readline().strip()) >>> saved == n True >>> os.remove('f') We should only have one pid in the lock file: >>> f = open('f.lock') >>> len(f.read().strip().split()) 1 >>> f.close() >>> os.remove('f.lock') """ def pid_in_lockfile(): r""" >>> import os, zc.lockfile >>> pid = os.getpid() >>> lock = zc.lockfile.LockFile("f.lock") >>> f = open("f.lock") >>> f.seek(1) >>> f.read().strip() == str(pid) True >>> f.close() Make sure that locking twice does not overwrite the old pid: >>> lock = zc.lockfile.LockFile("f.lock") Traceback (most recent call last): ... LockError: Couldn't lock 'f.lock' >>> f = open("f.lock") >>> f.seek(1) >>> f.read().strip() == str(pid) True >>> f.close() >>> lock.close() """ def test_suite(): suite = unittest.TestSuite() suite.addTest(doctest.DocFileSuite( 'README.txt', setUp=setupstack.setUpDirectory, tearDown=setupstack.tearDown)) suite.addTest(doctest.DocTestSuite( setUp=setupstack.setUpDirectory, tearDown=setupstack.tearDown)) return suite