Skip to content

Commit

Permalink
Issue 59: Support crontab ranges 'x-y' and 'x/y' (#49)
Browse files Browse the repository at this point in the history
* - 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

* - remove list handling of basic items in _range(), which is already
  done in the top part of the function
  • Loading branch information
ohinckel authored and cstrassburg committed Jul 8, 2016
1 parent f79f4d7 commit abb9d47
Showing 1 changed file with 28 additions and 9 deletions.
37 changes: 28 additions & 9 deletions lib/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ def _crontab(self, crontab):
if not next_event:
next_event = self._parse_month(crontab, next_month=True) # 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, next_month=False):
Expand All @@ -410,7 +410,7 @@ def _parse_month(self, crontab, next_month=False):
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 next_month: # next month
next_event = event_range[0]
Expand Down Expand Up @@ -507,16 +507,35 @@ 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)
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:
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))
for entry in item_range:
result.append('{:02d}'.format(entry))

return result

def _day_range(self, days):
Expand Down

0 comments on commit abb9d47

Please sign in to comment.