[Checkins] SVN: z3c.recipe.usercrontab/trunk/ - Removed essentially-unused complete environment variable handling.
Reinout van Rees
reinout at vanrees.org
Tue Jun 16 08:57:40 EDT 2009
Log message for revision 101076:
- Removed essentially-unused complete environment variable handling.
- Adding our entries with descriptive comments now: it includes the buildout
file and the part name.
Changed:
U z3c.recipe.usercrontab/trunk/CHANGES.txt
U z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt
U z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py
U z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/tests.py
U z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py
-=-
Modified: z3c.recipe.usercrontab/trunk/CHANGES.txt
===================================================================
--- z3c.recipe.usercrontab/trunk/CHANGES.txt 2009-06-16 12:27:38 UTC (rev 101075)
+++ z3c.recipe.usercrontab/trunk/CHANGES.txt 2009-06-16 12:57:40 UTC (rev 101076)
@@ -4,9 +4,13 @@
0.6 (unreleased)
----------------
-- Nothing changed yet.
+- Removed essentially-unused complete environment variable handling.
+ [reinout]
+- Adding our entries with descriptive comments now: it includes the buildout
+ file and the part name. [reinout]
+
0.5.1 (2009-06-16)
------------------
Modified: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt 2009-06-16 12:27:38 UTC (rev 101075)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/README.txt 2009-06-16 12:57:40 UTC (rev 101076)
@@ -14,131 +14,100 @@
installing of cronjobs into user crontabs.
>>> from z3c.recipe.usercrontab.usercrontab import UserCrontabManager
- >>> c = UserCrontabManager()
-Entry and environment handling
-------------------------------
+Entry handling
+--------------
-For these tests, we fake a crontab by filling the list of cron entries
-for this object:
+A user crontab manager manages a user's crontab for one specific buildout
+part. The part ends up in the identifier. We'll use 'test' here.
- >>> c.crontab = [ 'MAILTO=""', '@reboot echo "No-one will see this"']
- >>> print c
- MAILTO=""
- @reboot echo "No-one will see this"
+ >>> c = UserCrontabManager(identifier='test')
-Now, we're adding a method to it using the official way:
+In these tests, we can fake a crontab by filling the list of cron entries
+manually:
- >>> c.add_entry('@reboot echo "example.com gets spammed!"',
- ... MAILTO="example at example.com")
+ >>> c.crontab = ['@reboot echo "hello world"']
+ >>> print c # Handy shortcut
+ @reboot echo "hello world"
-The object also has a convenient __repr__, so we can test its output:
+Now, we're adding an entry to it using the official way. The entry is
+surrounded by markers:
+ >>> c.add_entry('@reboot echo "I just got added"')
>>> print c
- MAILTO=""
- @reboot echo "No-one will see this"
- MAILTO=example at example.com
- @reboot echo "example.com gets spammed!"
+ @reboot echo "hello world"
+ <BLANKLINE>
+ # Generated by test
+ @reboot echo "I just got added"
+ # END test
+ <BLANKLINE>
-Adding another entry with yet another MAILTO line is placed at the end:
+Removing entries also works. As long as the "Generated by" markers are
+present, it doesn't matter which entry you remove: everything surrounded by
+the markers is zapped:
- >>> 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
+ >>> c.del_entry('bla bla') == 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!"
+ @reboot echo "hello world"
-Removing entries does not remove too much:
+Pre-0.6, a WARNING environment variable was used. An entry (which content
+matters now!) is found there:
- >>> c.del_entry('@reboot echo "twice at example.com gets spammed twice!"') == 1
- True
+ >>> c.crontab = ['@reboot echo "hello world"',
+ ... 'WARNING="Everything below is added by bla bla',
+ ... '@reboot echo "old entry 1"',
+ ... '@reboot echo "old entry 2"']
>>> 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
+ @reboot echo "hello world"
+ WARNING="Everything below is added by bla bla
+ @reboot echo "old entry 1"
+ @reboot echo "old entry 2"
+ >>> c.del_entry('@reboot echo "old entry 1"')
+ 1
>>> print c
- MAILTO=""
- @reboot echo "No-one will see this"
+ @reboot echo "hello world"
+ WARNING="Everything below is added by bla bla
+ @reboot echo "old entry 2"
-Removing the final entry removes the remaining MAILTO line, leaving us
-with an empty list:
+Removing the last remaining entry under WARNING also removes the WARNING:
- >>> 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"')
+ >>> c.del_entry('@reboot echo "old entry 2"')
+ 1
>>> print c
- @reboot echo "Someone will see this"
+ @reboot echo "hello world"
-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"
-
Briefly in the 0.5 version, a 'BUILDOUT' environment variable was used for
grouping items per buildout. Now for some up/downgrade testing. 0.5.1 removes
the environment variable again. We'll add an entry with such a (now
deprecated) "grouping environment variable". First the start situation:
>>> c.crontab=[
+ ... 'WARNING="Everything below is added by bla bla',
... 'BUILDOUT=my/buildout',
... '@reboot echo nothing happens']
>>> print c # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ WARNING="Everything below is added by bla bla
BUILDOUT=my/buildout
@reboot echo nothing happens
-Now we add a similar entry. The BUILDOUT statement is removed:
+Doing anything (adding/removing) zaps BUILDOUT statement:
- >>> c.add_entry('@reboot echo nothing happens')
- >>> print c # doctest: +REPORT_NDIFF
+ >>> c.del_entry('nonexisting')
+ 0
+ >>> print c
+ WARNING="Everything below is added by bla bla
@reboot echo nothing happens
+And just to make sure, deleting that entry empties out the whole file:
+ >>> c.del_entry('@reboot echo nothing happens')
+ 1
+ >>> print c
+ <BLANKLINE>
+
+
Read/write crontab methods
--------------------------
@@ -152,7 +121,8 @@
>>> t.write("#dummy\n")
>>> c = UserCrontabManager(readcrontab="cat %s" % crontestfile,
- ... writecrontab="cat >%s" % crontestfile)
+ ... writecrontab="cat >%s" % crontestfile,
+ ... identifier='test')
>>> c.read_crontab()
>>> a = repr(c)
>>> c.add_entry('# improbable entry')
@@ -189,16 +159,8 @@
... 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.
@@ -213,13 +175,21 @@
>>> '# @reboot\techo nothing happens' in c.crontab
True
-
- >>> 'WARNING=The entries below were generated by buildout, do not modify' in c.crontab
- True
-
+ >>> print c # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ <BLANKLINE>
+ # Generated by .../sample-buildout [foo]
+ # @reboot echo nothing happens
+ # END .../sample-buildout [foo]
+ <BLANKLINE>
+
Uninstall the recipe:
- >>> print system(os.path.join('bin', 'buildout')+' buildout:parts=')
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... parts =
+ ... ''' % ( { 'crontest': crontestfile } ))
+ >>> print system(os.path.join('bin', 'buildout'))
Uninstalling foo.
Running uninstall recipe.
<BLANKLINE>
@@ -234,44 +204,127 @@
>>> a == b
True
-Now, break it by adding the same crontab entry twice:
+A second part installs fine:
- >>> print system(os.path.join('bin', 'buildout')+' "buildout:parts=foo bar"')
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... parts = foo bar
+ ...
+ ... [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 something happens
+ ... readcrontab = cat %(crontest)s
+ ... writecrontab = cat >%(crontest)s
+ ... ''' % ( { 'crontest': crontestfile } ))
+ >>> print system(os.path.join('bin', 'buildout'))
Installing foo.
Installing bar.
<BLANKLINE>
+ >>> c.read_crontab()
+ >>> print c # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ <BLANKLINE>
+ # Generated by .../sample-buildout [foo]
+ # @reboot echo nothing happens
+ # END .../sample-buildout [foo]
+ <BLANKLINE>
+ <BLANKLINE>
+ # Generated by .../sample-buildout [bar]
+ # @reboot echo something happens
+ # END .../sample-buildout [bar]
+ <BLANKLINE>
- >>> print system(os.path.join('bin', 'buildout')+' buildout:parts=') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+Uninstalling also works fine
+
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... parts =
+ ... ''' % ( { 'crontest': crontestfile } ))
+ >>> print system(os.path.join('bin', 'buildout'))
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.
+ Uninstalling foo.
+ Running uninstall recipe.
<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()
+Safety valves
+-------------
-And now we can uninstall again (albeit with some warnings):
+If the section has been removed, nothing can be found by the uninstall. You
+get warnings that way:
- >>> 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
+ >>> 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
+ ... ''' % ( { 'crontest': crontestfile } ))
+
+ >>> import os
+ >>> print system(os.path.join('bin', 'buildout'))
+ Installing foo.
+ <BLANKLINE>
+ >>> c.crontab = []
+ >>> c.write_crontab()
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... parts =
+ ... ''' % ( { 'crontest': crontestfile } ))
+ >>> print system(os.path.join('bin', 'buildout'))
Uninstalling foo.
Running uninstall recipe.
foo: WARNING: Did not find a crontab-entry during uninstall; please check manually if everything was removed correctly
<BLANKLINE>
+Another test: pre-0.6 config simulation:
+
+ >>> 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
+ ... ''' % ( { 'crontest': crontestfile } ))
+
+ >>> import os
+ >>> print system(os.path.join('bin', 'buildout'))
+ Installing foo.
+ <BLANKLINE>
+ >>> c.crontab = ['WARNING="Everything below is added by bla bla"',
+ ... 'BUILDOUT=/somewhere/out/there',
+ ... '# @reboot\techo nothing happens']
+ >>> c.write_crontab()
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... parts =
+ ... ''' % ( { 'crontest': crontestfile } ))
+ >>> print system(os.path.join('bin', 'buildout'))
+ Uninstalling foo.
+ Running uninstall recipe.
+ <BLANKLINE>
+ >>> c.read_crontab()
+ >>> print c
+ <BLANKLINE>
Modified: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py 2009-06-16 12:27:38 UTC (rev 101075)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/__init__.py 2009-06-16 12:57:40 UTC (rev 101076)
@@ -20,19 +20,17 @@
options['entry'] = '%s\t%s' % (options['times'], options['command'])
readcrontab = self.options.get('readcrontab', None)
writecrontab = self.options.get('writecrontab', None)
+ self.options['identifier'] = '%s [%s]' % (
+ buildout['buildout']['directory'], name)
+ self.crontab = UserCrontabManager(
+ readcrontab, writecrontab,
+ identifier=self.options['identifier'])
- self.crontab = UserCrontabManager(readcrontab, writecrontab)
- self.env = {
- 'WARNING':
- 'The entries below were generated by buildout, do not modify',
- #'BUILDOUT': buildout['buildout']['directory']
- }
-
def install(self):
crontab = self.crontab
crontab.read_crontab()
- crontab.add_entry(self.options['entry'], **self.env)
+ crontab.add_entry(self.options['entry'])
crontab.write_crontab()
return ()
@@ -45,7 +43,10 @@
readcrontab = options.get('readcrontab', None)
writecrontab = options.get('writecrontab', None)
- crontab = UserCrontabManager(readcrontab, writecrontab)
+ identifier = options.get('identifier', 'NO IDENTIFIER')
+ crontab = UserCrontabManager(
+ readcrontab, writecrontab,
+ identifier=identifier)
crontab.read_crontab()
nuked = crontab.del_entry(options['entry'])
if nuked==0:
Modified: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/tests.py
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/tests.py 2009-06-16 12:27:38 UTC (rev 101075)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/tests.py 2009-06-16 12:57:40 UTC (rev 101076)
@@ -16,16 +16,16 @@
from z3c.recipe.usercrontab import UserCrontabManager
-usercrontab = UserCrontabManager()
+usercrontab = UserCrontabManager(identifier='test')
def setUp(test):
zc.buildout.testing.buildoutSetUp(test)
- usercrontab.read_crontab()
+ usercrontab.read_crontab() # Store current user's real crontab.
zc.buildout.testing.install_develop('z3c.recipe.usercrontab', test)
def tearDown(test):
zc.buildout.testing.buildoutTearDown(test)
- usercrontab.write_crontab()
+ usercrontab.write_crontab() # Restore current user's real crontab.
def test_suite():
return unittest.TestSuite(doctest.DocFileSuite('README.txt', setUp=setUp,
Modified: z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py
===================================================================
--- z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py 2009-06-16 12:27:38 UTC (rev 101075)
+++ z3c.recipe.usercrontab/trunk/src/z3c/recipe/usercrontab/usercrontab.py 2009-06-16 12:57:40 UTC (rev 101076)
@@ -12,6 +12,10 @@
import re
+PREPEND = '# Generated by %s'
+APPEND = '# END %s'
+
+
def escape_string(s):
"""
Do a smart escape of string s, wrapping it in quotes and escaping
@@ -39,40 +43,6 @@
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'''
- ^ # Start of line
- ( # begin first group
- "[^"]*" # something enclosed in double quotes
- |\'[^\']*\' # OR something enclosed in single quotes
- |[^\s]+ # OR some non-space-containing string
- ) # end first group
-
- \s*=\s* # "=" surrounded by spaces
-
- ( # start second group
- "[^"]*" # something enclosed in double quotes
- |\'[^\']*\' # OR something enclosed in single quotes
- |[^"\']+ # OR something that does not have quotes
- )? # end of *optional* second group
-
- [^\s]* # trailing whitespace
- $ # end of line
- ''',
- re.VERBOSE)
-
-
-
defaultreadcrontab = "crontab -l"
defaultwritecrontab = "crontab -"
@@ -85,9 +55,12 @@
username = None
crontab = []
- def __init__(self, readcrontab=None, writecrontab=None):
+ def __init__(self, readcrontab=None, writecrontab=None, identifier=None):
self.readcrontab = readcrontab or defaultreadcrontab
self.writecrontab = writecrontab or defaultwritecrontab
+ assert identifier is not None
+ self.append = APPEND % identifier
+ self.prepend = PREPEND % identifier
def read_crontab(self):
self.crontab = [l.strip("\n") for l in
@@ -102,80 +75,95 @@
def __repr__(self):
return "\n".join(self.crontab)
- def add_entry(self, entry, **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
+ def find_boundaries(self):
+ # Migration: first zap all old BUILDOUT environment variables from
+ # version 0.5. A bit rude to do it here, but the feature was only
+ # released for a couple of hours.
+ self.crontab = [line for line in self.crontab
+ if not line.startswith('BUILDOUT=')]
- for line in self.crontab:
- match = env_re.match(line)
- if match:
- # We have an environment statement ('MAILTO=something')
- env_key = match.group(1)
- env_value = match.group(2)
- if env_key == 'BUILDOUT':
- # Feature only available in 0.5, reverted in 0.5.1: we
- # omit this environment variable now.
- continue
- cur_env[unescape_string(env_key)] = unescape_string(env_value)
+ start = None
+ end = None
+ old_warning_marker = None
+ for line_number, line in enumerate(self.crontab):
+ if line.strip() == self.prepend:
+ if start is not None:
+ raise RuntimeError("%s found twice in the same crontab. "
+ "Fix by hand." % self.prepend)
+ start = line_number
+ if line.strip() == self.append:
+ if end is not None:
+ raise RuntimeError("%s found twice in the same crontab. "
+ "Fix by hand." % self.append)
+ end = line_number + 1
+ # ^^^ +1 as we want the range boundary and that is behind the
+ # element.
+ if line.startswith('WARNING='):
+ old_warning_marker = line_number
+ return start, end, old_warning_marker
- new_crontab.append(line)
- if not done and dict_pmatch(env, cur_env):
- if line != entry:
- # Not already added 3 lines above...
- new_crontab.append(entry)
- done = True
+ def add_entry(self, entry):
+ """Add an entry to the crontab.
- if (not done):
- for (k, v) in env.iteritems():
- if k not in cur_env or cur_env[k] != v:
- if k == 'BUILDOUT':
- # empty line for better between-buildout visual separation.
- new_crontab.append('')
- new_crontab.append('%s=%s' % (escape_string(k),
- escape_string(v)))
- new_crontab.append(entry)
+ Find lines enclosed by APPEND/PREPEND, zap and re-add.
- 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.
+ start, end, old_warning_marker = self.find_boundaries()
+ inject_at = -1 # By default at the end of the file.
+ if old_warning_marker:
+ # At least in front of the old warning marker.
+ inject_at = old_warning_marker
+ if start is not None and end is not None:
+ # But preferably in our existing location.
+ self.crontab[start:end] = []
+ inject_at = start
- (If the same entry occurs multiple times, it is removed several
- times)
+ to_inject = ['', self.prepend, entry, self.append, '']
+ if inject_at == -1:
+ # [-1:-1] would inject before the last item...
+ self.crontab += to_inject
+ else:
+ self.crontab[inject_at:inject_at] = to_inject
+
+ def del_entry(self, entry):
+ """Remove an entry from a crontab.
+
+ Drop now-useless WARNING environment if it is the last one in the
+ file.
+
"""
- 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
+ start, end, old_warning_marker = self.find_boundaries()
+ if start is not None and end is not None:
+ if start > 0:
+ if not self.crontab[start - 1].strip():
+ # Also strip empty line in front.
+ start = start - 1
+ if end < len(self.crontab):
+ if not self.crontab[end].strip():
+ # Also strip empty line after end marker.
+ # Note: not self.crontab[end + 1] as end is the location
+ # AFTER the end marker to selected it with [start:end].
+ end = end + 1
+ if end == len(self.crontab):
+ end = None # Otherwise the last line stays in place
+ self.crontab[start:end] = []
+ return 1 # Number of entries that are removed.
+
+ if old_warning_marker is not None:
+ old = len(self.crontab[old_warning_marker:])
+ self.crontab[old_warning_marker:] = [
+ line for line in self.crontab[old_warning_marker:]
+ if line != entry]
+ new = len(self.crontab[old_warning_marker:])
+
+ # Cleanup when possible
+ remaining = [line for line in self.crontab[old_warning_marker:]
+ if line.strip()]
+ if len(remaining) == 1:
+ # Just the WARNING marker, so remove everything.
+ self.crontab[old_warning_marker:] = []
+
+ return old - new
+
+ # Nothing removed.
+ return 0
More information about the Checkins
mailing list