setName('kaliop:migration:migration') ->setDescription('Manually modify or get info about migrations in the database table.') ->addOption('delete', null, InputOption::VALUE_NONE, "Delete the specified migration.") ->addOption('info', null, InputOption::VALUE_NONE, "Get info about the specified migration.") ->addOption('add', null, InputOption::VALUE_NONE, "Add the specified migration definition.") ->addOption('skip', null, InputOption::VALUE_NONE, "Mark the specified migration as skipped.") ->addOption('no-interaction', 'n', InputOption::VALUE_NONE, "Do not ask any interactive question.") ->addArgument('migration', InputArgument::REQUIRED, 'The migration to add/skip (filename with full path) or detail/delete (plain migration name).', null) ->setHelp(<<kaliop:migration:migration command allows you to manually delete migrations versions from the migration table: ./ezpublish/console kaliop:migration:migration --delete migration_name As well as manually adding migrations to the migration table: ./ezpublish/console kaliop:migration:migration --add /path/to/migration_definition EOT ); } /** * Execute the command. * * @param InputInterface $input * @param OutputInterface $output * @return null|int null or 0 if everything went fine, or an error code */ protected function execute(InputInterface $input, OutputInterface $output) { $this->setOutput($output); $this->setVerbosity($output->getVerbosity()); if (!$input->getOption('add') && !$input->getOption('delete') && !$input->getOption('skip') && !$input->getOption('info')) { throw new \InvalidArgumentException('You must specify whether you want to --add, --delete, --skip or --info the specified migration.'); } $migrationService = $this->getMigrationService(); $migrationNameOrPath = $input->getArgument('migration'); if ($input->getOption('info')) { $output->writeln(''); $migration = $migrationService->getMigration($migrationNameOrPath); if ($migration == null) { throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table.', $migrationNameOrPath)); } switch ($migration->status) { case Migration::STATUS_DONE: $status = 'executed'; break; case Migration::STATUS_STARTED: $status = 'execution started'; break; case Migration::STATUS_TODO: // bold to-migrate! $status = 'not executed'; break; case Migration::STATUS_SKIPPED: $status = 'skipped'; break; case Migration::STATUS_PARTIALLY_DONE: $status = 'partially executed'; break; case Migration::STATUS_SUSPENDED: $status = 'suspended'; break; case Migration::STATUS_FAILED: $status = 'failed'; break; } $output->writeln('Migration: ' . $migration->name . ''); $output->writeln('Status: ' . $status); $output->writeln('Executed on: ' . ($migration->executionDate != null ? date("Y-m-d H:i:s", $migration->executionDate) : '--'). ''); $output->writeln('Execution notes: ' . $migration->executionError . ''); if ($migration->status == Migration::STATUS_SUSPENDED) { /// @todo decode the suspension context: date, step, ... } $output->writeln('Definition path: ' . $migration->path . ''); $output->writeln('Definition md5: ' . $migration->md5 . ''); if ($migration->path != '') { // q: what if we have a loader which does not work with is_file? We could probably remove this check... if (is_file($migration->path)) { try { $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migration->path)); if (count($migrationDefinitionCollection)) { $migrationDefinition = reset($migrationDefinitionCollection); $migrationDefinition = $migrationService->parseMigrationDefinition($migrationDefinition); if ($migrationDefinition->status != MigrationDefinition::STATUS_PARSED) { $output->writeln('Definition error: ' . $migrationDefinition->parsingError . ''); } if (md5($migrationDefinition->rawDefinition) != $migration->md5) { $output->writeln('Notes: The migration definition file has now a different checksum'); } } else { $output->writeln('Definition error: The migration definition file can not be loaded'); } } catch (\Exception $e) { /// @todo one day we should be able to limit the kind of exceptions we have to catch here... $output->writeln('Definition parsing error: ' . $e->getMessage() . ''); } } else { $output->writeln('Definition error: The migration definition file can not be found any more'); } } $output->writeln(''); return 0; } // ask user for confirmation to make changes if ($input->isInteractive() && !$input->getOption('no-interaction')) { $dialog = $this->getHelperSet()->get('question'); if (!$dialog->ask( $input, $output, new ConfirmationQuestion('Careful, the database will be modified. Do you want to continue Y/N ?', false) ) ) { $output->writeln('Migration change cancelled!'); return 0; } } if ($input->getOption('add')) { // will throw if a file is passed and it is not found, but not if an empty dir is passed $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migrationNameOrPath)); if (!count($migrationDefinitionCollection)) { throw new \InvalidArgumentException(sprintf('The path "%s" does not correspond to any migration definition.', $migrationNameOrPath)); } foreach ($migrationDefinitionCollection as $migrationDefinition) { $migrationName = basename($migrationDefinition->path); $migration = $migrationService->getMigration($migrationNameOrPath); if ($migration != null) { throw new \InvalidArgumentException(sprintf('The migration "%s" does already exist in the migrations table.', $migrationName)); } $migrationService->addMigration($migrationDefinition); $output->writeln('Added migration' . $migrationDefinition->path . ''); } return 0; } if ($input->getOption('delete')) { $migration = $migrationService->getMigration($migrationNameOrPath); if ($migration == null) { throw new \InvalidArgumentException(sprintf('The migration "%s" does not exist in the migrations table.', $migrationNameOrPath)); } $migrationService->deleteMigration($migration); return 0; } if ($input->getOption('skip')) { // will throw if a file is passed and it is not found, but not if an empty dir is passed $migrationDefinitionCollection = $migrationService->getMigrationsDefinitions(array($migrationNameOrPath)); if (!count($migrationDefinitionCollection)) { throw new \InvalidArgumentException(sprintf('The path "%s" does not correspond to any migration definition.', $migrationNameOrPath)); } foreach ($migrationDefinitionCollection as $migrationDefinition) { $migrationService->skipMigration($migrationDefinition); $output->writeln('Migration' . $migrationDefinition->path . ' marked as skipped'); } return 0; } throw new \InvalidArgumentException("Please specify one action to be taken on the given migration"); } }