diff options
author | Morris Jobke <hey@morrisjobke.de> | 2017-07-05 17:32:40 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-05 17:32:40 +0200 |
commit | 60398b919be713ddb1813956061fee638c54317a (patch) | |
tree | 483d8f03b2a2b2b11cfebefbf0c3eb3c4b408d8f /core | |
parent | ca565644b36930b63bb996268e848460843f0433 (diff) | |
parent | 163e8774a40bf35a650b41f1af415f89397511a5 (diff) | |
download | nextcloud-server-60398b919be713ddb1813956061fee638c54317a.tar.gz nextcloud-server-60398b919be713ddb1813956061fee638c54317a.zip |
Merge pull request #5231 from nextcloud/migrations
Migrations
Diffstat (limited to 'core')
-rw-r--r-- | core/Command/App/CheckCode.php | 2 | ||||
-rw-r--r-- | core/Command/Db/Migrations/ExecuteCommand.php | 92 | ||||
-rw-r--r-- | core/Command/Db/Migrations/GenerateCommand.php | 148 | ||||
-rw-r--r-- | core/Command/Db/Migrations/MigrateCommand.php | 64 | ||||
-rw-r--r-- | core/Command/Db/Migrations/StatusCommand.php | 115 | ||||
-rw-r--r-- | core/Migrations/Version13000Date20170705121758.php | 93 | ||||
-rw-r--r-- | core/register_command.php | 4 |
7 files changed, 517 insertions, 1 deletions
diff --git a/core/Command/App/CheckCode.php b/core/Command/App/CheckCode.php index 48662409dcf..a7ef9024326 100644 --- a/core/Command/App/CheckCode.php +++ b/core/Command/App/CheckCode.php @@ -97,7 +97,7 @@ class CheckCode extends Command implements CompletionAwareInterface { $checkList = new $checkerClass($checkList); } - $codeChecker = new CodeChecker($checkList); + $codeChecker = new CodeChecker($checkList, !$input->getOption('skip-validate-info')); $codeChecker->listen('CodeChecker', 'analyseFileBegin', function($params) use ($output) { if(OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { diff --git a/core/Command/Db/Migrations/ExecuteCommand.php b/core/Command/Db/Migrations/ExecuteCommand.php new file mode 100644 index 00000000000..0f21bdf28eb --- /dev/null +++ b/core/Command/Db/Migrations/ExecuteCommand.php @@ -0,0 +1,92 @@ +<?php +/** + * @author Joas Schilling <coding@schilljs.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com> + * @copyright Copyright (c) 2017, ownCloud GmbH + * + * @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/> + * + */ + +namespace OC\Core\Command\Db\Migrations; + + +use OC\DB\MigrationService; +use OC\Migration\ConsoleOutput; +use OCP\IConfig; +use OCP\IDBConnection; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class ExecuteCommand extends Command { + + /** @var IDBConnection */ + private $connection; + /** @var IConfig */ + private $config; + + /** + * ExecuteCommand constructor. + * + * @param IDBConnection $connection + * @param IConfig $config + */ + public function __construct(IDBConnection $connection, IConfig $config) { + $this->connection = $connection; + $this->config = $config; + + parent::__construct(); + } + + protected function configure() { + $this + ->setName('migrations:execute') + ->setDescription('Execute a single migration version manually.') + ->addArgument('app', InputArgument::REQUIRED, 'Name of the app this migration command shall work on') + ->addArgument('version', InputArgument::REQUIRED, 'The version to execute.', null); + + parent::configure(); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return int + */ + public function execute(InputInterface $input, OutputInterface $output) { + $appName = $input->getArgument('app'); + $ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output)); + $version = $input->getArgument('version'); + + if ($this->config->getSystemValue('debug', false) === false) { + $olderVersions = $ms->getMigratedVersions(); + $olderVersions[] = '0'; + $olderVersions[] = 'prev'; + if (in_array($version, $olderVersions, true)) { + $output->writeln('<error>Can not go back to previous migration without debug enabled</error>'); + return 1; + } + } + + + $ms->executeStep($version); + return 0; + } + +} diff --git a/core/Command/Db/Migrations/GenerateCommand.php b/core/Command/Db/Migrations/GenerateCommand.php new file mode 100644 index 00000000000..b6e1a17d683 --- /dev/null +++ b/core/Command/Db/Migrations/GenerateCommand.php @@ -0,0 +1,148 @@ +<?php +/** + * @author Joas Schilling <coding@schilljs.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com> + * @copyright Copyright (c) 2017, ownCloud GmbH + * + * @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/> + * + */ + +namespace OC\Core\Command\Db\Migrations; + + +use OC\DB\MigrationService; +use OC\Migration\ConsoleOutput; +use OCP\IDBConnection; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class GenerateCommand extends Command { + + private static $_templateSimple = + '<?php +namespace <namespace>; + +use Doctrine\DBAL\Schema\Schema; +use OCP\Migration\SimpleMigrationStep; +use OCP\Migration\IOutput; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class <classname> extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `Schema` + * @param array $options + * @since 13.0.0 + */ + public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) { + } + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `Schema` + * @param array $options + * @return null|Schema + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + return null; + } + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `Schema` + * @param array $options + * @since 13.0.0 + */ + public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) { + } +} +'; + + /** @var IDBConnection */ + private $connection; + + /** + * @param IDBConnection $connection + */ + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + + parent::__construct(); + } + + protected function configure() { + $this + ->setName('migrations:generate') + ->addArgument('app', InputArgument::REQUIRED, 'Name of the app this migration command shall work on') + ->addArgument('version', InputArgument::REQUIRED, 'Major version of this app, to allow versions on parallel development branches') + ; + + parent::configure(); + } + + public function execute(InputInterface $input, OutputInterface $output) { + $appName = $input->getArgument('app'); + $version = $input->getArgument('version'); + + if (!preg_match('/^\d{1,16}$/',$version)) { + $output->writeln('<error>The given version is invalid. Only 0-9 are allowed (max. 16 digits)</error>'); + return 1; + } + + $ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output)); + + $date = date('YmdHis'); + $path = $this->generateMigration($ms, 'Version' . $version . 'Date' . $date); + + $output->writeln("New migration class has been generated to <info>$path</info>"); + return 0; + } + + /** + * @param MigrationService $ms + * @param string $className + * @return string + */ + private function generateMigration(MigrationService $ms, $className) { + $placeHolders = [ + '<namespace>', + '<classname>', + ]; + $replacements = [ + $ms->getMigrationsNamespace(), + $className, + ]; + $code = str_replace($placeHolders, $replacements, self::$_templateSimple); + $dir = $ms->getMigrationsDirectory(); + $path = $dir . '/' . $className . '.php'; + + if (file_put_contents($path, $code) === false) { + throw new RuntimeException('Failed to generate new migration step.'); + } + + return $path; + } + +} diff --git a/core/Command/Db/Migrations/MigrateCommand.php b/core/Command/Db/Migrations/MigrateCommand.php new file mode 100644 index 00000000000..2b0e082acaa --- /dev/null +++ b/core/Command/Db/Migrations/MigrateCommand.php @@ -0,0 +1,64 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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/> + * + */ + +namespace OC\Core\Command\Db\Migrations; + + +use OC\DB\MigrationService; +use OC\Migration\ConsoleOutput; +use OCP\IDBConnection; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class MigrateCommand extends Command { + + /** @var IDBConnection */ + private $connection; + + /** + * @param IDBConnection $connection + */ + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + parent::__construct(); + } + + protected function configure() { + $this + ->setName('migrations:migrate') + ->setDescription('Execute a migration to a specified version or the latest available version.') + ->addArgument('app', InputArgument::REQUIRED, 'Name of the app this migration command shall work on') + ->addArgument('version', InputArgument::OPTIONAL, 'The version number (YYYYMMDDHHMMSS) or alias (first, prev, next, latest) to migrate to.', 'latest'); + + parent::configure(); + } + + public function execute(InputInterface $input, OutputInterface $output) { + $appName = $input->getArgument('app'); + $ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output)); + $version = $input->getArgument('version'); + + $ms->migrate($version); + } + +} diff --git a/core/Command/Db/Migrations/StatusCommand.php b/core/Command/Db/Migrations/StatusCommand.php new file mode 100644 index 00000000000..20172000ee3 --- /dev/null +++ b/core/Command/Db/Migrations/StatusCommand.php @@ -0,0 +1,115 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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/> + * + */ + +namespace OC\Core\Command\Db\Migrations; + +use OC\DB\MigrationService; +use OC\Migration\ConsoleOutput; +use OCP\IDBConnection; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class StatusCommand extends Command { + + /** @var IDBConnection */ + private $connection; + + /** + * @param IDBConnection $connection + */ + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + parent::__construct(); + } + + protected function configure() { + $this + ->setName('migrations:status') + ->setDescription('View the status of a set of migrations.') + ->addArgument('app', InputArgument::REQUIRED, 'Name of the app this migration command shall work on'); + } + + public function execute(InputInterface $input, OutputInterface $output) { + $appName = $input->getArgument('app'); + $ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output)); + + $infos = $this->getMigrationsInfos($ms); + foreach ($infos as $key => $value) { + $output->writeln(" <comment>>></comment> $key: " . str_repeat(' ', 50 - strlen($key)) . $value); + } + } + + /** + * @param MigrationService $ms + * @return array associative array of human readable info name as key and the actual information as value + */ + public function getMigrationsInfos(MigrationService $ms) { + + $executedMigrations = $ms->getMigratedVersions(); + $availableMigrations = $ms->getAvailableVersions(); + $executedUnavailableMigrations = array_diff($executedMigrations, array_keys($availableMigrations)); + + $numExecutedUnavailableMigrations = count($executedUnavailableMigrations); + $numNewMigrations = count(array_diff(array_keys($availableMigrations), $executedMigrations)); + + $infos = [ + 'App' => $ms->getApp(), + 'Version Table Name' => $ms->getMigrationsTableName(), + 'Migrations Namespace' => $ms->getMigrationsNamespace(), + 'Migrations Directory' => $ms->getMigrationsDirectory(), + 'Previous Version' => $this->getFormattedVersionAlias($ms, 'prev'), + 'Current Version' => $this->getFormattedVersionAlias($ms, 'current'), + 'Next Version' => $this->getFormattedVersionAlias($ms, 'next'), + 'Latest Version' => $this->getFormattedVersionAlias($ms, 'latest'), + 'Executed Migrations' => count($executedMigrations), + 'Executed Unavailable Migrations' => $numExecutedUnavailableMigrations, + 'Available Migrations' => count($availableMigrations), + 'New Migrations' => $numNewMigrations, + ]; + + return $infos; + } + + /** + * @param MigrationService $migrationService + * @param string $alias + * @return mixed|null|string + */ + private function getFormattedVersionAlias(MigrationService $migrationService, $alias) { + $migration = $migrationService->getMigration($alias); + //No version found + if ($migration === null) { + if ($alias === 'next') { + return 'Already at latest migration step'; + } + + if ($alias === 'prev') { + return 'Already at first migration step'; + } + } + + return $migration; + } + + +} diff --git a/core/Migrations/Version13000Date20170705121758.php b/core/Migrations/Version13000Date20170705121758.php new file mode 100644 index 00000000000..6f9c2d243f8 --- /dev/null +++ b/core/Migrations/Version13000Date20170705121758.php @@ -0,0 +1,93 @@ +<?php +/** + * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.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/>. + * + */ + +namespace OC\Core\Migrations; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Types\Type; +use OCP\Migration\SimpleMigrationStep; +use OCP\Migration\IOutput; + +class Version13000Date20170705121758 extends SimpleMigrationStep { + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `Schema` + * @param array $options + * @return null|Schema + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var Schema $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('personal_sections')) { + $table = $schema->createTable('personal_sections'); + + $table->addColumn('id', Type::STRING, [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('class', Type::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('priority', Type::INTEGER, [ + 'notnull' => true, + 'length' => 6, + 'default' => 0, + ]); + + $table->setPrimaryKey(['id'], 'personal_sections_id_index'); + $table->addUniqueIndex(['class'], 'personal_sections_class'); + } + + if (!$schema->hasTable('personal_settings')) { + $table = $schema->createTable('personal_settings'); + + $table->addColumn('id', Type::INTEGER, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 20, + ]); + $table->addColumn('class', Type::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('section', Type::STRING, [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('priority', Type::INTEGER, [ + 'notnull' => true, + 'length' => 6, + 'default' => 0, + ]); + + $table->setPrimaryKey(['id'], 'personal_settings_id_index'); + $table->addUniqueIndex(['class'], 'personal_settings_class'); + $table->addIndex(['section'], 'personal_settings_section'); + } + + return $schema; + } +} diff --git a/core/register_command.php b/core/register_command.php index 59fc65edbc8..bfb1138c5e3 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -85,6 +85,10 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) { $application->add(new OC\Core\Command\Db\GenerateChangeScript()); $application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig()))); $application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->getLogger())); + $application->add(new OC\Core\Command\Db\Migrations\StatusCommand(\OC::$server->getDatabaseConnection())); + $application->add(new OC\Core\Command\Db\Migrations\MigrateCommand(\OC::$server->getDatabaseConnection())); + $application->add(new OC\Core\Command\Db\Migrations\GenerateCommand(\OC::$server->getDatabaseConnection())); + $application->add(new OC\Core\Command\Db\Migrations\ExecuteCommand(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig())); $application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig())); $application->add(new OC\Core\Command\Encryption\Enable(\OC::$server->getConfig(), \OC::$server->getEncryptionManager())); |