diff options
Diffstat (limited to 'update.php')
-rw-r--r-- | update.php | 276 |
1 files changed, 100 insertions, 176 deletions
diff --git a/update.php b/update.php index c104b2308..c40653161 100644 --- a/update.php +++ b/update.php @@ -283,37 +283,34 @@ function update_fix_watchdog() { * The module whose update will be run. * @param $number * The update number to run. - * - * @return - * TRUE if the update was finished. Otherwise, FALSE. + * @param $context + * The batch conetxt array */ -function update_data($module, $number) { - $ret = module_invoke($module, 'update_'. $number); - // Assume the update finished unless the update results indicate otherwise. - $finished = 1; +function update_do_one($module, $number, &$context) { + $function = $module .'_update_'. $number; + if (function_exists($function)) { + $ret = $function(&$context['sandbox']); + } + if (isset($ret['#finished'])) { - $finished = $ret['#finished']; + $context['finished'] = $ret['#finished']; unset($ret['#finished']); } - // Save the query and results for display by update_finished_page(). - if (!isset($_SESSION['update_results'])) { - $_SESSION['update_results'] = array(); - } - if (!isset($_SESSION['update_results'][$module])) { - $_SESSION['update_results'][$module] = array(); + if (!isset($context['results'][$module])) { + $context['results'][$module] = array(); } - if (!isset($_SESSION['update_results'][$module][$number])) { - $_SESSION['update_results'][$module][$number] = array(); + if (!isset($context['results'][$module][$number])) { + $context['results'][$module][$number] = array(); } - $_SESSION['update_results'][$module][$number] = array_merge($_SESSION['update_results'][$module][$number], $ret); + $context['results'][$module][$number] = array_merge($context['results'][$module][$number], $ret);; - if ($finished == 1) { + if ($context['finished'] == 1) { // Update the installed version drupal_set_installed_schema_version($module, $number); } - return $finished; + $context['message'] = t('Updating @module module', array('@module' => $module)); } function update_selection_page() { @@ -321,8 +318,6 @@ function update_selection_page() { $output .= '<p>Click Update to start the update process.</p>'; drupal_set_title('Drupal database update'); - // Prevent browser from using cached drupal.js or update.js - drupal_add_js('misc/update.js', 'core', 'header', FALSE, TRUE); $output .= drupal_get_form('update_script_selection_form'); update_task_list('select'); @@ -377,7 +372,10 @@ function update_script_selection_form() { return $form; } -function update_update_page() { +function update_batch() { + global $base_url; + + $operations = array(); // Set the installed version so updates start at the correct place. foreach ($_POST['start'] as $module => $version) { drupal_set_installed_schema_version($module, $version - 1); @@ -386,145 +384,35 @@ function update_update_page() { if ($version <= $max_version) { foreach ($updates as $update) { if ($update >= $version) { - $_SESSION['update_remaining'][] = array('module' => $module, 'version' => $update); + $operations[] = array('update_do_one', array($module, $update)); } } } } - - // Keep track of total number of updates - if (isset($_SESSION['update_remaining'])) { - $_SESSION['update_total'] = count($_SESSION['update_remaining']); - } - - if ($_POST['has_js']) { - return update_progress_page(); - } - else { - return update_progress_page_nojs(); - } -} - -function update_progress_page() { - // Prevent browser from using cached drupal.js or update.js - drupal_add_js('misc/progress.js', 'core', 'header', FALSE, TRUE); - drupal_add_js('misc/update.js', 'core', 'header', FALSE, TRUE); - - drupal_set_title('Updating'); - update_task_list('run'); - $output = '<div id="progress"></div>'; - $output .= '<p id="wait">Please wait while your site is being updated.</p>'; - return $output; -} - -/** - * Perform updates for one second or until finished. - * - * @return - * An array indicating the status after doing updates. The first element is - * the overall percentage finished. The second element is a status message. - */ -function update_do_updates() { - while (isset($_SESSION['update_remaining']) && ($update = reset($_SESSION['update_remaining']))) { - $update_finished = update_data($update['module'], $update['version']); - if ($update_finished == 1) { - // Dequeue the completed update. - unset($_SESSION['update_remaining'][key($_SESSION['update_remaining'])]); - $update_finished = 0; // Make sure this step isn't counted double - } - if (timer_read('page') > 1000) { - break; - } - } - - if ($_SESSION['update_total']) { - $percentage = floor(($_SESSION['update_total'] - count($_SESSION['update_remaining']) + $update_finished) / $_SESSION['update_total'] * 100); - } - else { - $percentage = 100; - } - - // When no updates remain, clear the caches in case the data has been updated. - if (!isset($update['module'])) { - cache_clear_all('*', 'cache', TRUE); - cache_clear_all('*', 'cache_page', TRUE); - cache_clear_all('*', 'cache_filter', TRUE); - drupal_clear_css_cache(); - } - - return array($percentage, isset($update['module']) ? 'Updating '. $update['module'] .' module' : 'Updating complete'); + $batch = array( + 'operations' => $operations, + 'title' => 'Updating', + 'init_message' => 'Starting updates', + 'error_message' => 'An unrecoverable error has occured. You can find the error message below. It is advised to copy it to the clipboard for reference.', + 'finished' => 'update_finished', + ); + batch_set($batch); + batch_process($base_url .'/update.php?op=results', $base_url .'/update.php'); } -/** - * Perform updates for the JS version and return progress. - */ -function update_do_update_page() { - global $conf; - - // HTTP Post required - if ($_SERVER['REQUEST_METHOD'] != 'POST') { - drupal_set_message('HTTP Post is required.', 'error'); - drupal_set_title('Error'); - return ''; - } +function update_finished($success, $results, $operations) { + // clear the caches in case the data has been updated. + cache_clear_all('*', 'cache', TRUE); + cache_clear_all('*', 'cache_page', TRUE); + cache_clear_all('*', 'cache_filter', TRUE); + drupal_clear_css_cache(); - // Error handling: if PHP dies, the output will fail to parse as JSON, and - // the Javascript will tell the user to continue to the op=error page. - list($percentage, $message) = update_do_updates(); - print drupal_to_js(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message)); + $_SESSION['update_results'] = $results; + $_SESSION['update_success'] = $success; + $_SESSION['updates_remaining'] = $operations; } -/** - * Perform updates for the non-JS version and return the status page. - */ -function update_progress_page_nojs() { - drupal_set_title('Updating'); - update_task_list('run'); - - $new_op = 'do_update_nojs'; - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - // This is the first page so return some output immediately. - $percentage = 0; - $message = 'Starting updates'; - } - else { - // This is one of the later requests: do some updates first. - - // Error handling: if PHP dies due to a fatal error (e.g. non-existant - // function), it will output whatever is in the output buffer, - // followed by the error message. So, we put an explanation in the - // buffer to guide the user when an error happens. - ob_start(); - $fallback = '<p class="error">An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference. Please continue to the <a href="update.php?op=error">update summary</a>.</p>'; - $fallback = theme('maintenance_page', $fallback, FALSE); - - // We strip the end of the page using a marker in the template, so any - // additional HTML output by PHP shows up inside the page rather than - // below it. While this causes invalid HTML, the same would be true if - // we didn't, as content is not allowed to appear after </html> anyway. - list($fallback) = explode('<!--partial-->', $fallback); - print $fallback; - - // Do updates - list($percentage, $message) = update_do_updates(); - if ($percentage == 100) { - $new_op = 'finished'; - } - - // Updates were successful; wipe the output buffer as it's unneeded. - ob_end_clean(); - } - - drupal_set_html_head('<meta http-equiv="Refresh" content="0; URL=update.php?op='. $new_op .'">'); - $output = theme('progress_bar', $percentage, $message); - $output .= '<p>Updating your site will take a few seconds.</p>'; - - // Note: do not output drupal_set_message()s until the summary page. - print theme('maintenance_page', $output, FALSE); - return NULL; -} - -function update_finished_page($success) { +function update_results_page() { drupal_set_title('Drupal database update'); // NOTE: we can't use l() here because the URL would point to 'update.php?q=admin'. $links[] = '<a href="'. base_path() .'">Main page</a>'; @@ -532,18 +420,18 @@ function update_finished_page($success) { update_task_list(); // Report end result - if ($success) { + if ($_SESSION['update_success']) { $output = '<p>Updates were attempted. If you see no failures below, you may proceed happily to the <a href="index.php?q=admin">administration pages</a>. Otherwise, you may need to update your database manually. All errors have been <a href="index.php?q=admin/logs/watchdog">logged</a>.</p>'; } else { - $update = reset($_SESSION['update_remaining']); - $output = '<p class="error">The update process was aborted prematurely while running <strong>update #'. $update['version'] .' in '. $update['module'] .'.module</strong>. All other errors have been <a href="index.php?q=admin/logs/watchdog">logged</a>. You may need to check the <code>watchdog</code> database table manually.</p>'; + list($module, $version) = array_pop(reset($_SESSION['updates_remaining'])); + $output = '<p class="error">The update process was aborted prematurely while running <strong>update #'. $version .' in '. $module .'.module</strong>. All other errors have been <a href="index.php?q=admin/logs/watchdog">logged</a>. You may need to check the <code>watchdog</code> database table manually.</p>'; } if ($GLOBALS['access_check'] == FALSE) { $output .= "<p><strong>Reminder: don't forget to set the <code>\$access_check</code> value at the top of <code>update.php</code> back to <code>TRUE</code>.</strong></p>"; } - + $output .= theme('item_list', $links); // Output a list of queries executed @@ -570,8 +458,9 @@ function update_finished_page($success) { } } $output .= '</div>'; - unset($_SESSION['update_results']); } + unset($_SESSION['update_results']); + unset($_SESSION['update_success']); return $output; } @@ -779,6 +668,45 @@ function update_create_cache_tables() { } /** + * Create the batch table. + * + * This is part of the Drupal 5.x to 6.x migration. + */ +function update_create_batch_table() { + + // If batch table exists, update is not necessary + if (db_table_exists('batch')) { + return; + } + + $ret = array(); + switch ($GLOBALS['db_type']) { + case 'mysql': + case 'mysqli': + $ret[] = update_sql("CREATE TABLE {batch} ( + bid int(11) NOT NULL, + sid varchar(64) NOT NULL, + timestamp int(11) NOT NULL, + batch longtext, + PRIMARY KEY (bid), + KEY sid (sid) + ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); + break; + case 'pgsql': + $ret[] = update_sql("CREATE TABLE {batch} ( + bid int NOT NULL default '0', + sid varchar(64) NOT NULL default '', + timestamp int NOT NULL default '0', + batch text, + PRIMARY KEY (bid), + )"); + $ret[] = update_sql("CREATE INDEX {batch}_sid_idx ON {batch} (sid)"); + break; + } + return $ret; +} + +/** * Add the update task list to the current page. */ function update_task_list($active = NULL) { @@ -807,6 +735,7 @@ drupal_maintenance_theme(); // variable_(get|set), which only works after a full bootstrap. update_fix_access_table(); update_create_cache_tables(); +update_create_batch_table(); // Turn error reporting back on. From now on, only fatal errors (which are // not passed through the error handler) will cause a message to be printed. @@ -816,6 +745,7 @@ ini_set('display_errors', TRUE); if (($access_check == FALSE) || ($user->uid == 1)) { include_once './includes/install.inc'; + include_once './includes/batch.inc'; drupal_load_updates(); update_fix_schema_version(); @@ -825,39 +755,33 @@ if (($access_check == FALSE) || ($user->uid == 1)) { $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : ''; switch ($op) { - case 'Update': - $output = update_update_page(); - break; - - case 'finished': - $output = update_finished_page(TRUE); - break; - - case 'error': - $output = update_finished_page(FALSE); + // update.php ops + case '': + $output = update_info_page(); break; - case 'do_update': - $output = update_do_update_page(); + case 'selection': + $output = update_selection_page(); break; - case 'do_update_nojs': - $output = update_progress_page_nojs(); + case 'Update': + update_batch(); break; - case 'selection': - $output = update_selection_page(); + case 'results': + $output = update_results_page(); break; + // Regular batch ops : defer to batch processing API default: - $output = update_info_page(); + update_task_list('run'); + $output = _batch_page(); break; } } else { $output = update_access_denied_page(); } - -if (isset($output)) { +if (isset($output) && $output) { print theme('maintenance_page', $output); } |