diff --git scripts/update.sh scripts/update.sh new file mode 100755 index 0000000..6f33c33 --- /dev/null +++ scripts/update.sh @@ -0,0 +1,347 @@ +#!/usr/bin/env php + drupal_get_installed_schema_version($module); +} + +function update_show_updates($updates) { + echo t('Modules requiring updates:') . "\n\n"; + $files = system_get_module_data(); + foreach ($updates as $module => $update_list) { + echo "{$files[$module]->info['name']} ({$files[$module]->name})\n"; + echo " " . t('Pending updates:') . ' ' . implode(',', $update_list) . "\n\n"; + } +} + +function update_show_versions() { + + $files = system_get_module_data(); + + printf("%-20s %-20s %-19s %5s\n\n", 'Name', 'Module', 'Version', 'Schema'); + foreach ($files as $module => $file) { + printf("%-20s %-20s %-19s %5s\n", $file->info['name'], $module, $file->info['version'], $file->schema_version); + } +} + +function update_do_updates($updates) { + global $maintenance; + if ($maintenance) { + $site_status = variable_get('site_offline', 0); + variable_set('site_offline', 1); + if ($maintenance !== TRUE) { + $site_status_message = variable_get('site_offline_message', NULL); + variable_set('site_offine_message', $message); + } + } + $operations = array(); + foreach ($updates as $module => $update_list) { + foreach ($update_list as $update) { + $operations[] = array('update_sh_do_one', array($module, $update)); + } + } + + // Since this is running from the shell, we want to turn progressive off. + $_init_batch =& batch_get(); + if (empty($_init_batch)) { + $_init_batch = array( + 'sets' => array(), + 'progressive' => FALSE, + ); + } + + $batch = array( + 'operations' => $operations, + 'title' => 'Updating', + 'init_message' => 'Starting updates', + 'error_message' => 'An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference.', + 'finished' => 'update_sh_finished', + 'progressive' => FALSE, + ); + + batch_set($batch); + batch_process(); + + if ($_SESSION['update_success']) { + $output = 'Updates were attempted. If you see no failures below, you may proceed happily to the administration pages. Otherwise, you may need to update your database manually.' . $log_message . "\n"; + } + else { + list($module, $version) = array_pop(reset($_SESSION['updates_remaining'])); + $output = 'The update process was aborted prematurely while running update #' . $version . ' in ' . $module . '.module.' . $log_message; + if (module_exists('dblog')) { + $output .= ' You may need to check the watchdog database table manually.'; + } + $output .= "\n"; + } + + // Output a list of queries executed + $update_ok = TRUE; + if (!empty($_SESSION['update_results'])) { + $output .= "The following queries were executed\n\n"; + foreach ($_SESSION['update_results'] as $module => $updates) { + $output .= $module . " module\n"; + foreach ($updates as $number => $queries) { + if ($number != '#abort') { + $output .= 'Update #' . $number . "\n"; + foreach ($queries as $query) { + if ($query['success']) { + $output .= '* ' . htmlspecialchars_decode(html_entity_decode($query['query'])) . "\n"; + } + else { + $update_ok = FALSE; + $output .= '* Failed: ' . htmlspecialchars_decode(html_entity_decode($query['query'])) . "\n"; + } + } + if (!count($queries)) { + $output .= "* No queries\n"; + } + } + } + } + echo $output; + } + unset($_SESSION['update_results']); + unset($_SESSION['update_success']); + + if ($maintenance && $update_ok) { + variable_set('site_offline', $site_status); + if (empty($site_status_message)) { + variable_del('site_offine_message'); + } + else { + variable_set('site_offine_message', $site_status_message); + } + } + return $update_ok; +} + +function update_sh_do_one($module, $number, &$context) { + // If updates for this module have been aborted + // in a previous step, go no further. + if (!empty($context['results'][$module]['#abort'])) { + return; + } + + $function = $module . '_update_' . $number; + if (function_exists($function)) { + $ret = $function($context['sandbox']); + } + + if (isset($ret['#finished'])) { + $context['finished'] = $ret['#finished']; + unset($ret['#finished']); + } + + if (!isset($context['results'][$module])) { + $context['results'][$module] = array(); + } + if (!isset($context['results'][$module][$number])) { + $context['results'][$module][$number] = array(); + } + $context['results'][$module][$number] = array_merge($context['results'][$module][$number], $ret); + + if (!empty($ret['#abort'])) { + $context['results'][$module]['#abort'] = TRUE; + } + // Record the schema update if it was completed successfully. + if ($context['finished'] == 1 && empty($context['results'][$module]['#abort'])) { + drupal_set_installed_schema_version($module, $number); + } + + $context['message'] = 'Updating ' . check_plain($module) . ' module'; +} + +function update_sh_finished($success, $results, $operations) { + // clear the caches in case the data has been updated. + drupal_flush_all_caches(); + + $_SESSION['update_results'] = $results; + $_SESSION['update_success'] = $success; + $_SESSION['updates_remaining'] = $operations; +} + +$script = basename(array_shift($_SERVER['argv'])); + +$shortopts = 'hr:s:lum::ve'; +$longopts = array('help', 'root:', 'site:', 'list', 'update', + 'maintenance::', 'verbose', 'versions'); + +$args = @getopt($shortopts, $longopts); + +if (isset($args['h']) || isset($args['help'])) { + echo <<" +Example: {$script} "http://mysite.org/node" + +All arguments are long options. + + -h, --help This page. + + -r, --root Set the working directory for the script to the specified path. + To execute Drupal this has to be the root directory of your + Drupal installation, f.e. /home/www/foo/drupal (assuming Drupal + running on Unix). Current directory is not required. + Use surrounding quotation marks on Windows. + + -s, --site Used to specify with site will be used for the upgrade. If no + site is selected then default will be used. + + -l, --list List all pending updates. If there are updates available then + the script with exit with a 1 return flag + + -u, --update Process all pending updates. If there are any updates are not + processed successfully then the script with exit with a return + flag of 1. + + -m, --maintenance Set the site into maintenance while the updates are being + run. If there are any failures, the site will remain in + maintenance mode. An optional message can be specified which + will set the message on the maintenance screen. + + -v, --verbose This option displays the options as they are set, but will + produce errors from setting the session. + + -e, --versions List the versions of all the modules in the system. + +To run this script without --root argument invoke it from the root directory +of your Drupal installation with + + ./scripts/{$script} + +\n +EOF; + if (version_compare(phpversion(), '5.3.0', 'le')) { + echo "Warning: This version of PHP doesn't support long options\n"; + } + exit; +} + +// define default settings +$_SERVER['HTTP_HOST'] = 'default'; +$_SERVER['PHP_SELF'] = '/update.php'; +$_SERVER['REMOTE_ADDR'] = '127.0.0.1'; +$_SERVER['SERVER_SOFTWARE'] = 'PHP CLI'; +$_SERVER['REQUEST_METHOD'] = 'GET'; +$_SERVER['QUERY_STRING'] = ''; +$_SERVER['PHP_SELF'] = $_SERVER['REQUEST_URI'] = '/'; +$_SERVER['SCRIPT_NAME'] = '/' . basename($_SERVER['SCRIPT_NAME']); +$_SERVER['HTTP_USER_AGENT'] = 'console'; + +// toggle verbose mode +$_verbose_mode = isset($args['h']) || isset($args['help']) ? TRUE : FALSE; + +$maintenance = TRUE; + +// parse invocation arguments +if (isset($args['r']) || isset($args['root'])) { + // change working directory + $path = isset($args['r']) ? $args['r'] : $args['root']; + if (is_dir($path)) { + chdir($path); + if ($_verbose_mode) { + echo "cwd changed to: {$path}\n"; + } + } + else { + echo "\nERROR: {$path} not found.\n\n"; + } +} + +if (isset($args['s']) || isset($args['site'])) { + $site = isset($args['s']) ? $args['s'] : $args['site']; + if (file_exists('./sites/' . $site)) { + $_SERVER['HTTP_HOST'] = $site; + $_SERVER['PHP_SELF'] = $_SERVER['REQUEST_URI'] = '/update.php'; + } + else { + echo "ERROR: Unable to locate site {$site}\n"; + exit(1); + } +} + +if (isset($args['m']) || isset($args['maintenance'])) { + $opt = isset($args['m']) ? $args['m'] : (isset($args['maintenance']) ? $args['maintenance'] : NULL); + if (is_string($opt)) { + $maintenance = $opt; + } +} + +define('DRUPAL_ROOT', realpath(getcwd())); + +include_once './includes/bootstrap.inc'; +drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); +include_once './includes/install.inc'; +include_once './includes/form.inc'; +drupal_load_updates(); + + + +$user = user_load(array('uid' => 1)); +foreach ($args as $arg => $option) { + switch ($arg) { + case 'l': + case 'list': + if ($updates = drupal_get_updates()) { + update_show_updates($updates); + exit(1); + } + else { + echo t('No updates available') . "\n"; + } + break 2; + + case 'e': + case 'versions': + update_show_versions(); + break 2; + + case 'u': + case 'update': + if ($updates = drupal_get_updates()) { + if (!update_do_updates($updates)) { + exit(1); + } + } + break 2; + } +} +exit();