update_7.inc

  1. 8.0.x commands/core/drupal/update_7.inc
  2. 6.x commands/core/drupal/update_7.inc
  3. 7.x commands/core/drupal/update_7.inc
  4. 3.x commands/core/drupal/update_7.inc
  5. 5.x commands/core/drupal/update_7.inc
  6. master commands/core/drupal/update_7.inc

Update.php for provisioned sites. This file is a derivative of the standard drupal update.php, which has been modified to allow being run from the command line.

Functions

Namesort descending Description
drush_update_batch Start the database update batch process.
drush_update_do_one Perform one update and store the results which will later be displayed on the finished page.
drush_update_finished
updatedb_status Return a 2 item array with
update_check_requirements Check update requirements and report any errors.
update_extra_requirements Returns (and optionally stores) extra requirements that only apply during particular parts of the update.php process.
update_main
update_main_prepare
_update_batch_command

Constants

Namesort descending Description
MAINTENANCE_MODE Global flag to identify update.php run, and so avoid various unwanted operations, such as hook_init() and hook_exit() invokes, css/js preprocessing and translation, and solve some theming issues. This flag is checked on several places in Drupal code…

File

commands/core/drupal/update_7.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Update.php for provisioned sites.
  5. * This file is a derivative of the standard drupal update.php,
  6. * which has been modified to allow being run from the command
  7. * line.
  8. */
  9. use Drush\Log\LogLevel;
  10. /**
  11. * Global flag to identify update.php run, and so avoid various unwanted
  12. * operations, such as hook_init() and hook_exit() invokes, css/js preprocessing
  13. * and translation, and solve some theming issues. This flag is checked on several
  14. * places in Drupal code (not just update.php).
  15. */
  16. define('MAINTENANCE_MODE', 'update');
  17. /**
  18. * Drupal's update.inc has functions that are in previous update_X.inc files
  19. * for example, update_check_incompatibility() which can prove useful when
  20. * enabling modules.
  21. */
  22. require_once DRUSH_DRUPAL_CORE . '/includes/update.inc';
  23. /**
  24. * Returns (and optionally stores) extra requirements that only apply during
  25. * particular parts of the update.php process.
  26. */
  27. function update_extra_requirements($requirements = NULL) {
  28. static $extra_requirements = array();
  29. if (isset($requirements)) {
  30. $extra_requirements += $requirements;
  31. }
  32. return $extra_requirements;
  33. }
  34. /**
  35. * Perform one update and store the results which will later be displayed on
  36. * the finished page.
  37. *
  38. * An update function can force the current and all later updates for this
  39. * module to abort by returning a $ret array with an element like:
  40. * $ret['#abort'] = array('success' => FALSE, 'query' => 'What went wrong');
  41. * The schema version will not be updated in this case, and all the
  42. * aborted updates will continue to appear on update.php as updates that
  43. * have not yet been run.
  44. *
  45. * @param $module
  46. * The module whose update will be run.
  47. * @param $number
  48. * The update number to run.
  49. * @param $context
  50. * The batch context array
  51. */
  52. function drush_update_do_one($module, $number, $dependency_map, &$context) {
  53. $function = $module . '_update_' . $number;
  54. // If this update was aborted in a previous step, or has a dependency that
  55. // was aborted in a previous step, go no further.
  56. if (!empty($context['results']['#abort']) && array_intersect($context['results']['#abort'], array_merge($dependency_map, array($function)))) {
  57. return;
  58. }
  59. $context['log'] = FALSE;
  60. $ret = array();
  61. if (function_exists($function)) {
  62. try {
  63. if ($context['log']) {
  64. Database::startLog($function);
  65. }
  66. drush_log("Executing " . $function);
  67. $ret['results']['query'] = $function($context['sandbox']);
  68. // If the update hook returned a status message (common in batch updates),
  69. // show it to the user.
  70. if ($ret['results']['query']) {
  71. drush_log($ret['results']['query'], LogLevel::OK);
  72. }
  73. $ret['results']['success'] = TRUE;
  74. }
  75. // @TODO We may want to do different error handling for different exception
  76. // types, but for now we'll just print the message.
  77. catch (Exception $e) {
  78. $ret['#abort'] = array('success' => FALSE, 'query' => $e->getMessage());
  79. drush_set_error('DRUPAL_EXCEPTION', $e->getMessage());
  80. }
  81. if ($context['log']) {
  82. $ret['queries'] = Database::getLog($function);
  83. }
  84. }
  85. if (isset($context['sandbox']['#finished'])) {
  86. $context['finished'] = $context['sandbox']['#finished'];
  87. unset($context['sandbox']['#finished']);
  88. }
  89. if (!isset($context['results'][$module])) {
  90. $context['results'][$module] = array();
  91. }
  92. if (!isset($context['results'][$module][$number])) {
  93. $context['results'][$module][$number] = array();
  94. }
  95. $context['results'][$module][$number] = array_merge($context['results'][$module][$number], $ret);
  96. if (!empty($ret['#abort'])) {
  97. // Record this function in the list of updates that were aborted.
  98. $context['results']['#abort'][] = $function;
  99. }
  100. // Record the schema update if it was completed successfully.
  101. if ($context['finished'] == 1 && empty($ret['#abort'])) {
  102. drupal_set_installed_schema_version($module, $number);
  103. }
  104. $context['message'] = 'Performed update: ' . $function;
  105. }
  106. /**
  107. * Check update requirements and report any errors.
  108. */
  109. function update_check_requirements() {
  110. $warnings = FALSE;
  111. // Check the system module and update.php requirements only.
  112. $requirements = system_requirements('update');
  113. $requirements += update_extra_requirements();
  114. // If there are issues, report them.
  115. foreach ($requirements as $requirement) {
  116. if (isset($requirement['severity']) && $requirement['severity'] != REQUIREMENT_OK) {
  117. $message = isset($requirement['description']) ? $requirement['description'] : '';
  118. if (isset($requirement['value']) && $requirement['value']) {
  119. $message .= ' (Currently using ' . $requirement['title'] . ' ' . $requirement['value'] . ')';
  120. }
  121. $warnings = TRUE;
  122. drupal_set_message($message, LogLevel::WARNING);
  123. }
  124. }
  125. return $warnings;
  126. }
  127. function update_main_prepare() {
  128. // Some unavoidable errors happen because the database is not yet up-to-date.
  129. // Our custom error handler is not yet installed, so we just suppress them.
  130. drush_errors_off();
  131. // We prepare a minimal bootstrap for the update requirements check to avoid
  132. // reaching the PHP memory limit.
  133. $core = DRUSH_DRUPAL_CORE;
  134. require_once $core . '/includes/bootstrap.inc';
  135. require_once $core . '/includes/common.inc';
  136. require_once $core . '/includes/file.inc';
  137. require_once $core . '/includes/entity.inc';
  138. include_once $core . '/includes/unicode.inc';
  139. update_prepare_d7_bootstrap();
  140. drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
  141. require_once $core . '/includes/install.inc';
  142. require_once $core . '/modules/system/system.install';
  143. // Load module basics.
  144. include_once $core . '/includes/module.inc';
  145. $module_list['system']['filename'] = 'modules/system/system.module';
  146. module_list(TRUE, FALSE, FALSE, $module_list);
  147. drupal_load('module', 'system');
  148. // Reset the module_implements() cache so that any new hook implementations
  149. // in updated code are picked up.
  150. module_implements('', FALSE, TRUE);
  151. // Set up $language, since the installer components require it.
  152. drupal_language_initialize();
  153. // Set up theme system for the maintenance page.
  154. drupal_maintenance_theme();
  155. // Check the update requirements for Drupal.
  156. update_check_requirements();
  157. // update_fix_d7_requirements() needs to run before bootstrapping beyond path.
  158. // So bootstrap to DRUPAL_BOOTSTRAP_LANGUAGE then include unicode.inc.
  159. drupal_bootstrap(DRUPAL_BOOTSTRAP_LANGUAGE);
  160. update_fix_d7_requirements();
  161. // Clear the module_implements() cache before the full bootstrap. The calls
  162. // above to drupal_maintenance_theme() and update_check_requirements() have
  163. // invoked hooks before all modules have actually been loaded by the full
  164. // bootstrap. This means that the module_implements() results for any hooks
  165. // that have been invoked, including hook_module_implements_alter(), is a
  166. // smaller set of modules than should be returned normally.
  167. // @see https://github.com/drush-ops/drush/pull/399
  168. module_implements('', FALSE, TRUE);
  169. // Now proceed with a full bootstrap.
  170. drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL);
  171. drupal_maintenance_theme();
  172. drush_errors_on();
  173. include_once DRUPAL_ROOT . '/includes/batch.inc';
  174. drupal_load_updates();
  175. update_fix_compatibility();
  176. // Change query-strings on css/js files to enforce reload for all users.
  177. _drupal_flush_css_js();
  178. // Flush the cache of all data for the update status module.
  179. if (db_table_exists('cache_update')) {
  180. cache_clear_all('*', 'cache_update', TRUE);
  181. }
  182. module_list(TRUE, FALSE, TRUE);
  183. }
  184. function update_main() {
  185. update_main_prepare();
  186. list($pending, $start) = updatedb_status();
  187. if ($pending) {
  188. // @todo get table header working.
  189. // $headers = array(dt('Module'), dt('ID'), dt('Description'));
  190. drush_print_table($pending);
  191. if (!drush_confirm(dt('Do you wish to run all pending updates?'))) {
  192. return drush_user_abort();
  193. }
  194. drush_update_batch($start);
  195. }
  196. else {
  197. drush_log(dt("No database updates required"), LogLevel::SUCCESS);
  198. }
  199. }
  200. function _update_batch_command($id) {
  201. update_main_prepare();
  202. drush_batch_command($id);
  203. }
  204. /**
  205. * Start the database update batch process.
  206. *
  207. * @param $start
  208. * An array of all the modules and which update to start at.
  209. * @param $redirect
  210. * Path to redirect to when the batch has finished processing.
  211. * @param $url
  212. * URL of the batch processing page (should only be used for separate
  213. * scripts like update.php).
  214. * @param $batch
  215. * Optional parameters to pass into the batch API.
  216. * @param $redirect_callback
  217. * (optional) Specify a function to be called to redirect to the progressive
  218. * processing page.
  219. */
  220. function drush_update_batch($start) {
  221. // Resolve any update dependencies to determine the actual updates that will
  222. // be run and the order they will be run in.
  223. $updates = update_resolve_dependencies($start);
  224. // Store the dependencies for each update function in an array which the
  225. // batch API can pass in to the batch operation each time it is called. (We
  226. // do not store the entire update dependency array here because it is
  227. // potentially very large.)
  228. $dependency_map = array();
  229. foreach ($updates as $function => $update) {
  230. $dependency_map[$function] = !empty($update['reverse_paths']) ? array_keys($update['reverse_paths']) : array();
  231. }
  232. $operations = array();
  233. foreach ($updates as $update) {
  234. if ($update['allowed']) {
  235. // Set the installed version of each module so updates will start at the
  236. // correct place. (The updates are already sorted, so we can simply base
  237. // this on the first one we come across in the above foreach loop.)
  238. if (isset($start[$update['module']])) {
  239. drupal_set_installed_schema_version($update['module'], $update['number'] - 1);
  240. unset($start[$update['module']]);
  241. }
  242. // Add this update function to the batch.
  243. $function = $update['module'] . '_update_' . $update['number'];
  244. $operations[] = array('drush_update_do_one', array($update['module'], $update['number'], $dependency_map[$function]));
  245. }
  246. }
  247. $batch['operations'] = $operations;
  248. $batch += array(
  249. 'title' => 'Updating',
  250. 'init_message' => 'Starting updates',
  251. '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.',
  252. 'finished' => 'drush_update_finished',
  253. 'file' => 'includes/update.inc',
  254. );
  255. batch_set($batch);
  256. drush_backend_batch_process('updatedb-batch-process');
  257. }
  258. function drush_update_finished($success, $results, $operations) {
  259. // Nothing to do here. All caches already cleared. Kept as documentation of 'finished' callback.
  260. }
  261. /**
  262. * Return a 2 item array with
  263. * - an array where each item is a 3 item associative array describing a pending update.
  264. * - an array listing the first update to run, keyed by module.
  265. */
  266. function updatedb_status() {
  267. $pending = update_get_update_list();
  268. $return = array();
  269. // Ensure system module's updates run first.
  270. $start['system'] = array();
  271. // Print a list of pending updates for this module and get confirmation.
  272. foreach ($pending as $module => $updates) {
  273. if (isset($updates['start'])) {
  274. foreach ($updates['pending'] as $update_id => $description) {
  275. // Strip cruft from front.
  276. $description = str_replace($update_id . ' - ', '', $description);
  277. $return[] = array('module' => ucfirst($module), 'update_id' => $update_id, 'description' => $description);
  278. }
  279. if (isset($updates['start'])) {
  280. $start[$module] = $updates['start'];
  281. }
  282. }
  283. }
  284. return array($return, $start);
  285. }