Created
November 21, 2016 07:25
-
-
Save kalabro/470aaf49b9727c0c0a795ea7daf69eb6 to your computer and use it in GitHub Desktop.
Duuu! Drupal Auto-Update script. Dirty and Old fashioned.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Duuu! Drupal Auto-Update script. Last tested with Drush 7.0. | |
* TODO: | |
* - convert to command. | |
* | |
* Requirements: | |
* - Drush 7 **OR** Core Update module enabled. | |
* - curl (optionally for HTTP site check). | |
* | |
* Usage: | |
* > drush scr /path/to/duuu.php --r /www/drupal -l https://example.com --security-only [email protected] -y | |
* | |
*/ | |
// Projects to update. Leave empty to update all. Use --security-only flag to check security releases only. | |
$projects = array(); // All projects mode. | |
//$projects = array('drupal'); // Core only mode. | |
$email = drush_get_option('email', variable_get('site_mail')); | |
$bcc = '[email protected]'; | |
$messages = array(); | |
$backup_dir = drush_get_option('backup-dir', drush_server_home() . '/' . 'drush-backups'); | |
$backup_dir = drush_trim_path($backup_dir) . '/duuu/' . gmdate('Y-m-d_His', $_SERVER['REQUEST_TIME']); | |
// Set one backup dir for all further backups. | |
drush_set_context('DRUSH_BACKUP_DIR', $backup_dir); | |
drush_prepare_backup_dir(); | |
// 1. Check if there are security updates of Drupal core. | |
drush_log('1. Check if there are new updates.'); | |
// Requires update module for Drush < 7. | |
drush_invoke_process('@self', 'cc', array('drush')); | |
$return = drush_invoke_process('@self', 'pm-updatestatus', $projects, array('security-only' => drush_get_option('security-only')), FALSE); | |
$candidates = array(); | |
foreach ($return['object'] as $project => $project_data) { | |
if (empty($projects) || in_array($project, $projects)) { | |
if ($project_data['existing_version'] != $project_data['candidate_version']) { | |
$candidates[$project] = $project . '-' . $project_data['candidate_version']; | |
} | |
} | |
} | |
if (empty($candidates)) { | |
drush_log(dt('No code updates available.'), 'ok'); | |
drush_delete_dir($backup_dir); | |
return FALSE; | |
} | |
drush_print_r($candidates); | |
// 2. Backup database. | |
drush_log('2. Backup database.'); | |
$return = drush_invoke_process('@self', 'sql-dump', array(), array( | |
'result-file' => $backup_dir . '/database.sql', | |
'gzip' => TRUE | |
), FALSE); | |
if ($return['error_status'] || empty($return['object'])) { | |
return drush_set_error('DRUSH_SQL_DUMP_FAILED', dt('sql-dump failed.')); | |
} | |
$backup_sql = $return['object']; | |
drush_log($backup_sql); | |
// 3. Move site to maintenance mode. | |
drush_log('3. Move site to maintenance mode.'); | |
drush_invoke_process('@self', 'vset', array( | |
'maintenance_mode', | |
'1' | |
), array('exact' => TRUE), FALSE); | |
// 4. Enable Update module. | |
drush_log('4. Enable Update module.'); | |
$update_is_enabled_by_script = FALSE; | |
if (!module_exists('update')) { | |
$return = drush_invoke_process('@self', 'en', array('update'), array(), FALSE); | |
$update_is_enabled_by_script = TRUE; | |
} | |
// 5. Duuu it finally! | |
drush_log('5. Duuu it finally!'); | |
$success = TRUE; | |
try { | |
// Unset options unsupported by pm-update. | |
drush_unset_option('email'); | |
// drush_invoke('up') always returns FALSE thus $return doesn't make sense. | |
$return = drush_invoke('up', $projects); | |
// Use Drush errors stack to check if update failed. | |
$errors = drush_get_context('DRUSH_ERROR_LOG', array()); | |
if (!empty($errors)) { | |
foreach ($errors as $error_code => $error_messages) { | |
$messages[] = $error_code . ': ' . implode(', ', $error_messages); | |
} | |
$success = FALSE; | |
} | |
} catch (Exception $e) { | |
$messages[] = $e->getCode() . ': ' . $e->getMessage(); | |
$success = FALSE; | |
} | |
// Restore robots.txt, .gitignore, .htaccess. | |
drush_print_r($candidates); | |
if (isset($candidates['drupal'])) { | |
$restore_files = array('robots.txt', '.gitignore', '.htaccess'); | |
foreach ($restore_files as $file) { | |
$old_file = $backup_dir . '/drupal/' . $file; | |
$new_file = drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . $file; | |
drush_print($old_file . ' ' . md5_file($old_file)); | |
drush_print($new_file . ' ' . md5_file($new_file)); | |
if (md5_file($old_file) != md5_file($new_file)) { | |
// Restore. | |
@drush_op('rename', $new_file, "$new_file.new"); | |
copy($old_file, $new_file); | |
$messages[] = dt('Manual update of @file is required. New file is save as @file.new.', array('@file' => $file)); | |
} | |
} | |
} | |
// Turn off maintenance mode. | |
drush_invoke_process('@self', 'vset', array( | |
'maintenance_mode', | |
'0' | |
), array('exact' => TRUE), FALSE); | |
// Disable Update module. | |
if ($update_is_enabled_by_script) { | |
drush_invoke_process('@self', 'dis', array('update'), array(), FALSE); | |
} | |
// Touch front page. | |
$site_available = TRUE; | |
$http_code = duuu_get_front_page_http_code(); | |
drush_log(dt('Front page responses with @code code.', array('@code' => $http_code))); | |
if ($http_code >= 500) { | |
$success = FALSE; | |
$site_available = FALSE; | |
} | |
// Rollback. | |
if (!$success) { | |
// Call context-specific upc rollback function in case it wasn't called in drush_invoke('up'). | |
drush_pm_updatecode_rollback(); | |
// Database restore. | |
drush_invoke_process('@self', 'sql-query', array(), array('file' => $backup_sql), FALSE); | |
// Check if site was restored successfully. | |
$http_code = duuu_get_front_page_http_code(); | |
if ($http_code >= 500) { | |
$site_available = FALSE; | |
} | |
} | |
$messages[] = dt('Backup is stored in @backup_dir', array('@backup_dir' => $backup_dir)); | |
if (drush_shell_exec('which du')) { | |
drush_shell_exec("du -cksh %s", $backup_dir); | |
$return = drush_shell_exec_output(); | |
if (isset($return[1]) && preg_match('/([\.\w]+)\stotal/', $return[1], $matches)) { | |
$messages[] = dt('Backup size: @size.', array('@size' => $matches[1])); | |
} | |
} | |
// 6. Send email. | |
drush_log(dt('6. Send email.')); | |
if ($success) { | |
$title = dt('Update successful to @candidates.', array('@candidates' => implode(', ', $candidates))); | |
} | |
else { | |
$title = dt('New releases available: @candidates. Automatic update failed.', array('@candidates' => implode(', ', $candidates))); | |
} | |
if (!$site_available) { | |
// TODO: does Drush still works if Drupal is down? | |
$title = dt('SITE UNAVAILABLE!') . ' ' . $title; | |
mail($email, $title, implode("\n", $messages), "Bcc: $bcc"); | |
} | |
else { | |
$mail_message = drupal_mail('drush', 'key', $email, language_default(), array(), variable_get('site_mail'), FALSE); | |
$mail_message['subject'] = $title; | |
$mail_message['body'] = $messages; | |
$mail_message['headers']['Bcc'] = $bcc; | |
$system = drupal_mail_system('drush', 'key'); | |
$mail_message = $system->format($mail_message); | |
$mail_message['result'] = $system->mail($mail_message); | |
$result = $mail_message['result']; | |
} | |
function duuu_get_front_page_http_code() { | |
$site_url = drush_get_context('DRUSH_URI'); | |
if ($site_url != 'http://default' && valid_url($site_url) && drush_shell_exec('which curl')) { | |
drush_shell_exec('curl -s -o /dev/null -I -w "%{http_code}" ' . check_url($site_url) . '/'); | |
$return = drush_shell_exec_output(); | |
$http_code = intval($return[0]); | |
return $http_code; | |
} | |
// Command can not be executed. | |
return -1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment