diff --git a/Dockerfile b/Dockerfile index 035128a..0b29a95 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,7 @@ RUN set -ex; \ docker-cli \ ; -COPY kiwi-cron /usr/local/bin/ +COPY bin /usr/local/bin/ +COPY libexec /usr/local/libexec/ CMD [ "kiwi-cron" ] \ No newline at end of file diff --git a/bin/kiwi-cron b/bin/kiwi-cron new file mode 100755 index 0000000..ce925f9 --- /dev/null +++ b/bin/kiwi-cron @@ -0,0 +1,5 @@ +#!/bin/sh + +# replace crontab, run crond +/usr/local/libexec/kiwi-cron/schedule_dirs | crontab - +exec crond -fd 8 \ No newline at end of file diff --git a/kiwi-cron b/kiwi-cron deleted file mode 100755 index 4660c02..0000000 --- a/kiwi-cron +++ /dev/null @@ -1,172 +0,0 @@ -#!/bin/sh - -crontab='' -crontab_line () { - if [ -z "${crontab}" ]; then - crontab="${1}" - else - crontab="$( - printf '%s\n%s' "${crontab}" "${1}"; - )" - fi -} - -print_cron_schedule() { - pcs_min="${1}" - pcs_hour="${2}" - pcs_day="${3}" - pcs_month="${4}" - pcs_weekday="${5}" - pcs_command="${6}" - - printf '%-8s%-8s%-8s%-8s%-8s%s\n' \ - "${pcs_min}" "${pcs_hour}" "${pcs_day}" "${pcs_month}" "${pcs_weekday}" "${pcs_command}" -} - -create_schedule() { - cs_every="${1:-1}" - cs_units="${2}" - cs_command="${3}" - - if [ "${cs_every}" -eq 1 ]; then - cs_every="" - else - cs_every="/${cs_every}" - fi - - # generate valid random schedule values - # generally, "nighttime" and "weekend" will be preferred. - - # shellcheck disable=SC3028 - rand_min=$(( RANDOM % 60 )) - - # shellcheck disable=SC3028 - # rand_hour=$(( RANDOM % 24 )) - rand_hour=$(( (21 + RANDOM % 7) % 24 )) - - # shellcheck disable=SC3028 - rand_day=$(( RANDOM % 31 + 1 )) - - # shellcheck disable=SC3028 - # rand_weekday=$(( RANDOM % 7 )) - rand_weekday=$(( (6 + RANDOM % 2) % 7 )) - - # shellcheck disable=SC3028 - # rand_month=$(( RANDOM % 12 + 1 )) - rand_month=$(( RANDOM % 2 + 1 )) - - case "${cs_units}" in - minute) - print_cron_schedule \ - "*${cs_every}" "*" "*" "*" "*" "${cs_command}" - ;; - hour) - print_cron_schedule \ - "${rand_min}" "*${cs_every}" "*" "*" "*" "${cs_command}" - ;; - day) - print_cron_schedule \ - "${rand_min}" "${rand_hour}" "*${cs_every}" "*" "*" "${cs_command}" - ;; - week) - print_cron_schedule \ - "${rand_min}" "${rand_hour}" "*" "*" "${rand_weekday}" "${cs_command}" - ;; - month) - print_cron_schedule \ - "${rand_min}" "${rand_hour}" "${rand_day}" "*${cs_every}" "*" "${cs_command}" - ;; - year) - print_cron_schedule \ - "${rand_min}" "${rand_hour}" "${rand_day}" "${rand_month}" "*" "${cs_command}" - ;; - esac -} - -dir_has_no_files () { - dhnf_directory="${1}" - - # count files in directory - dhnf_filecount="$( - find "${dhnf_directory}" -type f -mindepth 1 -maxdepth 1 \ - | wc -l - )" - - # true if empty - test "${dhnf_filecount}" -eq "0" -} - -dir_to_unit () { - dtu_dirname="${1}" - - case "${dtu_dirname}" in - minute|hour|day|week|month|year) - echo "${dtu_dirname}" - ;; - - # truncated "daily" - dai) - echo "day" - ;; - - # truncated "annually" - annual) - echo "year" - ;; - esac -} - -crontab_line '# crontab generated by kiwi-cron' -crontab_line '# generation time: '"$(date)" -crontab_line '#' -crontab_line "$( - print_cron_schedule \ - "# min" "hour" "day" "month" "weekday" "command" -)" - -# check *ly dirs in "/kiwi-cron" directory -schedule_dirs="$( - find "/kiwi-cron" -type d -name "*ly" -mindepth 1 -maxdepth 1 -)" - -for schedule_dir in ${schedule_dirs}; do - # ignore if no files - if dir_has_no_files "${schedule_dir}"; then - continue - fi - - # infer units by directory name - dir_name="${schedule_dir##*/}" - units="${dir_name%ly}" - units="$( dir_to_unit "${units}" )" - - crontab_line "$( - create_schedule "1" "${units}" "run-parts '${schedule_dir}'" - )" -done - -# check dirs in "/kiwi-cron/every" directory -every_schedule_dirs="$( - find "/kiwi-cron/every" -type d -mindepth 1 -maxdepth 1 -)" - -for schedule_dir in ${every_schedule_dirs}; do - # ignore if no files - if dir_has_no_files "${schedule_dir}"; then - continue - fi - - # infer schedule params by directory name - dir_name="${schedule_dir##*/}" - every="$( echo "${dir_name}" | awk -F_ '{print $1}' )" - units="$( echo "${dir_name}" | awk -F_ '{print $2}' )" - units="${units%s}" - - crontab_line "$( - create_schedule "${every}" "${units}" "run-parts '${schedule_dir}'" - )" -done - -# replace crontab, run crond -echo "${crontab}" | crontab - -exec crond -fd 8 diff --git a/libexec/kiwi-cron/create_schedule b/libexec/kiwi-cron/create_schedule new file mode 100755 index 0000000..792b346 --- /dev/null +++ b/libexec/kiwi-cron/create_schedule @@ -0,0 +1,62 @@ +#!/bin/sh + +this_script="$( readlink -f "${0}" )" +this_dir="${this_script%/*}" + +cs_every="${1:-1}" +cs_units="${2}" +cs_command="${3}" + +if [ "${cs_every}" -eq 1 ]; then + cs_every="" +else + cs_every="/${cs_every}" +fi + +# generate valid random schedule values +# generally, "nighttime" and "weekend" will be preferred. + +# shellcheck disable=SC3028 # RANDOM is defined in alpine's /bin/sh +cs_rand_min=$(( RANDOM % 60 )) + +# shellcheck disable=SC3028 +# cs_rand_hour=$(( RANDOM % 24 )) +cs_rand_hour=$(( (21 + RANDOM % 7) % 24 )) + +# shellcheck disable=SC3028 +cs_rand_day=$(( RANDOM % 31 + 1 )) + +# shellcheck disable=SC3028 +# cs_rand_weekday=$(( RANDOM % 7 )) +cs_rand_weekday=$(( (6 + RANDOM % 2) % 7 )) + +# shellcheck disable=SC3028 +# cs_rand_month=$(( RANDOM % 12 + 1 )) +cs_rand_month=$(( RANDOM % 2 + 1 )) + +case "${cs_units}" in +minute) + "${this_dir}/print_cron_schedule" \ + "*${cs_every}" "*" "*" "*" "*" "${cs_command}" + ;; +hour) + "${this_dir}/print_cron_schedule" \ + "${cs_rand_min}" "*${cs_every}" "*" "*" "*" "${cs_command}" + ;; +day) + "${this_dir}/print_cron_schedule" \ + "${cs_rand_min}" "${cs_rand_hour}" "*${cs_every}" "*" "*" "${cs_command}" + ;; +week) + "${this_dir}/print_cron_schedule" \ + "${cs_rand_min}" "${cs_rand_hour}" "*" "*" "${cs_rand_weekday}" "${cs_command}" + ;; +month) + "${this_dir}/print_cron_schedule" \ + "${cs_rand_min}" "${cs_rand_hour}" "${cs_rand_day}" "*${cs_every}" "*" "${cs_command}" + ;; +year) + "${this_dir}/print_cron_schedule" \ + "${cs_rand_min}" "${cs_rand_hour}" "${cs_rand_day}" "${cs_rand_month}" "*" "${cs_command}" + ;; +esac diff --git a/libexec/kiwi-cron/print_cron_schedule b/libexec/kiwi-cron/print_cron_schedule new file mode 100755 index 0000000..10067c9 --- /dev/null +++ b/libexec/kiwi-cron/print_cron_schedule @@ -0,0 +1,11 @@ +#!/bin/sh + +pcs_minute="${1}" +pcs_hour="${2}" +pcs_day="${3}" +pcs_month="${4}" +pcs_weekday="${5}" +pcs_command="${6}" + +printf '%-8s%-8s%-8s%-8s%-8s%s\n' \ + "${pcs_minute}" "${pcs_hour}" "${pcs_day}" "${pcs_month}" "${pcs_weekday}" "${pcs_command}" diff --git a/libexec/kiwi-cron/print_crontab b/libexec/kiwi-cron/print_crontab new file mode 100755 index 0000000..13f4793 --- /dev/null +++ b/libexec/kiwi-cron/print_crontab @@ -0,0 +1,2 @@ +#!/bin/sh + diff --git a/libexec/kiwi-cron/schedule_dirs b/libexec/kiwi-cron/schedule_dirs new file mode 100755 index 0000000..8214536 --- /dev/null +++ b/libexec/kiwi-cron/schedule_dirs @@ -0,0 +1,101 @@ +#!/bin/sh + +this_script="$( readlink -f "${0}" )" +this_dir="${this_script%/*}" + +crontab='' +crontab_line () { + if [ -z "${crontab}" ]; then + crontab="${1}" + else + crontab="$( + printf '%s\n%s' "${crontab}" "${1}"; + )" + fi +} + +dir_has_no_files () { + dhnf_directory="${1}" + + # count files in directory + dhnf_filecount="$( + find "${dhnf_directory}" -type f -mindepth 1 -maxdepth 1 \ + | wc -l + )" + + # true if empty + test "${dhnf_filecount}" -eq "0" +} + +dir_to_unit () { + dtu_dirname="${1}" + + case "${dtu_dirname}" in + # truncated "daily" + dai) + echo "day" + ;; + + # truncated "annually" + annual) + echo "year" + ;; + + *) + echo "${dtu_dirname}" + ;; + esac +} + +crontab_line '# crontab generated by kiwi-cron' +crontab_line '# generation time: '"$(date)" +crontab_line '#' +crontab_line "$( + "${this_dir}/print_cron_schedule" \ + "# min" "hour" "day" "month" "weekday" "command" +)" + +# check *ly dirs in "/kiwi-cron" directory +schedule_dirs="$( + find "/kiwi-cron" -type d -name "*ly" -mindepth 1 -maxdepth 1 +)" + +for schedule_dir in ${schedule_dirs}; do + # ignore if no files + if dir_has_no_files "${schedule_dir}"; then + continue + fi + + # infer units by directory name + dir_name="${schedule_dir##*/}" + units="${dir_name%ly}" + units="$( dir_to_unit "${units}" )" + + crontab_line "$( + "${this_dir}/create_schedule" "1" "${units}" "run-parts '${schedule_dir}'" + )" +done + +# check dirs in "/kiwi-cron/every" directory +every_schedule_dirs="$( + find "/kiwi-cron/every" -type d -mindepth 1 -maxdepth 1 +)" + +for schedule_dir in ${every_schedule_dirs}; do + # ignore if no files + if dir_has_no_files "${schedule_dir}"; then + continue + fi + + # infer schedule params by directory name + dir_name="${schedule_dir##*/}" + every="$( echo "${dir_name}" | awk -F_ '{print $1}' )" + units="$( echo "${dir_name}" | awk -F_ '{print $2}' )" + units="${units%s}" + + crontab_line "$( + "${this_dir}/create_schedule" "${every}" "${units}" "run-parts '${schedule_dir}'" + )" +done + +echo "${crontab}"