From 3327f04c54f2d5c793e693119c9c560859ea2ba5 Mon Sep 17 00:00:00 2001 From: Oliver Hinckel Date: Fri, 6 Dec 2013 18:20:13 +0100 Subject: [PATCH 1/2] - change _range() function in sheduler: . add support for interval specification using "/x" . add support for range specification using "x-y" . refactor a little bit to have one block which handles a single item, which is used recursively when using ",", "/x" or "x-y" # implements suggestion of issue #59 - log exception message when error occurs while analyzing the crontab entry --- lib/scheduler.py | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/scheduler.py b/lib/scheduler.py index 38c7262cf4..6e631b321b 100755 --- a/lib/scheduler.py +++ b/lib/scheduler.py @@ -358,8 +358,8 @@ def _crontab(self, crontab): if not next_event: next_event = self._parse_month(crontab, offset=1) # next month return next_event - except: - logger.error("Error parsing crontab: {}".format(crontab)) + except Exception as e: + logger.error('Error parsing crontab "{}": {}'.format(crontab, e)) return datetime.datetime.now(tzutc()) + dateutil.relativedelta.relativedelta(years=+10) def _parse_month(self, crontab, offset=0): @@ -378,7 +378,7 @@ def _parse_month(self, crontab, offset=0): day_range = day_range + self._range(day, 0o1, mdays) else: day_range = self._range(day, 0o1, mdays) - # combine the differnt ranges + # combine the different ranges event_range = sorted([str(day) + '-' + str(hour) + '-' + str(minute) for minute in minute_range for hour in hour_range for day in day_range]) if offset: # next month next_event = event_range[0] @@ -472,16 +472,36 @@ def _sun(self, crontab): def _range(self, entry, low, high): result = [] item_range = [] - if entry == '*': - item_range = list(range(low, high + 1)) - else: + + # Check for multiple items and process each item recursively + if ',' in entry: for item in entry.split(','): - item = int(item) - if item > high: # entry above range - item = high # truncate value to highest possible - item_range.append(item) - for entry in item_range: - result.append('{:02d}'.format(entry)) + result.extend(self._range(item, low, high)) + + # Check for intervals, e.g. "*/2", "9-17/2" + elif '/' in entry: + spec_range, interval = entry.split('/') + logger.error('Cron spec interval {} {}'.format(entry, interval)) + result = self._range(spec_range, low, high)[::int(interval)] + + # Check for numeric ranges, e.g. "9-17" + elif '-' in entry: + spec_low, spec_high = entry.split('-') + result = self._range('*', int(spec_low), int(spec_high)) + + # Process single item + else: + if entry == '*': + item_range = list(range(low, high + 1)) + else: + for item in entry.split(','): + item = int(item) + if item > high: # entry above range + item = high # truncate value to highest possible + item_range.append(item) + for entry in item_range: + result.append('{:02d}'.format(entry)) + return result def _day_range(self, days): From 0d12f35433c0f2027a59fa146122d91c3e9301ad Mon Sep 17 00:00:00 2001 From: Oliver Hinckel Date: Fri, 6 Dec 2013 22:03:02 +0100 Subject: [PATCH 2/2] - remove list handling of basic items in _range(), which is already done in the top part of the function --- lib/scheduler.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/scheduler.py b/lib/scheduler.py index 6e631b321b..e3790d5207 100755 --- a/lib/scheduler.py +++ b/lib/scheduler.py @@ -494,11 +494,10 @@ def _range(self, entry, low, high): if entry == '*': item_range = list(range(low, high + 1)) else: - for item in entry.split(','): - item = int(item) - if item > high: # entry above range - item = high # truncate value to highest possible - item_range.append(item) + item = int(entry) + if item > high: # entry above range + item = high # truncate value to highest possible + item_range.append(item) for entry in item_range: result.append('{:02d}'.format(entry))