summaryrefslogtreecommitdiffstats
path: root/core/Command
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2017-07-18 13:37:01 +0200
committerJoas Schilling <coding@schilljs.com>2017-07-25 12:45:38 +0200
commitf6c48b1548763e0eda66af7c2720d363e1671090 (patch)
treed3ae4f2a405d08c4e052e7beabb06e3609b7423e /core/Command
parent8d751ff2b429380af7e5c870844a6a32f82f0741 (diff)
downloadnextcloud-server-f6c48b1548763e0eda66af7c2720d363e1671090.tar.gz
nextcloud-server-f6c48b1548763e0eda66af7c2720d363e1671090.zip
Add a script to generate a migration from database.xml
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'core/Command')
-rw-r--r--core/Command/Db/Migrations/GenerateCommand.php18
-rw-r--r--core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php201
2 files changed, 214 insertions, 5 deletions
diff --git a/core/Command/Db/Migrations/GenerateCommand.php b/core/Command/Db/Migrations/GenerateCommand.php
index e6c38d06e5d..f8a992940f9 100644
--- a/core/Command/Db/Migrations/GenerateCommand.php
+++ b/core/Command/Db/Migrations/GenerateCommand.php
@@ -36,7 +36,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class GenerateCommand extends Command {
- private static $_templateSimple =
+ protected static $_templateSimple =
'<?php
namespace <namespace>;
@@ -66,7 +66,7 @@ class <classname> extends SimpleMigrationStep {
* @since 13.0.0
*/
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
- return null;
+<schemabody>
}
/**
@@ -81,7 +81,7 @@ class <classname> extends SimpleMigrationStep {
';
/** @var IDBConnection */
- private $connection;
+ protected $connection;
/**
* @param IDBConnection $connection
@@ -123,16 +123,24 @@ class <classname> extends SimpleMigrationStep {
/**
* @param MigrationService $ms
* @param string $className
+ * @param string $schemaBody
* @return string
*/
- private function generateMigration(MigrationService $ms, $className) {
+ protected function generateMigration(MigrationService $ms, $className, $schemaBody = '') {
+ if ($schemaBody === '') {
+ $schemaBody = "\t\t" . 'return null;';
+ }
+
+
$placeHolders = [
'<namespace>',
'<classname>',
+ '<schemabody>',
];
$replacements = [
$ms->getMigrationsNamespace(),
$className,
+ $schemaBody,
];
$code = str_replace($placeHolders, $replacements, self::$_templateSimple);
$dir = $ms->getMigrationsDirectory();
@@ -147,7 +155,7 @@ class <classname> extends SimpleMigrationStep {
return $path;
}
- private function ensureMigrationDirExists($directory) {
+ protected function ensureMigrationDirExists($directory) {
if (file_exists($directory) && is_dir($directory)) {
return;
}
diff --git a/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php b/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php
new file mode 100644
index 00000000000..38f8d82b961
--- /dev/null
+++ b/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php
@@ -0,0 +1,201 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Haertl <jus@bitgrid.net>
+ *
+ * @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\Command\Db\Migrations;
+
+
+use Doctrine\DBAL\Schema\Schema;
+use OC\DB\MDB2SchemaReader;
+use OC\DB\MigrationService;
+use OC\Migration\ConsoleOutput;
+use OCP\App\IAppManager;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class GenerateFromSchemaFileCommand extends GenerateCommand {
+
+ /** @var IConfig */
+ protected $config;
+
+ /** @var IAppManager */
+ protected $appManager;
+
+ public function __construct(IConfig $config, IAppManager $appManager, IDBConnection $connection) {
+ parent::__construct($connection);
+ $this->config = $config;
+ $this->appManager = $appManager;
+ }
+
+
+ protected function configure() {
+ parent::configure();
+
+ $this->setName('migrations:generate-from-schema');
+ }
+
+ 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;
+ }
+
+ $reader = new MDB2SchemaReader($this->config, $this->connection->getDatabasePlatform());
+ $schema = new Schema();
+ if ($appName === 'core') {
+ $reader->loadSchemaFromFile(\OC::$SERVERROOT . '/db_structure.xml', $schema);
+ } else {
+ if (!file_exists($this->appManager->getAppPath($appName) . '/appinfo/database.xml')) {
+ throw new \RuntimeException('App ' . $appName . ' does not have a database.xml file');
+ }
+ $reader->loadSchemaFromFile($this->appManager->getAppPath($appName) . '/appinfo/database.xml', $schema);
+ }
+
+
+ $schemaBody = $this->schemaToMigration($schema);
+
+ $ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output));
+
+ $date = date('YmdHis');
+ $path = $this->generateMigration($ms, 'Version' . $version . 'Date' . $date, $schemaBody);
+
+ $output->writeln("New migration class has been generated to <info>$path</info>");
+ return 0;
+ }
+
+ /**
+ * @param Schema $schema
+ * @return string
+ */
+ protected function schemaToMigration(Schema $schema) {
+ $content = <<<'EOT'
+ /** @var Schema $schema */
+ $schema = $schemaClosure();
+
+EOT;
+
+ foreach ($schema->getTables() as $table) {
+ $content .= str_replace('{{table-name}}', substr($table->getName(), 3), <<<'EOT'
+
+ if (!$schema->hasTable('{{table-name}}')) {
+ $table = $schema->createTable('{{table-name}}');
+
+EOT
+ );
+
+ foreach ($table->getColumns() as $column) {
+ $content .= str_replace(['{{name}}', '{{type}}'], [$column->getName(), $column->getType()->getName()], <<<'EOT'
+ $table->addColumn('{{name}}', '{{type}}', [
+
+EOT
+ );
+ if ($column->getAutoincrement()) {
+ $content .= <<<'EOT'
+ 'autoincrement' => true,
+
+EOT;
+ }
+ $content .= str_replace('{{notnull}}', $column->getNotnull() ? 'true' : 'false', <<<'EOT'
+ 'notnull' => {{notnull}},
+
+EOT
+ );
+ if ($column->getLength() !== null) {
+ $content .= str_replace('{{length}}', $column->getLength(), <<<'EOT'
+ 'length' => {{length}},
+
+EOT
+ );
+ }
+ $default = $column->getDefault();
+ if ($default !== null) {
+ $default = is_numeric($default) ? $default : "'$default'";
+ $content .= str_replace('{{default}}', $default, <<<'EOT'
+ 'default' => {{default}},
+
+EOT
+ );
+ }
+ $content .= <<<'EOT'
+ ]);
+
+EOT;
+ }
+
+ $content .= <<<'EOT'
+
+EOT;
+
+ $primaryKey = $table->getPrimaryKey();
+ if ($primaryKey !== null) {
+ $content .= str_replace('{{columns}}', implode('\', \'', $primaryKey->getUnquotedColumns()), <<<'EOT'
+ $table->setPrimaryKey(['{{columns}}']);
+
+EOT
+ );
+ }
+
+ foreach ($table->getIndexes() as $index) {
+ if ($index->isPrimary()) {
+ continue;
+ }
+
+ if ($index->isUnique()) {
+ $content .= str_replace(
+ ['{{columns}}', '{{name}}'],
+ [implode('\', \'', $index->getUnquotedColumns()), $index->getName()],
+ <<<'EOT'
+ $table->addUniqueIndex(['{{columns}}'], '{{name}}');
+
+EOT
+ );
+ } else {
+ $content .= str_replace(
+ ['{{columns}}', '{{name}}'],
+ [implode('\', \'', $index->getUnquotedColumns()), $index->getName()],
+ <<<'EOT'
+ $table->addIndex(['{{columns}}'], '{{name}}');
+
+EOT
+ );
+ }
+ }
+
+ $content .= <<<'EOT'
+ }
+
+EOT;
+ }
+
+ $content .= <<<'EOT'
+ return $schema;
+EOT;
+
+ return $content;
+ }
+}