addDescription( 'Build SQL files from abstract JSON files' ); $this->addOption( 'json', 'Path to the json file.', true, true ); $this->addOption( 'sql', 'Path to output.', true, true ); $this->addOption( 'type', 'Can be either \'mysql\', \'sqlite\', or \'postgres\'. Default: mysql', false, true ); } public function execute() { global $IP; $jsonPath = $this->getOption( 'json' ); $relativeJsonPath = str_replace( "$IP/", '', $jsonPath ); $sqlPath = $this->getOption( 'sql' ); $abstractSchemaChange = json_decode( file_get_contents( $jsonPath ), true ); if ( $abstractSchemaChange === null ) { $this->fatalError( "'$jsonPath' seems to be invalid json. Check the syntax and try again!" ); } $schemaChangeBuilder = ( new DoctrineSchemaBuilderFactory() )->getSchemaChangeBuilder( $this->getOption( 'type', 'mysql' ) ); $schemaChangeSqls = $schemaChangeBuilder->getSchemaChangeSql( $abstractSchemaChange ); $sql = "-- This file is automatically generated using maintenance/generateSchemaChangeSql.php.\n" . "-- Source: $relativeJsonPath\n" . "-- Do not modify this file directly.\n" . "-- See https://www.mediawiki.org/wiki/Manual:Schema_changes\n"; if ( $schemaChangeSqls !== [] ) { // Temporary $sql .= implode( ";\n\n", $schemaChangeSqls ) . ';'; $sql = ( new SqlFormatter( new NullHighlighter() ) )->format( $sql ); } // Postgres hacks if ( $this->getOption( 'type', 'mysql' ) === 'postgres' ) { // Remove table prefixes from Postgres schema, people should not set it // but better safe than sorry. $sql = str_replace( "\n/*_*/\n", ' ', $sql ); // MySQL goes with varbinary for collation reasons, but postgres can't // properly understand BYTEA type and works just fine with TEXT type // FIXME: This should be fixed at some point (T257755) $sql = str_replace( "BYTEA", 'TEXT', $sql ); } // Until the linting issue is resolved // https://github.com/doctrine/sql-formatter/issues/53 $sql = str_replace( "\n/*_*/\n", " /*_*/", $sql ); $sql = str_replace( "; ", ";\n", $sql ); $sql = preg_replace( "/\n+? +?/", ' ', $sql ); $sql = str_replace( "/*_*/ ", "/*_*/", $sql ); // Sqlite hacks if ( $this->getOption( 'type', 'mysql' ) === 'sqlite' ) { // Doctrine prepends __temp__ to the table name and we set the table with the schema prefix causing invalid // sqlite. $sql = str_replace( '__temp__ /*_*/', '/*_*/__temp__', $sql ); } file_put_contents( $sqlPath, $sql ); } } $maintClass = GenerateSchemaChangeSql::class; require_once RUN_MAINTENANCE_IF_MAIN;