diff options
Diffstat (limited to 'core/Command/Db/Migrations')
-rw-r--r-- | core/Command/Db/Migrations/ExecuteCommand.php | 35 | ||||
-rw-r--r-- | core/Command/Db/Migrations/GenerateCommand.php | 77 | ||||
-rw-r--r-- | core/Command/Db/Migrations/GenerateMetadataCommand.php | 79 | ||||
-rw-r--r-- | core/Command/Db/Migrations/MigrateCommand.php | 30 | ||||
-rw-r--r-- | core/Command/Db/Migrations/PreviewCommand.php | 111 | ||||
-rw-r--r-- | core/Command/Db/Migrations/StatusCommand.php | 31 |
6 files changed, 235 insertions, 128 deletions
diff --git a/core/Command/Db/Migrations/ExecuteCommand.php b/core/Command/Db/Migrations/ExecuteCommand.php index e87e133fa31..a89072c1ad1 100644 --- a/core/Command/Db/Migrations/ExecuteCommand.php +++ b/core/Command/Db/Migrations/ExecuteCommand.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com> - * @copyright Copyright (c) 2017, ownCloud GmbH - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2017 ownCloud GmbH + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\Db\Migrations; @@ -35,13 +19,10 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class ExecuteCommand extends Command implements CompletionAwareInterface { - private Connection $connection; - private IConfig $config; - - public function __construct(Connection $connection, IConfig $config) { - $this->connection = $connection; - $this->config = $config; - + public function __construct( + private Connection $connection, + private IConfig $config, + ) { parent::__construct(); } diff --git a/core/Command/Db/Migrations/GenerateCommand.php b/core/Command/Db/Migrations/GenerateCommand.php index aa93adaebb4..a75280fa8b1 100644 --- a/core/Command/Db/Migrations/GenerateCommand.php +++ b/core/Command/Db/Migrations/GenerateCommand.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com> - * @copyright Copyright (c) 2017, ownCloud GmbH - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2017 ownCloud GmbH + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\Db\Migrations; @@ -33,37 +16,21 @@ use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareI use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; class GenerateCommand extends Command implements CompletionAwareInterface { - protected static $_templateSimple = - '<?php + protected static $_templateSimple + = '<?php declare(strict_types=1); /** - * @copyright Copyright (c) {{year}} Your name <your@email.com> - * - * @author Your name <your@email.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: {{year}} Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace {{namespace}}; @@ -72,9 +39,10 @@ use Closure; use OCP\DB\ISchemaWrapper; use OCP\Migration\IOutput; use OCP\Migration\SimpleMigrationStep; +use Override; /** - * Auto-generated migration step: Please modify to your needs! + * FIXME Auto-generated migration step: Please modify to your needs! */ class {{classname}} extends SimpleMigrationStep { @@ -83,6 +51,7 @@ class {{classname}} extends SimpleMigrationStep { * @param Closure(): ISchemaWrapper $schemaClosure * @param array $options */ + #[Override] public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { } @@ -92,6 +61,7 @@ class {{classname}} extends SimpleMigrationStep { * @param array $options * @return null|ISchemaWrapper */ + #[Override] public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { {{schemabody}} } @@ -99,20 +69,18 @@ class {{classname}} extends SimpleMigrationStep { /** * @param IOutput $output * @param Closure(): ISchemaWrapper $schemaClosure -g * @param array $options + * @param array $options */ + #[Override] public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { } } '; - protected Connection $connection; - protected IAppManager $appManager; - - public function __construct(Connection $connection, IAppManager $appManager) { - $this->connection = $connection; - $this->appManager = $appManager; - + public function __construct( + protected Connection $connection, + protected IAppManager $appManager, + ) { parent::__construct(); } @@ -147,7 +115,7 @@ g * @param array $options if ($fullVersion) { [$major, $minor] = explode('.', $fullVersion); - $shouldVersion = (string) ((int)$major * 1000 + (int)$minor); + $shouldVersion = (string)((int)$major * 1000 + (int)$minor); if ($version !== $shouldVersion) { $output->writeln('<comment>Unexpected migration version for current version: ' . $fullVersion . '</comment>'); $output->writeln('<comment> - Pattern: XYYY </comment>'); @@ -155,6 +123,7 @@ g * @param array $options $output->writeln('<comment> - Actual: ' . $version . '</comment>'); if ($input->isInteractive()) { + /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); $question = new ConfirmationQuestion('Continue with your given version? (y/n) [n] ', false); @@ -190,7 +159,7 @@ g * @param array $options */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { - $allApps = \OC_App::getAllApps(); + $allApps = $this->appManager->getAllAppsInAppsFolders(); return array_diff($allApps, \OC_App::getEnabledApps(true, true)); } @@ -235,7 +204,7 @@ g * @param array $options $path = $dir . '/' . $className . '.php'; if (file_put_contents($path, $code) === false) { - throw new RuntimeException('Failed to generate new migration step.'); + throw new RuntimeException('Failed to generate new migration step. Could not write to ' . $path); } return $path; diff --git a/core/Command/Db/Migrations/GenerateMetadataCommand.php b/core/Command/Db/Migrations/GenerateMetadataCommand.php new file mode 100644 index 00000000000..581259c99df --- /dev/null +++ b/core/Command/Db/Migrations/GenerateMetadataCommand.php @@ -0,0 +1,79 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\Core\Command\Db\Migrations; + +use OC\Migration\MetadataManager; +use OCP\App\IAppManager; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @since 30.0.0 + */ +class GenerateMetadataCommand extends Command { + public function __construct( + private readonly MetadataManager $metadataManager, + private readonly IAppManager $appManager, + ) { + parent::__construct(); + } + + protected function configure(): void { + $this->setName('migrations:generate-metadata') + ->setHidden(true) + ->setDescription('Generate metadata from DB migrations - internal and should not be used'); + + parent::configure(); + } + + public function execute(InputInterface $input, OutputInterface $output): int { + $output->writeln( + json_encode( + [ + 'migrations' => $this->extractMigrationMetadata() + ], + JSON_PRETTY_PRINT + ) + ); + + return 0; + } + + private function extractMigrationMetadata(): array { + return [ + 'core' => $this->extractMigrationMetadataFromCore(), + 'apps' => $this->extractMigrationMetadataFromApps() + ]; + } + + private function extractMigrationMetadataFromCore(): array { + return $this->metadataManager->extractMigrationAttributes('core'); + } + + /** + * get all apps and extract attributes + * + * @return array + * @throws \Exception + */ + private function extractMigrationMetadataFromApps(): array { + $allApps = $this->appManager->getAllAppsInAppsFolders(); + $metadata = []; + foreach ($allApps as $appId) { + // We need to load app before being able to extract Migrations + $alreadyLoaded = $this->appManager->isAppLoaded($appId); + if (!$alreadyLoaded) { + $this->appManager->loadApp($appId); + } + $metadata[$appId] = $this->metadataManager->extractMigrationAttributes($appId); + } + return $metadata; + } +} diff --git a/core/Command/Db/Migrations/MigrateCommand.php b/core/Command/Db/Migrations/MigrateCommand.php index f0f35716997..2e02f031479 100644 --- a/core/Command/Db/Migrations/MigrateCommand.php +++ b/core/Command/Db/Migrations/MigrateCommand.php @@ -1,24 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2017, ownCloud GmbH - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2017 ownCloud GmbH + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\Db\Migrations; @@ -33,10 +18,9 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class MigrateCommand extends Command implements CompletionAwareInterface { - private Connection $connection; - - public function __construct(Connection $connection) { - $this->connection = $connection; + public function __construct( + private Connection $connection, + ) { parent::__construct(); } diff --git a/core/Command/Db/Migrations/PreviewCommand.php b/core/Command/Db/Migrations/PreviewCommand.php new file mode 100644 index 00000000000..f5b850fff76 --- /dev/null +++ b/core/Command/Db/Migrations/PreviewCommand.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\Core\Command\Db\Migrations; + +use OC\Migration\MetadataManager; +use OC\Updater\ReleaseMetadata; +use OCP\Migration\Attributes\MigrationAttribute; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Helper\TableCell; +use Symfony\Component\Console\Helper\TableCellStyle; +use Symfony\Component\Console\Helper\TableSeparator; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @since 30.0.0 + */ +class PreviewCommand extends Command { + private bool $initiated = false; + public function __construct( + private readonly MetadataManager $metadataManager, + private readonly ReleaseMetadata $releaseMetadata, + ) { + parent::__construct(); + } + + protected function configure(): void { + $this + ->setName('migrations:preview') + ->setDescription('Get preview of available DB migrations in case of initiating an upgrade') + ->addArgument('version', InputArgument::REQUIRED, 'The destination version number'); + + parent::configure(); + } + + public function execute(InputInterface $input, OutputInterface $output): int { + $version = $input->getArgument('version'); + if (filter_var($version, FILTER_VALIDATE_URL)) { + $metadata = $this->releaseMetadata->downloadMetadata($version); + } elseif (str_starts_with($version, '/')) { + $metadata = json_decode(file_get_contents($version), true, flags: JSON_THROW_ON_ERROR); + } else { + $metadata = $this->releaseMetadata->getMetadata($version); + } + + $parsed = $this->metadataManager->getMigrationsAttributesFromReleaseMetadata($metadata['migrations'] ?? [], true); + + $table = new Table($output); + $this->displayMigrations($table, 'core', $parsed['core'] ?? []); + foreach ($parsed['apps'] as $appId => $migrations) { + if (!empty($migrations)) { + $this->displayMigrations($table, $appId, $migrations); + } + } + $table->render(); + + $unsupportedApps = $this->metadataManager->getUnsupportedApps($metadata['migrations']); + if (!empty($unsupportedApps)) { + $output->writeln(''); + $output->writeln('Those apps are not supporting metadata yet and might initiate migrations on upgrade: <info>' . implode(', ', $unsupportedApps) . '</info>'); + } + + return 0; + } + + private function displayMigrations(Table $table, string $appId, array $data): void { + if (empty($data)) { + return; + } + + if ($this->initiated) { + $table->addRow(new TableSeparator()); + } + $this->initiated = true; + + $table->addRow( + [ + new TableCell( + $appId, + [ + 'colspan' => 2, + 'style' => new TableCellStyle(['cellFormat' => '<info>%s</info>']) + ] + ) + ] + )->addRow(new TableSeparator()); + + /** @var MigrationAttribute[] $attributes */ + foreach ($data as $migration => $attributes) { + $attributesStr = []; + if (empty($attributes)) { + $attributesStr[] = '<comment>(metadata not set)</comment>'; + } + foreach ($attributes as $attribute) { + $definition = '<info>' . $attribute->definition() . '</info>'; + $definition .= empty($attribute->getDescription()) ? '' : "\n " . $attribute->getDescription(); + $definition .= empty($attribute->getNotes()) ? '' : "\n <comment>" . implode("</comment>\n <comment>", $attribute->getNotes()) . '</comment>'; + $attributesStr[] = $definition; + } + $table->addRow([$migration, implode("\n", $attributesStr)]); + } + } +} diff --git a/core/Command/Db/Migrations/StatusCommand.php b/core/Command/Db/Migrations/StatusCommand.php index 725ee075215..97ecc76a924 100644 --- a/core/Command/Db/Migrations/StatusCommand.php +++ b/core/Command/Db/Migrations/StatusCommand.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2017, ownCloud GmbH - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2017 ownCloud GmbH + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\Db\Migrations; @@ -34,10 +18,9 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class StatusCommand extends Command implements CompletionAwareInterface { - private Connection $connection; - - public function __construct(Connection $connection) { - $this->connection = $connection; + public function __construct( + private Connection $connection, + ) { parent::__construct(); } |