Source code for univention.admin.cron

# SPDX-FileCopyrightText: 2004-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

"""|UDM| functions for creating crontab entries."""

from __future__ import annotations

from typing import TYPE_CHECKING


if TYPE_CHECKING:
    from collections.abc import Mapping, Sequence


[docs] def month_map(month: str) -> str | int | None: """ Map English month name to 1-based numeric month-in-year. .. seealso:: :py:func:`month_reverse_map` >>> month_map('*') '*' >>> month_map('January') 1 """ month_list = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] if month == '*': return '*' if month in month_list: return month_list.index(month) return None # FIXME:
[docs] def weekday_map(weekday: str) -> str | int | None: """ Map English day-of-week name to numeric value 1-7. .. seealso:: :py:func:`weekday_reverse_map` >>> weekday_map('*') '*' >>> weekday_map('Monday') 1 """ weekday_list = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] if weekday == '*': return '*' if weekday in weekday_list: return weekday_list.index(weekday) return None # FIXME:
[docs] def month_reverse_map(month: str | int) -> str | None: """ Map 1-based numeric month-in-year to English month name. .. seealso:: :py:func:`month_map` >>> month_reverse_map('*') '*' >>> month_reverse_map(1) 'January' """ month_list = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] if month == '*': return '*' if int(month) < len(month_list): return month_list[int(month)] return None # FIXME:
[docs] def weekday_reverse_map(weekday: str | int) -> str | None: """ Map numeric day-of-week value 1-7 to English name. .. seealso:: :py:func:`weekday_map` >>> weekday_reverse_map('*') '*' >>> weekday_reverse_map(1) 'Monday' """ weekday_list = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] if weekday == '*': return '*' if int(weekday) < len(weekday_list): return weekday_list[int(weekday)] return None # FIXME:
[docs] def cron_create(cronlist: Mapping[str, Sequence[str]]) -> str: """ Create a crontab time string. :param cronlist: A mapping of strings to lists. .. seealso:: :py:func:`cron_split` >>> cron_create(dict(minute=[], hour=[], day=[], month=[], weekday=[])) '* * * * * ' >>> cron_create(dict(minute=['0'], hour=['1'], day=['2'], month=['March'], weekday=['Thursday'])) '0 1 2 3 4 ' >>> cron_create(dict(minute=['all'], hour=['all'], day=['all'], month=['all'], weekday=['all'])) '0,5,10,15,20,25,30,35,40,45,50,55 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 1,2,3,4,5,6,7,8,9,10,11,12 1,2,3,4,5,6,7 ' """ keys = ['minute', 'hour', 'day', 'month', 'weekday'] string = '' for key in keys: if key in cronlist: if not cronlist[key]: string += '* ' continue for i, cron in enumerate(cronlist[key]): if i > 0: string += ',' if key == 'month': if cron == 'all': string += '1,2,3,4,5,6,7,8,9,10,11,12' else: string += '%s' % month_map(cron) elif key == 'weekday': if cron == 'all': string += '1,2,3,4,5,6,7' else: string += '%s' % weekday_map(cron) elif key == 'day': # note: removed since only values from 1-31 are allowed for days in cron # if cron == '00': # string+='0' if cron == 'all': string += '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31' else: string += '%s' % cron elif key == 'hour': if cron == '00': string += '0' elif cron == 'all': string += '0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23' else: string += '%s' % cron elif key == 'minute': if cron == '00': string += '0' elif cron == 'all': string += '0,5,10,15,20,25,30,35,40,45,50,55' else: string += '%s' % cron string += ' ' return string
[docs] def cron_split(cronlist): """ Split a crontab time string into its parts. :param cronlist: a crontab time string 'minute hour day month weekday'. .. seealso:: :py:func:`cron_create` >>> cron_split('* * * * * ') == {'minute': ['*'], 'hour': ['*'], 'day': ['*'], 'month': ['*'], 'weekday': ['*']} True >>> cron_split('* * * 1 *')['month'] ['January'] >>> cron_split('* * * * 1')['weekday'] ['Monday'] """ cron = cronlist.split(' ') res = {} keys = ['minute', 'hour', 'day', 'month', 'weekday'] pos = 0 for entry in cron: if not entry: continue if keys[pos] == 'month': res[keys[pos]] = [] for i in entry.split(','): try: res[keys[pos]].append(month_reverse_map(i)) except Exception: res[keys[pos]].append(i) elif keys[pos] == 'weekday': res[keys[pos]] = [] for i in entry.split(','): try: res[keys[pos]].append(weekday_reverse_map(i)) except Exception: res[keys[pos]].append(i) elif keys[pos] == 'day' and '55' in entry.split(','): res[keys[pos]] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31'] # fmt: skip else: res[keys[pos]] = entry.split(',') pos += 1 return res