diff --git a/core/modules/migrate_drupal_ui/src/Batch/MigrateUpgradeRollbackBatch.php b/core/modules/migrate_drupal_ui/src/Batch/MigrateUpgradeRollbackBatch.php new file mode 100644 index 0000000..2ca582b --- /dev/null +++ b/core/modules/migrate_drupal_ui/src/Batch/MigrateUpgradeRollbackBatch.php @@ -0,0 +1,211 @@ +getDefinition($migration_id); + $configuration = []; + + // @todo Find a way to avoid this in https://www.drupal.org/node/2804611. + if ($definition['destination']['plugin'] === 'entity:file') { + // Make sure we have a single trailing slash. + if ($definition['source']['plugin'] === 'd7_file_private') { + $configuration['source']['constants']['source_base_path'] = rtrim($config['source_private_file_path'], '/') . '/'; + } + $configuration['source']['constants']['source_base_path'] = rtrim($config['source_base_path'], '/') . '/'; + } + + /** @var \Drupal\migrate\Plugin\Migration $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id, $configuration); + + if ($migration) { + static::$messages = new MigrateMessageCapture(); + $executable = new MigrateExecutable($migration, static::$messages); + + $migration_name = $migration->label() ? $migration->label() : $migration_id; + + try { + $migration_status = $executable->rollback(); + } + catch (\Exception $e) { + \Drupal::logger('migrate_drupal_ui')->error($e->getMessage()); + $migration_status = MigrationInterface::RESULT_FAILED; + } + + switch ($migration_status) { + case MigrationInterface::RESULT_COMPLETED: + // Store the number processed in the sandbox. + $context['sandbox']['num_processed'] += static::$numProcessed; + $message = new PluralTranslatableMarkup( + $context['sandbox']['num_processed'], 'Rolled back @migration (processed 1 item total)', 'Rolled back @migration (processed @count items total)', + ['@migration' => $migration_name]); + $context['sandbox']['messages'][] = $message; + \Drupal::logger('migrate_drupal_ui')->notice($message); + $context['sandbox']['num_processed'] = 0; + $context['results']['successes']++; + break; + + case MigrationInterface::RESULT_INCOMPLETE: + $context['sandbox']['messages'][] = (string) new PluralTranslatableMarkup( + static::$numProcessed, 'Continuing with @migration (processed 1 item)', 'Continuing with @migration (processed @count items)', + ['@migration' => $migration_name]); + $context['sandbox']['num_processed'] += static::$numProcessed; + break; + + case MigrationInterface::RESULT_STOPPED: + $context['sandbox']['messages'][] = t('Operation stopped by request'); + break; + + case MigrationInterface::RESULT_FAILED: + $context['sandbox']['messages'][] = t('Operation on @migration failed', ['@migration' => $migration_name]); + $context['results']['failures']++; + static::logger()->error('Operation on @migration failed', ['@migration' => $migration_name]); + break; + + case MigrationInterface::RESULT_SKIPPED: + $context['sandbox']['messages'][] = (string) new TranslatableMarkup('Operation on @migration skipped due to unfulfilled dependencies', ['@migration' => $migration_name]); + \Drupal::logger('migrate_drupal_ui')->error('Operation on @migration skipped due to unfulfilled dependencies', ['@migration' => $migration_name]); + break; + + case MigrationInterface::RESULT_DISABLED: + // Skip silently if disabled. + break; + } + + // Unless we're continuing on with this migration, take it off the list. + if ($migration_status != MigrationInterface::RESULT_INCOMPLETE) { + array_shift($context['sandbox']['migration_ids']); + $context['sandbox']['current']++; + } + + // Add and log any captured messages. + foreach (static::$messages->getMessages() as $message) { + $context['sandbox']['messages'][] = $message; + \Drupal::logger('migrate_drupal_ui')->error($message); + } + + // Only display the last MESSAGE_LENGTH messages, in reverse order. + $message_count = count($context['sandbox']['messages']); + $context['message'] = ''; + for ($index = max(0, $message_count - self::MESSAGE_LENGTH); $index < $message_count; $index++) { + $context['message'] = $context['sandbox']['messages'][$index] . "
\n" . $context['message']; + } + if ($message_count > self::MESSAGE_LENGTH) { + // Indicate there are earlier messages not displayed. + $context['message'] .= '…'; + } + // At the top of the list, display the next one (which will be the one + // that is running while this message is visible). + if (!empty($context['sandbox']['migration_ids'])) { + $migration_id = reset($context['sandbox']['migration_ids']); + $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id); + $migration_name = $migration->label() ? $migration->label() : $migration_id; + $context['message'] = (string) new TranslatableMarkup('Currently rolling back @migration (@current of @max total tasks)', [ + '@migration' => $migration_name, + '@current' => $context['sandbox']['current'], + '@max' => $context['sandbox']['max'], + ]) . "
\n" . $context['message']; + } + } + else { + array_shift($context['sandbox']['migration_ids']); + $context['sandbox']['current']++; + } + + $context['finished'] = 1 - count($context['sandbox']['migration_ids']) / $context['sandbox']['max']; + } + + /** + * Callback executed when Migrate Upgrade Rollback batch process completes. + * + * @param bool $success + * TRUE if batch successfully completed. + * @param array $results + * Batch results. + * @param array $operations + * An array of methods run in the batch. + * @param string $elapsed + * The time to run the batch. + */ + public static function finished($success, array $results, array $operations, $elapsed) { + $successes = $results['successes']; + $failures = $results['failures']; + + // If we had any successes log that for the user. + if ($successes > 0) { + drupal_set_message(\Drupal::translation()->formatPlural($successes, 'Completed 1 rollback task successfully', 'Completed @count rollback tasks successfully')); + } + + // If we had failures, log them and show the migration failed. + if ($failures > 0) { + drupal_set_message(\Drupal::translation()->formatPlural($failures, '1 rollback failed', '@count rollbacks failed')); + drupal_set_message(t('Rollback process not completed'), 'error'); + } + else { + drupal_set_message(t('Rollback of the upgrade is complete - you may now start the upgrade process from scratch.')); + } + + if (\Drupal::moduleHandler()->moduleExists('dblog')) { + $url = Url::fromRoute('migrate_drupal_ui.log'); + drupal_set_message(Link::fromTextAndUrl(new TranslatableMarkup('Review the detailed upgrade log'), $url), $failures ? 'error' : 'status'); + } + } + +} diff --git a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php index 66e7b04..2ece404 100644 --- a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php +++ b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php @@ -14,6 +14,7 @@ use Drupal\migrate\Plugin\MigrationPluginManagerInterface; use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface; use Drupal\migrate_drupal_ui\Batch\MigrateUpgradeImportBatch; +use Drupal\migrate_drupal_ui\Batch\MigrateUpgradeRollbackBatch; use Drupal\migrate_drupal\MigrationConfigurationTrait; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -350,6 +351,7 @@ public function submitOverviewForm(array &$form, FormStateInterface $form_state) case static::MIGRATE_UPGRADE_ROLLBACK: $form_state->setValue('step', 'confirm'); break; + default: $form_state->setValue('step', 'credentials'); break; @@ -763,10 +765,10 @@ public function buildConfirmForm(array $form, FormStateInterface $form_state) { $form['actions']['submit']['#value'] = $this->t('Perform upgrade'); - if ($rollback = $form_state->getValue('upgrade_option') == static::MIGRATE_UPGRADE_ROLLBACK) { + if ($form_state->getValue('upgrade_option') == static::MIGRATE_UPGRADE_ROLLBACK) { $form_state->setStorage(['upgrade_option' => static::MIGRATE_UPGRADE_ROLLBACK]); $form['rollback'] = [ - '#markup' => $this->t('All previously-imported content, as well as configuration such as field definitions, will be removed.') + '#markup' => $this->t('All previously-imported content, as well as configuration such as field definitions, will be removed.'), ]; $form['actions']['submit']['#value'] = $this->t('Perform rollback'); } @@ -964,6 +966,7 @@ public function buildConfirmForm(array $form, FormStateInterface $form_state) { */ public function submitConfirmForm(array &$form, FormStateInterface $form_state) { $storage = $form_state->getStorage(); + $config['source_base_path'] = $storage['source_base_path']; if (isset($storage['upgrade_option']) && $storage['upgrade_option'] == static::MIGRATE_UPGRADE_ROLLBACK) { $migrations = $this->pluginManager->createInstances([]); @@ -988,14 +991,13 @@ public function submitConfirmForm(array &$form, FormStateInterface $form_state) 'progress_message' => '', 'operations' => [ [ - [MigrateUpgradeRunBatch::class, 'run'], - [array_keys($migrations), 'rollback', []], + [MigrateUpgradeRollbackBatch::class, 'run'], + [array_keys($migrations), $config], ], ], 'finished' => [ - MigrateUpgradeRunBatch::class, - 'finished', - ], + MigrateUpgradeRollbackBatch::class, 'finished', + ], ]; batch_set($batch); $form_state->setRedirect('migrate_drupal_ui.upgrade'); @@ -1003,19 +1005,17 @@ public function submitConfirmForm(array &$form, FormStateInterface $form_state) } else { $migrations = $storage['migrations']; - $config['source_base_path'] = $storage['source_base_path']; $batch = [ 'title' => $this->t('Running upgrade'), 'progress_message' => '', 'operations' => [ [ - [MigrateUpgradeRunBatch::class, 'run'], - [array_keys($migrations), 'import', $config], + [MigrateUpgradeImportBatch::class, 'run'], + [array_keys($migrations), $config], ], ], 'finished' => [ - MigrateUpgradeRunBatch::class, - 'finished', + MigrateUpgradeImportBatch::class, 'finished', ], ]; batch_set($batch); @@ -1061,12 +1061,6 @@ public function getCancelUrl() { public function getDescription() { // The description is added by the buildConfirmForm() method. // @see \Drupal\migrate_drupal_ui\Form\MigrateUpgradeForm::buildConfirmForm() - if ($this->state->get('migrate_drupal_ui.performed')) { - return; - } - else { - return $this->t('

Upgrade analysis report

'); - } } /**