diff --git a/contrib/crontab.php b/contrib/crontab.php index 72a8fb623..ff6288076 100644 --- a/contrib/crontab.php +++ b/contrib/crontab.php @@ -2,7 +2,8 @@ /* Recipe for adding crontab jobs. -It checks for duplicates by the command part of the job. Changing the schedule will update the crontab. So when you change the command part you have to manually remove the old one. Use `crontab -e` on the server to remove it. +This recipe creates a new section in the crontab file with the configured jobs. +The section is identified by the *crontab:identifier* variable, by default the application name. ## Configuration @@ -20,6 +21,7 @@ ]); ``` */ + namespace Deployer; // Get path to bin @@ -27,110 +29,67 @@ return which('crontab'); }); -desc('Loads crontab'); -task('crontab:load', function () { - set('crontab:all', []); - - // Crontab is empty - if (!test ("{{bin/crontab}} -l >> /dev/null 2>&1")) { - return; - } - - $cronData = run ("{{bin/crontab}} -l"); - $cronLines = explode (PHP_EOL, $cronData); - - $currentTasks = []; - foreach ($cronLines as $cronLine) { - $jobData = parseJob($cronLine); - if (is_null ($jobData)) { - continue; - } - - $currentTasks[$jobData['ckey']] = $jobData; - } - - set ('crontab:all', $currentTasks); +set('crontab:identifier', function () { + return get('application', 'application'); }); desc('Sync crontab jobs'); task('crontab:sync', function () { - $syncJobs = get('crontab:jobs', []); + $cronJobsLocal = get('crontab:jobs', []); - if (count ($syncJobs) == 0) { + if (count($cronJobsLocal) == 0) { writeln("Nothing to sync - configure crontab:jobs"); return; } - // Load current jobs - invoke('crontab:load'); - $cronJobs = get('crontab:all'); - - foreach ($syncJobs as $syncJob) { - $syncJob = parse($syncJob); - $syncJobData = parseJob($syncJob); - - if (is_null ($syncJobData)) { - continue; - } + $cronJobs = getRemoteCrontab(); + $identifier = get('crontab:identifier'); + $sectionStart = "###< $identifier"; + $sectionEnd = "###> $identifier"; - $cronJobData = $cronJobs[$syncJobData['ckey']] ?? NULL; + // find our cronjob section + $start = array_search($sectionStart, $cronJobs); + $end = array_search($sectionEnd, $cronJobs); - if (!is_null ($cronJobData) && $cronJobData['skey'] == $syncJobData['skey']) { - // Job is exists and correct - writeLn($syncJobData['cmd'] . ': OK'); - } - else { - if (is_null ($cronJobData)) { - writeLn($syncJobData['cmd'] . ': NEW'); - } - else { - writeLn($syncJobData['cmd'] . ': FIX'); - } - - $cronJobs[$syncJobData['ckey']] = $syncJobData; + if ($start === false || $end === false) { + // Section is not found, create the section + $cronJobs[] = $sectionStart; + foreach ($cronJobsLocal as $cronJobLocal) { + $cronJobs[] = parse($cronJobLocal); } + $cronJobs[] = $sectionEnd; + writeln("Crontab: Found no section, created the section with configured jobs"); + } else { + // Replace the existing section + array_splice($cronJobs, $start + 1, $end - $start - 1, $cronJobsLocal); + writeln("Crontab: Found existing section, replaced with configured jobs"); } - $tmpCrontabPath = \sprintf('/tmp/%s', \uniqid('crontab_save_')); + setRemoteCrontab($cronJobs); +}); + +function setRemoteCrontab(array $lines): void +{ + $tmpCrontabPath = sprintf('/tmp/%s', uniqid('crontab_save_')); if (test("[ -f '$tmpCrontabPath' ]")) { run("unlink '$tmpCrontabPath'"); } - foreach ($cronJobs as $cronJob) { - $jobString = $cronJob['minute'] . ' ' . $cronJob['hour'] . ' ' . $cronJob['day'] . ' ' . $cronJob['month'] . ' ' . $cronJob['weekday'] . ' ' . $cronJob['cmd']; - run("echo '" . $jobString . "' >> $tmpCrontabPath"); + foreach ($lines as $line) { + run("echo '" . $line . "' >> $tmpCrontabPath"); } run('{{bin/crontab}} ' . $tmpCrontabPath); run('unlink ' . $tmpCrontabPath); -}); - - -function parseJob ($job) { - if (!is_string($job)) { - return NULL; - } - - if (substr ($job, 0, 1) == '#') { - return NULL; - } - - $jobData = explode (' ', $job, 6); +} - if (count ($jobData) != 6) { - return NULL; +function getRemoteCrontab(): array +{ + if (!test("{{bin/crontab}} -l >> /dev/null 2>&1")) { + return []; } - return [ - 'skey' => md5 ($job), - 'ckey' => md5 ($jobData['5']), - 'minute' => $jobData['0'], - 'hour' => $jobData['1'], - 'day' => $jobData['2'], - 'month' => $jobData['3'], - 'weekday' => $jobData['4'], - 'cmd' => $jobData['5'], - ]; + return explode(PHP_EOL, run("{{bin/crontab}} -l")); }