[Checkins] SVN: z3c.recipe.usercrontab/trunk/ import initial revision
Jasper Spaans
jspaans at thehealthagency.com
Mon Feb 23 08:28:12 EST 2009
Log message for revision 97160:
import initial revision
Changed:
A z3c.recipe.usercrontab/trunk/CHANGES.txt
A z3c.recipe.usercrontab/trunk/README.txt
A z3c.recipe.usercrontab/trunk/buildout.cfg
A z3c.recipe.usercrontab/trunk/setup.py
A z3c.recipe.usercrontab/trunk/src/
A z3c.recipe.usercrontab/trunk/src/z3c/
A z3c.recipe.usercrontab/trunk/src/z3c/__init__.py
A z3c.recipe.usercrontab/trunk/src/z3c/recipe/
A z3c.recipe.usercrontab/trunk/src/z3c/recipe/__init__.py
A z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/
A z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt
A z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py
A z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/rtests.py
A z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py
-=-
Added: z3c.recipe.usercrontab/trunk/CHANGES.txt
===================================================================
--- z3c.recipe.usercrontab/trunk/CHANGES.txt (rev 0)
+++ z3c.recipe.usercrontab/trunk/CHANGES.txt 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1,21 @@
+z3c.recipe.usercrontab changes
+******************************
+
+0.3 (unreleased)
+================
+
+* Renamed to z3c.recipe.usercrontab
+* Add an option to change the command used to read and write crontabs
+* Improved tests to not modify the real crontab
+
+0.2 (2008-01-12)
+================
+
+* Warn if an entry cannot be removed in buildout uninstall
+* Break if multiple entries would be removed in buildout uninstall
+* Have del_entry return the number of removed
+
+0.1 (2008-01-12)
+================
+
+* Initial release.
Property changes on: z3c.recipe.usercrontab/trunk/CHANGES.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.recipe.usercrontab/trunk/README.txt
===================================================================
--- z3c.recipe.usercrontab/trunk/README.txt (rev 0)
+++ z3c.recipe.usercrontab/trunk/README.txt 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1,35 @@
+======================
+z3c.recipe.usercrontab
+======================
+
+The problem
+===========
+
+When deploying applications, it can be useful to have maintenance
+tasks be started periodically. On Unix platforms this is usually done
+using ``cron`` which starts `cronjobs`. Adding cronjobs to the
+system-wide cron directory (for example by placing a file in
+``/etc/cron.d``) can be handled using the ``zc.recipe.deployment``
+package, but it does not support adding cronjobs by normal
+users. (as ``/etc/cron.d`` usually is world-writable).
+
+The solution
+============
+``z3c.recipe.usercrontab`` interfaces with cron using ``crontab(1)``,
+and allows normal users to install their own cronjobs. This is done by
+having buildout add and remove cronjobs when installing and
+uninstalling packages.
+
+How to use it
+=============
+
+To use ``z3c.recipe.usercrontab`` you need to add the following to
+your buildout.cfg::
+
+ [mycronjob]
+ recipe = z3c.recipe.usercrontab
+ times = 0 12 * * *
+ command = echo nothing happens at noon
+
+and finally add ``mycronjob`` to the ``parts`` line(s) of your
+buildout.cfg
Property changes on: z3c.recipe.usercrontab/trunk/README.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.recipe.usercrontab/trunk/buildout.cfg
===================================================================
--- z3c.recipe.usercrontab/trunk/buildout.cfg (rev 0)
+++ z3c.recipe.usercrontab/trunk/buildout.cfg 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1,15 @@
+[buildout]
+develop = .
+parts = test
+prefer-final = true
+unzip = true
+versions = versions
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.recipe.usercrontab
+defaults = '--tests-pattern rtests'.split()
+
+[versions]
+zc.recipe.egg >= 1.1.0
+zope.testing = 3.6.0
Added: z3c.recipe.usercrontab/trunk/setup.py
===================================================================
--- z3c.recipe.usercrontab/trunk/setup.py (rev 0)
+++ z3c.recipe.usercrontab/trunk/setup.py 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1,47 @@
+# Copyright (c) 2009 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
+from setuptools import setup, find_packages
+
+version = '0.3dev'
+name = 'z3c.recipe.usercrontab'
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(name=name,
+ version=version,
+ author='Jasper Spaans, Jan-Jaap Driessen',
+ author_email='jspaans at thehealthagency.com',
+ license='ZPL',
+ classifiers=[
+ "Development Status :: 4 - Beta",
+ "Framework :: Buildout",
+ "Intended Audience :: Developers",
+ "Topic :: Software Development :: Build Tools",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "License :: OSI Approved :: Zope Public License"
+ ],
+ description="User Crontab install buildout recipe",
+ long_description=(read('README.txt') + '\n' +
+ 'Detailed documentation\n' +
+ '======================\n' +
+ read('src/z3c/recipe/usercrontab/README.txt')),
+ package_dir={'': 'src'},
+ packages=find_packages('src'),
+ namespace_packages=['z3c', 'z3c.recipe'],
+ include_package_data=True,
+ install_requires=['setuptools', 'zc.buildout'],
+ entry_points={
+ 'zc.buildout': ['default = %s:UserCrontab' % name],
+ 'zc.buildout.uninstall': ['default = %s:uninstall_usercrontab' % name]
+ }
+ )
Property changes on: z3c.recipe.usercrontab/trunk/setup.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.recipe.usercrontab/trunk/src/z3c/__init__.py
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/__init__.py (rev 0)
+++ z3c.recipe.usercrontab/trunk/src/z3c/__init__.py 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
Property changes on: z3c.recipe.usercrontab/trunk/src/z3c/__init__.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.recipe.usercrontab/trunk/src/z3c/recipe/__init__.py
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/__init__.py (rev 0)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/__init__.py 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
Property changes on: z3c.recipe.usercrontab/trunk/src/z3c/recipe/__init__.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt (rev 0)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1,242 @@
+# Copyright (c) 2009 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.
+
+The recipe z3c.recipe.usercrontab is a small recipe to facilitate the
+installing of cronjobs into user crontabs.
+
+ >>> from z3c.recipe.usercrontab.usercrontab import UserCrontabManager
+ >>> c = UserCrontabManager()
+
+For these tests, we fake a crontab by filling the list of cron entries
+for this object::
+
+ >>> c.crontab = [ 'MAILTO=""', '@reboot echo "No-one will see this"']
+ >>> print c
+ MAILTO=""
+ @reboot echo "No-one will see this"
+
+Now, we're adding a method to it using the official way::
+
+ >>> c.add_entry('@reboot echo "example.com gets spammed!"',
+ ... MAILTO="example at example.com")
+
+The object also has a convenient __repr__, so we can test its output::
+
+ >>> print c
+ MAILTO=""
+ @reboot echo "No-one will see this"
+ MAILTO=example at example.com
+ @reboot echo "example.com gets spammed!"
+
+Adding another entry with yet another MAILTO line is placed at the end::
+
+ >>> c.add_entry('@reboot echo "example.com gets spammed twice!"',
+ ... MAILTO="twice at example.com")
+ >>> print c
+ MAILTO=""
+ @reboot echo "No-one will see this"
+ MAILTO=example at example.com
+ @reboot echo "example.com gets spammed!"
+ MAILTO=twice at example.com
+ @reboot echo "example.com gets spammed twice!"
+
+When another entry is made with the same MAILTO, the MAILTO clause is
+not repeated again::
+
+ >>> c.add_entry('@reboot echo "twice at example.com gets spammed twice!"',
+ ... MAILTO="twice at example.com")
+ >>> print c
+ MAILTO=""
+ @reboot echo "No-one will see this"
+ MAILTO=example at example.com
+ @reboot echo "example.com gets spammed!"
+ MAILTO=twice at example.com
+ @reboot echo "twice at example.com gets spammed twice!"
+ @reboot echo "example.com gets spammed twice!"
+
+Removing entries also works, and removes superfluous environment variables::
+
+ >>> c.del_entry('@reboot echo "example.com gets spammed!"') == 1
+ True
+ >>> print c
+ MAILTO=""
+ @reboot echo "No-one will see this"
+ MAILTO=twice at example.com
+ @reboot echo "twice at example.com gets spammed twice!"
+ @reboot echo "example.com gets spammed twice!"
+
+Removing entries does not remove too much::
+
+ >>> c.del_entry('@reboot echo "twice at example.com gets spammed twice!"') == 1
+ True
+ >>> print c
+ MAILTO=""
+ @reboot echo "No-one will see this"
+ MAILTO=twice at example.com
+ @reboot echo "example.com gets spammed twice!"
+
+Removing the last entry also removes the dangling MAILTO line::
+
+ >>> c.del_entry('@reboot echo "example.com gets spammed twice!"') == 1
+ True
+ >>> print c
+ MAILTO=""
+ @reboot echo "No-one will see this"
+
+Removing the final entry removes the remaining MAILTO line, leaving us
+with an empty list::
+
+ >>> c.del_entry('@reboot echo "No-one will see this"') == 1
+ True
+ >>> len(c.crontab)
+ 0
+
+Adding an entry without a MAILTO environment line also doesn't put in
+an empty one::
+
+ >>> c.add_entry('@reboot echo "Someone will see this"')
+ >>> print c
+ @reboot echo "Someone will see this"
+
+Adding an entry with an empty MAILTO line adds it at the end, so the
+first entry is not disturbed::
+
+ >>> c.add_entry('@reboot echo "No-one will see this"', MAILTO="")
+ >>> print c
+ @reboot echo "Someone will see this"
+ MAILTO=""
+ @reboot echo "No-one will see this"
+
+Next, test the read_crontab and write_crontab methods; we'll use
+``cat`` and a temporary file to not modifiy the crontab of the user
+running these tests::
+
+ >>> import tempfile
+ >>> t = tempfile.NamedTemporaryFile('w')
+ >>> crontestfile = t.name
+ >>> t.write("#dummy\n")
+
+ >>> c = UserCrontabManager(readcrontab="cat %s" % crontestfile,
+ ... writecrontab="cat >%s" % crontestfile)
+ >>> c.read_crontab()
+ >>> a = repr(c)
+ >>> c.add_entry('# improbable entry')
+ >>> c.write_crontab()
+ >>> c.read_crontab()
+ >>> b =repr(c)
+ >>> a == b
+ False
+
+Now, delete this entry again and make sure the old crontab is restored::
+
+ >>> c.del_entry('# improbable entry') == 1
+ True
+ >>> c.write_crontab()
+ >>> c.read_crontab()
+ >>> b = repr(c)
+ >>> a == b
+ True
+
+Do the buildout shuffle::
+
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... parts = foo
+ ...
+ ... [foo]
+ ... recipe = z3c.recipe.usercrontab
+ ... times = # @reboot
+ ... command = echo nothing happens
+ ... readcrontab = cat %(crontest)s
+ ... writecrontab = cat >%(crontest)s
+ ...
+ ... [bar]
+ ... recipe = z3c.recipe.usercrontab
+ ... times = # @reboot
+ ... command = echo nothing happens
+ ... readcrontab = cat %(crontest)s
+ ... writecrontab = cat >%(crontest)s
+ ... ''' % ( { 'crontest': crontestfile } ))
+
+
+ >>> import os
+ >>> print system(os.path.join('bin', 'buildout'))
+ Installing foo.
+ <BLANKLINE>
+
+Check that it really was added to the crontab::
+
+ >>> c.read_crontab()
+ >>> b = repr(c)
+ >>> a == b
+ False
+
+ >>> '# @reboot\techo nothing happens' in c.crontab
+ True
+
+ >>> 'WARNING=The entries below were generated by buildout, do not modify' in c.crontab
+ True
+
+Uninstall the recipe::
+
+ >>> print system(os.path.join('bin', 'buildout')+' buildout:parts=')
+ Uninstalling foo.
+ Running uninstall recipe.
+ <BLANKLINE>
+
+And check that its entry was removed (i.e., the contents of the
+crontab are the same as when this test was started; in any case, the
+teardown from the testrunner makes sure the old situation is
+restored)::
+
+ >>> c.read_crontab()
+ >>> b = repr(c)
+ >>> a == b
+ True
+
+Now, break it by adding the same crontab entry twice::
+
+ >>> print system(os.path.join('bin', 'buildout')+' "buildout:parts=foo bar"')
+ Installing foo.
+ Installing bar.
+ <BLANKLINE>
+
+ >>> print system(os.path.join('bin', 'buildout')+' buildout:parts=') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ Uninstalling bar.
+ Running uninstall recipe.
+ bar: FATAL ERROR: Found more than one matching crontab-entry during uninstall; please resolve manually.
+ Matched lines: # @reboot echo nothing happens
+ While:
+ Installing.
+ Uninstalling bar.
+ <BLANKLINE>
+ An internal error occured due to a bug in either zc.buildout or in a
+ recipe being used:
+ Traceback (most recent call last):
+ ...
+ RuntimeError: Found more than one matching crontab-entry during uninstall
+ <BLANKLINE>
+
+Manually fix it by removing the offending lines::
+ >>> c.read_crontab()
+ >>> c.del_entry("# @reboot\techo nothing happens")
+ 2
+ >>> c.write_crontab()
+
+And now we can uninstall again (albeit with some warnings)::
+ >>> print system(os.path.join('bin', 'buildout')+' buildout:parts=') # doctest:
+ Uninstalling bar.
+ Running uninstall recipe.
+ bar: WARNING: Did not find a crontab-entry during uninstall; please check manually if everything was removed correctly
+ Uninstalling foo.
+ Running uninstall recipe.
+ foo: WARNING: Did not find a crontab-entry during uninstall; please check manually if everything was removed correctly
+ <BLANKLINE>
Property changes on: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py (rev 0)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1,52 @@
+# Copyright (c) 2009 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 logging
+from z3c.recipe.usercrontab.usercrontab import UserCrontabManager
+
+class UserCrontab:
+ def __init__(self, buildout, name, options):
+ self.options = options
+
+ options['entry'] = '%s\t%s' % (options['times'], options['command'])
+ readcrontab = self.options.get('readcrontab', None)
+ writecrontab = self.options.get('writecrontab', None)
+
+ self.crontab = UserCrontabManager(readcrontab, writecrontab)
+ self.env = { 'WARNING' :
+ 'The entries below were generated by buildout, do not modify' }
+
+ def install(self):
+ crontab = self.crontab
+
+ crontab.read_crontab()
+ crontab.add_entry(self.options['entry'], **self.env)
+ crontab.write_crontab()
+
+ return ()
+
+ def update(self):
+ pass
+
+def uninstall_usercrontab(name, options):
+ readcrontab = options.get('readcrontab', None)
+ writecrontab = options.get('writecrontab', None)
+
+ crontab = UserCrontabManager(readcrontab, writecrontab)
+ crontab.read_crontab()
+ nuked = crontab.del_entry(options['entry'])
+ if nuked==0:
+ logging.getLogger(name).warning("WARNING: Did not find a crontab-entry during uninstall; "
+ "please check manually if everything was removed correctly")
+ elif nuked > 1:
+ logging.getLogger(name).error("FATAL ERROR: Found more than one matching crontab-entry during uninstall; "
+ "please resolve manually.\nMatched lines: %s" % (options['entry']))
+ raise RuntimeError("Found more than one matching crontab-entry during uninstall")
+ crontab.write_crontab()
Property changes on: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/rtests.py
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/rtests.py (rev 0)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/rtests.py 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1,32 @@
+# Copyright (c) 2007-2009 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 zc.buildout.testing
+
+import unittest
+import zope.testing
+from zope.testing import doctest, renormalizing
+
+from z3c.recipe.usercrontab import UserCrontabManager
+
+usercrontab = UserCrontabManager()
+
+def setUp(test):
+ zc.buildout.testing.buildoutSetUp(test)
+ usercrontab.read_crontab()
+ zc.buildout.testing.install_develop('z3c.recipe.usercrontab', test)
+
+def tearDown(test):
+ zc.buildout.testing.buildoutTearDown(test)
+ usercrontab.write_crontab()
+
+def test_suite():
+ return unittest.TestSuite(doctest.DocFileSuite('README.txt', setUp=setUp,
+ tearDown=tearDown))
Property changes on: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/rtests.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py (rev 0)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py 2009-02-23 13:28:11 UTC (rev 97160)
@@ -0,0 +1,146 @@
+# Copyright (c) 2009 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 re
+
+def escape_string(s):
+ """
+ Do a smart escape of string s, wrapping it in quotes and escaping
+ those quotes if necessary. If the first or last byte is a space,
+ also quote the string.
+ """
+ for c,d in (('"', "'"), ("'", '"')):
+ if c in s:
+ return '%s%s%s' % (d, s.replace(d, '\\'+d), d)
+ if len(s)==0 or s[0].isspace() or s[-1].isspace():
+ return '"%s"' % s
+
+ return s
+
+def unescape_string(s):
+ """
+ Unescape any escaped quotes, and remove quotes around the string
+ """
+ if len(s)==0:
+ return s
+ for c in ('"', "'"):
+ if(s[0]==c and s[-1]==c):
+ return s[1:-1].replace('\\'+c, c)
+ return s
+
+
+def dict_pmatch(d1, d2):
+ """
+ Returns true if all keys in d1 are in d2 and all values match
+ """
+ for k,v in d1.iteritems():
+ if not (k in d2 and d2[k]==v):
+ return False
+ return True
+
+
+env_re = re.compile(r'^("[^"]*"|\'[^\']*\'|[^\s]+)\s*='
+ '\s*("[^"]*"|\'[^\']*\'|[^"\']+)?[^\s]*$')
+
+defaultreadcrontab = "crontab -l"
+defaultwritecrontab = "crontab -"
+
+class UserCrontabManager(object):
+ """
+ Helper class to edit entries in user crontabs (see man 5 crontab)
+ """
+
+ username = None
+ crontab = []
+
+ def __init__(self, readcrontab=defaultreadcrontab,
+ writecrontab=defaultwritecrontab):
+ self.readcrontab = readcrontab
+ self.writecrontab = writecrontab
+
+ def read_crontab(self):
+ self.crontab = [ l.strip("\n") for l in
+ os.popen(self.readcrontab, "r") ]
+
+ def write_crontab(self):
+ fd = os.popen(self.writecrontab, "w")
+ for l in self.crontab:
+ fd.write("%s\n" % l)
+ fd.close()
+
+ def __repr__(self):
+ return "\n".join(self.crontab)
+
+ def add_entry(self, line, **env):
+ """
+ Add an entry to a crontab, if kw's are set, set environment args
+ to be like that.
+ """
+ cur_env = {}
+ new_crontab = []
+ done = False
+
+ for l in self.crontab:
+ m = env_re.match(l)
+ if m:
+ cur_env[unescape_string(m.group(1))] = unescape_string(m.group(2))
+ new_crontab.append(l)
+ if not done and dict_pmatch(env, cur_env):
+ new_crontab.append(line)
+ done = True
+
+ if (not done):
+ for (k,v) in env.iteritems():
+ if k not in cur_env or cur_env[k] != v:
+ new_crontab.append('%s=%s' % (escape_string(k),
+ escape_string(v)))
+ new_crontab.append(line)
+
+ self.crontab = new_crontab
+
+
+ def del_entry(self, line):
+ """
+ Remove an entry from a crontab, dropping useless environment
+ args at the end of the crontab, and which are replaced by
+ something else before an actual crontab entry is found.
+
+ (If the same entry occurs multiple times, it is removed several
+ times)
+ """
+ new_crontab = []
+ fresh_env = {}
+ nuked = True
+ dangling = True
+ num_nuked = 0
+ for l in reversed(self.crontab):
+ m = env_re.match(l)
+ if m:
+ k,v = unescape_string(m.group(1)), unescape_string(m.group(2))
+ if dangling:
+ continue
+ if nuked is True:
+ if k in fresh_env:
+ continue
+ fresh_env[k] = v
+ else:
+ if l==line:
+ nuked=True
+ num_nuked = num_nuked + 1
+ continue
+ else:
+ if len(l.strip()):
+ dangling = False
+ nuked=False
+ fresh_env = {}
+ new_crontab.append(l)
+ self.crontab = [l for l in reversed(new_crontab) ]
+ return num_nuked
Property changes on: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py
___________________________________________________________________
Added: svn:eol-style
+ native
More information about the Checkins
mailing list