Add a new type of database to the installer from extension
Decouple Installer services Implement injection class Autoloader and i18n messages from extension.json Implement extension selector by type Add i18n message key `version-database` Extensions for testing: - https://github.com/MWStake/PerconaDB - real Percona extension - https://github.com/killev/mediawiki-dbext2 - fake extension for test Bug: T226857, T255151 Change-Id: I9ec8a18ad19283f6be67ac000110ac370afc0815
This commit is contained in:
parent
52f1bfa61b
commit
46eabe275c
17 changed files with 629 additions and 87 deletions
|
|
@ -237,6 +237,8 @@ For notes on 1.34.x and older releases, see HISTORY.
|
||||||
Doing so using that hook is now soft deprecated.
|
Doing so using that hook is now soft deprecated.
|
||||||
* A new BlockPermissionChecker service was introduced for checking
|
* A new BlockPermissionChecker service was introduced for checking
|
||||||
block-related permissions.
|
block-related permissions.
|
||||||
|
* The support of 'database' type of extensions has been added to allow 3d party
|
||||||
|
databases like Percona be used as storage. See T226857, T253248.
|
||||||
* …
|
* …
|
||||||
|
|
||||||
=== External library changes in 1.35 ===
|
=== External library changes in 1.35 ===
|
||||||
|
|
@ -1243,6 +1245,8 @@ because of Phabricator reports.
|
||||||
instead.
|
instead.
|
||||||
* Using Skin::addToBodyAttributes() method to add body attributes has been
|
* Using Skin::addToBodyAttributes() method to add body attributes has been
|
||||||
deprecated. Use OutputPageBodyAttributes hook instead.
|
deprecated. Use OutputPageBodyAttributes hook instead.
|
||||||
|
* Installer::getDBTypes has been hard deprecated in favor of
|
||||||
|
InstallerDBSupport::getDatabases
|
||||||
* …
|
* …
|
||||||
|
|
||||||
=== Other changes in 1.35 ===
|
=== Other changes in 1.35 ===
|
||||||
|
|
|
||||||
|
|
@ -820,6 +820,29 @@ class LocalisationCache {
|
||||||
return $used;
|
return $used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $messagesDirs = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $additionalMessagesDirs = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add additional path for looking for i18n localization messages
|
||||||
|
*
|
||||||
|
* @internal for Installer with DbType extensions
|
||||||
|
* @since 1.35
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
public function addMessagesDir( string $name, string $path ) : void {
|
||||||
|
$this->additionalMessagesDirs[$name] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the combined list of messages dirs from
|
* Gets the combined list of messages dirs from
|
||||||
* core and extensions
|
* core and extensions
|
||||||
|
|
@ -837,7 +860,7 @@ class LocalisationCache {
|
||||||
'rest' => "$IP/includes/Rest/i18n",
|
'rest' => "$IP/includes/Rest/i18n",
|
||||||
'oojs-ui' => "$IP/resources/lib/ooui/i18n",
|
'oojs-ui' => "$IP/resources/lib/ooui/i18n",
|
||||||
'paramvalidator' => "$IP/includes/libs/ParamValidator/i18n",
|
'paramvalidator' => "$IP/includes/libs/ParamValidator/i18n",
|
||||||
] + $this->options->get( 'MessagesDirs' );
|
] + $this->options->get( 'MessagesDirs' ) + $this->additionalMessagesDirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
* @file
|
* @file
|
||||||
* @ingroup Installer
|
* @ingroup Installer
|
||||||
*/
|
*/
|
||||||
|
use MediaWiki\Installer\Services\InstallerDBSupport;
|
||||||
use MediaWiki\MediaWikiServices;
|
use MediaWiki\MediaWikiServices;
|
||||||
use Wikimedia\Rdbms\IDatabase;
|
use Wikimedia\Rdbms\IDatabase;
|
||||||
use Wikimedia\Rdbms\IMaintainableDatabase;
|
use Wikimedia\Rdbms\IMaintainableDatabase;
|
||||||
|
|
@ -195,8 +196,8 @@ abstract class DatabaseUpdater {
|
||||||
Maintenance $maintenance = null
|
Maintenance $maintenance = null
|
||||||
) {
|
) {
|
||||||
$type = $db->getType();
|
$type = $db->getType();
|
||||||
if ( in_array( $type, Installer::getDBTypes() ) ) {
|
if ( InstallerDBSupport::getInstance()->hasDatabase( $type ) ) {
|
||||||
$class = ucfirst( $type ) . 'Updater';
|
$class = InstallerDBSupport::getInstance()->getDBUpdaterClass( $type );
|
||||||
|
|
||||||
return new $class( $db, $shared, $maintenance );
|
return new $class( $db, $shared, $maintenance );
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
* @ingroup Installer
|
* @ingroup Installer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use MediaWiki\Installer\Services\InstallerDBSupport;
|
||||||
use MediaWiki\Interwiki\NullInterwikiLookup;
|
use MediaWiki\Interwiki\NullInterwikiLookup;
|
||||||
use MediaWiki\MediaWikiServices;
|
use MediaWiki\MediaWikiServices;
|
||||||
use MediaWiki\Shell\Shell;
|
use MediaWiki\Shell\Shell;
|
||||||
|
|
@ -100,19 +101,9 @@ abstract class Installer {
|
||||||
protected $parserOptions;
|
protected $parserOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Known database types. These correspond to the class names <type>Installer,
|
* @var InstallerDBSupport
|
||||||
* and are also MediaWiki database types valid for $wgDBtype.
|
|
||||||
*
|
|
||||||
* To add a new type, create a <type>Installer class and a Database<type>
|
|
||||||
* class, and add a config-type-<type> message to MessagesEn.php.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
protected static $dbTypes = [
|
protected $installerDbSupport;
|
||||||
'mysql',
|
|
||||||
'postgres',
|
|
||||||
'sqlite',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of environment check methods called by doEnvironmentChecks().
|
* A list of environment check methods called by doEnvironmentChecks().
|
||||||
|
|
@ -406,7 +397,6 @@ abstract class Installer {
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
global $wgMemc, $wgUser, $wgObjectCaches;
|
global $wgMemc, $wgUser, $wgObjectCaches;
|
||||||
|
|
||||||
$defaultConfig = new GlobalVarConfig(); // all the stuff from DefaultSettings.php
|
$defaultConfig = new GlobalVarConfig(); // all the stuff from DefaultSettings.php
|
||||||
$installerConfig = self::getInstallerConfig( $defaultConfig );
|
$installerConfig = self::getInstallerConfig( $defaultConfig );
|
||||||
|
|
||||||
|
|
@ -458,7 +448,9 @@ abstract class Installer {
|
||||||
$this->doEnvironmentPreps();
|
$this->doEnvironmentPreps();
|
||||||
|
|
||||||
$this->compiledDBs = [];
|
$this->compiledDBs = [];
|
||||||
foreach ( self::getDBTypes() as $type ) {
|
$this->installerDbSupport = InstallerDBSupport::getInstance();
|
||||||
|
|
||||||
|
foreach ( $this->installerDbSupport->getDatabases() as $type ) {
|
||||||
$installer = $this->getDBInstaller( $type );
|
$installer = $this->getDBInstaller( $type );
|
||||||
|
|
||||||
if ( !$installer->isCompiled() ) {
|
if ( !$installer->isCompiled() ) {
|
||||||
|
|
@ -475,11 +467,13 @@ abstract class Installer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of known DB types.
|
* Get a list of known DB types.
|
||||||
|
* @deprecated since 1.35 use InstallerDBSupport::getDatabases instead
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function getDBTypes() {
|
public static function getDBTypes() {
|
||||||
return self::$dbTypes;
|
wfDeprecated( __METHOD__, '1.35' );
|
||||||
|
return InstallerDBSupport::getInstance()->getDatabases();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -561,13 +555,16 @@ abstract class Installer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the DatabaseInstaller class name for this type
|
* Get the DatabaseInstaller class name for this type
|
||||||
|
* @deprecated since 1.35 use InstallerDBSupport instead
|
||||||
*
|
*
|
||||||
* @param string $type database type ($wgDBtype)
|
* @param string $type database type ($wgDBtype)
|
||||||
* @return string Class name
|
* @return string Class name
|
||||||
* @since 1.30
|
* @since 1.30
|
||||||
*/
|
*/
|
||||||
public static function getDBInstallerClass( $type ) {
|
public static function getDBInstallerClass( $type ) {
|
||||||
return ucfirst( $type ) . 'Installer';
|
wfDeprecated( __METHOD__, '1.35' );
|
||||||
|
|
||||||
|
return InstallerDBSupport::getInstance()->getDBInstallerClass( $type );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -582,10 +579,8 @@ abstract class Installer {
|
||||||
$type = $this->getVar( 'wgDBtype' );
|
$type = $this->getVar( 'wgDBtype' );
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = strtolower( $type );
|
|
||||||
|
|
||||||
if ( !isset( $this->dbInstallers[$type] ) ) {
|
if ( !isset( $this->dbInstallers[$type] ) ) {
|
||||||
$class = self::getDBInstallerClass( $type );
|
$class = $this->installerDbSupport->getDBInstallerClass( $type );
|
||||||
$this->dbInstallers[$type] = new $class( $this );
|
$this->dbInstallers[$type] = new $class( $this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -769,7 +764,7 @@ abstract class Installer {
|
||||||
$allNames = [];
|
$allNames = [];
|
||||||
|
|
||||||
// Messages: config-type-mysql, config-type-postgres, config-type-sqlite
|
// Messages: config-type-mysql, config-type-postgres, config-type-sqlite
|
||||||
foreach ( self::getDBTypes() as $name ) {
|
foreach ( $this->installerDbSupport->getDatabases() as $name ) {
|
||||||
$allNames[] = wfMessage( "config-type-$name" )->text();
|
$allNames[] = wfMessage( "config-type-$name" )->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
336
includes/installer/Services/InstallerDBSupport.php
Normal file
336
includes/installer/Services/InstallerDBSupport.php
Normal file
|
|
@ -0,0 +1,336 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @ingroup Installer
|
||||||
|
*
|
||||||
|
* @author Art Baltai
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare( strict_types = 1 );
|
||||||
|
namespace MediaWiki\Installer\Services;
|
||||||
|
|
||||||
|
use DatabaseInstaller;
|
||||||
|
use DatabaseUpdater;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use MediaWiki\Logger\LoggerFactory;
|
||||||
|
use MediaWiki\MediaWikiServices;
|
||||||
|
use MysqlInstaller;
|
||||||
|
use MysqlUpdater;
|
||||||
|
use PostgresInstaller;
|
||||||
|
use PostgresUpdater;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use SqliteInstaller;
|
||||||
|
use SqliteUpdater;
|
||||||
|
use Wikimedia\Rdbms\Database;
|
||||||
|
use Wikimedia\Rdbms\DatabaseMysqli;
|
||||||
|
use Wikimedia\Rdbms\DatabasePostgres;
|
||||||
|
use Wikimedia\Rdbms\DatabaseSqlite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.35
|
||||||
|
*/
|
||||||
|
class InstallerDBSupport {
|
||||||
|
public const EXTENSION_TYPE_DATABASE = 'database';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var InstallerDBSupport $instance
|
||||||
|
*/
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Known database types. These correspond to the class names <type>Installer,
|
||||||
|
* and are also MediaWiki database types valid for $wgDBtype.
|
||||||
|
*
|
||||||
|
* To add a new type, create a <type>Installer class and a Database<type>
|
||||||
|
* class, and add a config-type-<type> message to MessagesEn.php.
|
||||||
|
*
|
||||||
|
* @var array<string, array>
|
||||||
|
*/
|
||||||
|
private $databaseInfo = [
|
||||||
|
'mysql' => [
|
||||||
|
'installer' => MysqlInstaller::class,
|
||||||
|
'updater' => MysqlUpdater::class,
|
||||||
|
'driver' => DatabaseMysqli::class,
|
||||||
|
'extension' => 'core'
|
||||||
|
],
|
||||||
|
'postgres' => [
|
||||||
|
'installer' => PostgresInstaller::class,
|
||||||
|
'updater' => PostgresUpdater::class,
|
||||||
|
'driver' => DatabasePostgres::class,
|
||||||
|
'extension' => 'core'
|
||||||
|
],
|
||||||
|
'sqlite' => [
|
||||||
|
'installer' => SqliteInstaller::class,
|
||||||
|
'updater' => SqliteUpdater::class,
|
||||||
|
'driver' => DatabaseSqlite::class,
|
||||||
|
'extension' => 'core'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var InstallerExtensionRegistration
|
||||||
|
*/
|
||||||
|
private $extensionRegistration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
public static function getInstance(): self {
|
||||||
|
global $IP, $wgExtensionDirectory;
|
||||||
|
if ( !isset( self::$instance ) ) {
|
||||||
|
$extensionDir = $wgExtensionDirectory ?: "$IP/extensions";
|
||||||
|
$installerRegistration = new InstallerExtensionRegistration(
|
||||||
|
$extensionDir,
|
||||||
|
MediaWikiServices::getInstance()->getLocalisationCache()
|
||||||
|
);
|
||||||
|
self::$instance = new InstallerDBSupport(
|
||||||
|
$installerRegistration,
|
||||||
|
LoggerFactory::getInstance( 'Installer' )
|
||||||
|
);
|
||||||
|
self::$instance->registerDbExtensions(
|
||||||
|
( new InstallerExtensionSelector( $extensionDir ) )
|
||||||
|
->getExtOptionsByType( self::EXTENSION_TYPE_DATABASE )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function __construct(
|
||||||
|
InstallerExtensionRegistration $extensionRegistration,
|
||||||
|
LoggerInterface $logger
|
||||||
|
) {
|
||||||
|
$this->extensionRegistration = $extensionRegistration;
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerDbExtensions( iterable $extDbOptionsByType ): bool {
|
||||||
|
$registered = false;
|
||||||
|
foreach ( $extDbOptionsByType as $extensionName => $extDbOptions ) {
|
||||||
|
$result = $this->registerDbExtension(
|
||||||
|
$extensionName,
|
||||||
|
$extDbOptions
|
||||||
|
);
|
||||||
|
$registered = $result || $registered;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $registered;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerDbExtension(
|
||||||
|
string $extensionName,
|
||||||
|
array $extJsonOptions
|
||||||
|
): bool {
|
||||||
|
if ( !isset( $extJsonOptions['Providers']['Databases'] ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$newDatabases = $extJsonOptions['Providers']['Databases'];
|
||||||
|
$isRegistred = false;
|
||||||
|
foreach ( $newDatabases as $database => $options ) {
|
||||||
|
if ( is_numeric( $database ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( $isRegistred === false ) {
|
||||||
|
$this->extensionRegistration->register(
|
||||||
|
$extensionName,
|
||||||
|
$extJsonOptions
|
||||||
|
);
|
||||||
|
$isRegistred = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->registerDatabase(
|
||||||
|
$database,
|
||||||
|
$options['Installer'] ?? $this->getInstallerClassAuto( $database ),
|
||||||
|
$options['Updater'] ?? $this->getUpdaterClassAuto( $database ),
|
||||||
|
$options['Driver'] ?? $this->getDriverClassAuto( $database ),
|
||||||
|
$extensionName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isRegistred;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isDatabaseInfoValid(
|
||||||
|
string $dbInstaller,
|
||||||
|
string $dbUpdater,
|
||||||
|
string $dbDriver
|
||||||
|
): bool {
|
||||||
|
$isValid = true;
|
||||||
|
if ( !is_subclass_of( $dbInstaller, DatabaseInstaller::class ) ) {
|
||||||
|
$this->logger->warning( 'Database `Installer` should be a subclass of '
|
||||||
|
. DatabaseInstaller::class );
|
||||||
|
$isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !is_subclass_of( $dbUpdater, DatabaseUpdater::class ) ) {
|
||||||
|
$this->logger->warning( 'Database `Updater` should be a subclass of '
|
||||||
|
. DatabaseUpdater::class );
|
||||||
|
$isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !is_subclass_of( $dbDriver, Database::class ) ) {
|
||||||
|
$this->logger->warning( 'Database `Driver` should be a subclass of ' . Database::class );
|
||||||
|
$isValid = false;
|
||||||
|
}
|
||||||
|
return $isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $database
|
||||||
|
* @param string $dbInstaller
|
||||||
|
* @param string $dbUpdater
|
||||||
|
* @param string $dbDriver
|
||||||
|
* @param string $extensionName
|
||||||
|
*/
|
||||||
|
private function registerDatabase(
|
||||||
|
string $database,
|
||||||
|
string $dbInstaller,
|
||||||
|
string $dbUpdater,
|
||||||
|
string $dbDriver,
|
||||||
|
string $extensionName
|
||||||
|
): void {
|
||||||
|
if ( !$this->isDatabaseInfoValid( $dbInstaller, $dbUpdater, $dbDriver ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->databaseInfo[ strtolower( $database ) ] = [
|
||||||
|
'installer' => $dbInstaller,
|
||||||
|
'updater' => $dbUpdater,
|
||||||
|
'driver' => $dbDriver,
|
||||||
|
'extension' => $extensionName,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of known DB types.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getDatabases(): array {
|
||||||
|
return array_keys( $this->databaseInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks wheather given database type is registered
|
||||||
|
* @param string $database
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasDatabase( string $database ): bool {
|
||||||
|
return array_key_exists( $database, $this->databaseInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the database installer class for given database type, throws an
|
||||||
|
* InvalidArgumentException if no given database registerred
|
||||||
|
*
|
||||||
|
* @param string $database
|
||||||
|
* @return string Class name
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function getDBInstallerClass( string $database ): string {
|
||||||
|
if ( !isset( $this->databaseInfo[strtolower( $database )] ) ) {
|
||||||
|
throw new InvalidArgumentException( __METHOD__ .
|
||||||
|
" no registered database found for type '$database'" );
|
||||||
|
}
|
||||||
|
return $this->databaseInfo[strtolower( $database )]['installer'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the database updater class for given database type, throws an
|
||||||
|
* InvalidArgumentException if no given database registerred
|
||||||
|
*
|
||||||
|
* @param string $database
|
||||||
|
* @return string class name
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function getDBUpdaterClass( string $database ): string {
|
||||||
|
if ( !isset( $this->databaseInfo[strtolower( $database )] ) ) {
|
||||||
|
throw new InvalidArgumentException( __METHOD__ .
|
||||||
|
" no registered database found for type '$database'" );
|
||||||
|
}
|
||||||
|
return $this->databaseInfo[strtolower( $database )]['updater'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the database driver class for given database type, throws an
|
||||||
|
* InvalidArgumentException if no given database registerred
|
||||||
|
*
|
||||||
|
* @param string $database
|
||||||
|
* @return string class name
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function getDBDriverClass( string $database ): string {
|
||||||
|
if ( !isset( $this->databaseInfo[strtolower( $database )] ) ) {
|
||||||
|
throw new InvalidArgumentException( __METHOD__ .
|
||||||
|
" no registered database found for type '$database'" );
|
||||||
|
}
|
||||||
|
return $this->databaseInfo[strtolower( $database )]['driver'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets extension name that implements classes for given database type, throws an
|
||||||
|
* InvalidArgumentException if no given database registerred
|
||||||
|
*
|
||||||
|
* @param string $database
|
||||||
|
* @return string|null
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function getExtensionNameForDatabase(
|
||||||
|
string $database
|
||||||
|
): string {
|
||||||
|
if ( !isset( $this->databaseInfo[strtolower( $database )] ) ) {
|
||||||
|
throw new InvalidArgumentException( __METHOD__ .
|
||||||
|
" no registered database found for type '$database'" );
|
||||||
|
}
|
||||||
|
return $this->databaseInfo[strtolower( $database )]['extension'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate default name for database Installer
|
||||||
|
*
|
||||||
|
* @param string $type database type ($wgDBtype)
|
||||||
|
* @return string Class name
|
||||||
|
*/
|
||||||
|
private function getInstallerClassAuto( string $type ): string {
|
||||||
|
return ucfirst( $type ) . 'Installer';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate default name for database Updater
|
||||||
|
*
|
||||||
|
* @param string $type database type ($wgDBtype)
|
||||||
|
* @return string Class name
|
||||||
|
*/
|
||||||
|
private function getUpdaterClassAuto( string $type ): string {
|
||||||
|
return ucfirst( $type ) . 'Updater';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate default name for database Driver
|
||||||
|
*
|
||||||
|
* @param string $type database type ($wgDBtype)
|
||||||
|
* @return string Class name
|
||||||
|
*/
|
||||||
|
private function getDriverClassAuto( string $type ): string {
|
||||||
|
return 'Database' . ucfirst( $type );
|
||||||
|
}
|
||||||
|
}
|
||||||
110
includes/installer/Services/InstallerExtensionRegistration.php
Normal file
110
includes/installer/Services/InstallerExtensionRegistration.php
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @ingroup Installer
|
||||||
|
*
|
||||||
|
* @author Art Baltai
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare( strict_types = 1 );
|
||||||
|
namespace MediaWiki\Installer\Services;
|
||||||
|
|
||||||
|
use ExtensionRegistry;
|
||||||
|
use LocalisationCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.35
|
||||||
|
*/
|
||||||
|
class InstallerExtensionRegistration {
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $extensionDir;
|
||||||
|
|
||||||
|
/** @var LocalisationCache */
|
||||||
|
private $localisationCache;
|
||||||
|
|
||||||
|
public function __construct( string $extensionDir, LocalisationCache $localisationCache ) {
|
||||||
|
$this->extensionDir = $extensionDir;
|
||||||
|
$this->localisationCache = $localisationCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register class autoloader, i18n messages
|
||||||
|
* @param string $extensionName
|
||||||
|
* @param array $extJsonOptions
|
||||||
|
*/
|
||||||
|
public function register(
|
||||||
|
string $extensionName,
|
||||||
|
array $extJsonOptions
|
||||||
|
): void {
|
||||||
|
$this->registerClassAutoloader( $extensionName, $extJsonOptions );
|
||||||
|
$this->registerMessagesDirs( $extensionName, $extJsonOptions );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerClassAutoloader(
|
||||||
|
string $extensionName,
|
||||||
|
array $extJsonOptions
|
||||||
|
): void {
|
||||||
|
global $wgAutoloadLocalClasses;
|
||||||
|
|
||||||
|
$extPath = $this->getExtensionPath( $extensionName );
|
||||||
|
ExtensionRegistry::exportAutoloadClassesAndNamespaces(
|
||||||
|
$extPath,
|
||||||
|
$extJsonOptions
|
||||||
|
);
|
||||||
|
// important for upgrade (mw-config/?page=ExistingWiki) with existing LocalSettings.php
|
||||||
|
if (
|
||||||
|
!empty( $extJsonOptions['AutoloadClasses'] )
|
||||||
|
&& is_array( $extJsonOptions['AutoloadClasses'] )
|
||||||
|
) {
|
||||||
|
foreach ( $extJsonOptions['AutoloadClasses'] as $extensionName => $path ) {
|
||||||
|
$wgAutoloadLocalClasses[$extensionName] = "$extPath/$path";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerMessagesDirs(
|
||||||
|
string $extensionName,
|
||||||
|
array $extJsonOptions
|
||||||
|
): void {
|
||||||
|
if ( !is_array( $extJsonOptions['MessagesDirs'] ?? null ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $extJsonOptions['MessagesDirs'] as $messageType => $messagesDirs ) {
|
||||||
|
$messagesDirs = (array)$messagesDirs;
|
||||||
|
foreach ( $messagesDirs as $key => $messageDir ) {
|
||||||
|
$i18nDir = $this->getExtensionPath( $extensionName ) . "/$messageDir";
|
||||||
|
if ( !is_dir( $i18nDir ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->localisationCache->addMessagesDir(
|
||||||
|
count( $messagesDirs ) === 1
|
||||||
|
? $messageType
|
||||||
|
: "{$messageType}_{$key}",
|
||||||
|
$i18nDir
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getExtensionPath( string $extensionName ) : string {
|
||||||
|
return "{$this->extensionDir}/{$extensionName}";
|
||||||
|
}
|
||||||
|
}
|
||||||
104
includes/installer/Services/InstallerExtensionSelector.php
Normal file
104
includes/installer/Services/InstallerExtensionSelector.php
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @ingroup Installer
|
||||||
|
*
|
||||||
|
* @author Art Baltai
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare( strict_types = 1 );
|
||||||
|
namespace MediaWiki\Installer\Services;
|
||||||
|
|
||||||
|
use Generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.35
|
||||||
|
*/
|
||||||
|
class InstallerExtensionSelector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $extensionDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]|null
|
||||||
|
*/
|
||||||
|
private $extensionJsonPath;
|
||||||
|
|
||||||
|
public function __construct( string $extensionDir ) {
|
||||||
|
$this->extensionDir = $extensionDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getExtensionJsonPaths() : array {
|
||||||
|
if ( $this->extensionJsonPath === null ) {
|
||||||
|
$this->extensionJsonPath = [];
|
||||||
|
if ( is_dir( $this->extensionDir ) ) {
|
||||||
|
$dh = opendir( $this->extensionDir );
|
||||||
|
while ( ( $extension = readdir( $dh ) ) !== false ) {
|
||||||
|
if ( mb_substr( $extension, 0, 1 ) === '.' ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$jsonPath = "{$this->extensionDir}/{$extension}/extension.json";
|
||||||
|
if ( is_file( $jsonPath ) && is_readable( $jsonPath ) ) {
|
||||||
|
$this->extensionJsonPath[$extension] = $jsonPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir( $dh );
|
||||||
|
|
||||||
|
uksort( $this->extensionJsonPath, 'strnatcasecmp' );
|
||||||
|
} // @todo else:warning?
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->extensionJsonPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Generator for interating through all exntension.json files converterd
|
||||||
|
* into array. Key is string of exntension name and value is decoded exntension.json.
|
||||||
|
*
|
||||||
|
* @return Generator
|
||||||
|
*/
|
||||||
|
private function getExtensionJsons() : Generator {
|
||||||
|
foreach ( $this->getExtensionJsonPaths() as $extension => $jsonPath ) {
|
||||||
|
$json = file_get_contents( $jsonPath );
|
||||||
|
$options = json_decode( $json, true );
|
||||||
|
if ( !is_array( $options ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $extension => $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Generator for interating through extension's options
|
||||||
|
* filtered by certain type.
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return Generator
|
||||||
|
*/
|
||||||
|
public function getExtOptionsByType( string $type ) : Generator {
|
||||||
|
foreach ( $this->getExtensionJsons() as $extensionName => $options ) {
|
||||||
|
if ( $type === ( $options['type'] ?? null ) ) {
|
||||||
|
yield $extensionName => $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
* @file
|
* @file
|
||||||
* @ingroup Installer
|
* @ingroup Installer
|
||||||
*/
|
*/
|
||||||
|
use MediaWiki\Installer\Services\InstallerDBSupport;
|
||||||
|
|
||||||
class WebInstallerDBConnect extends WebInstallerPage {
|
class WebInstallerDBConnect extends WebInstallerPage {
|
||||||
|
|
||||||
|
|
@ -50,7 +51,7 @@ class WebInstallerDBConnect extends WebInstallerPage {
|
||||||
|
|
||||||
// Messages: config-dbsupport-mysql, config-dbsupport-postgres, config-dbsupport-sqlite
|
// Messages: config-dbsupport-mysql, config-dbsupport-postgres, config-dbsupport-sqlite
|
||||||
$dbSupport = '';
|
$dbSupport = '';
|
||||||
foreach ( Installer::getDBTypes() as $type ) {
|
foreach ( InstallerDBSupport::getInstance()->getDatabases() as $type ) {
|
||||||
$dbSupport .= wfMessage( "config-dbsupport-$type" )->plain() . "\n";
|
$dbSupport .= wfMessage( "config-dbsupport-$type" )->plain() . "\n";
|
||||||
}
|
}
|
||||||
$this->addHTML( $this->parent->getInfoBox(
|
$this->addHTML( $this->parent->getInfoBox(
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
* @ingroup Installer
|
* @ingroup Installer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use MediaWiki\Installer\Services\InstallerDBSupport;
|
||||||
|
|
||||||
class WebInstallerExistingWiki extends WebInstallerPage {
|
class WebInstallerExistingWiki extends WebInstallerPage {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -140,7 +142,7 @@ class WebInstallerExistingWiki extends WebInstallerPage {
|
||||||
protected function handleExistingUpgrade( $vars ) {
|
protected function handleExistingUpgrade( $vars ) {
|
||||||
// Check $wgDBtype
|
// Check $wgDBtype
|
||||||
if ( !isset( $vars['wgDBtype'] ) ||
|
if ( !isset( $vars['wgDBtype'] ) ||
|
||||||
!in_array( $vars['wgDBtype'], Installer::getDBTypes() )
|
!InstallerDBSupport::getInstance()->hasDatabase( $vars['wgDBtype'] )
|
||||||
) {
|
) {
|
||||||
return Status::newFatal( 'config-localsettings-connection-error', '' );
|
return Status::newFatal( 'config-localsettings-connection-error', '' );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
* @ingroup Installer
|
* @ingroup Installer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use MediaWiki\Installer\Services\InstallerDBSupport;
|
||||||
use Wikimedia\IPUtils;
|
use Wikimedia\IPUtils;
|
||||||
|
|
||||||
class WebInstallerOptions extends WebInstallerPage {
|
class WebInstallerOptions extends WebInstallerPage {
|
||||||
|
|
@ -147,7 +148,14 @@ class WebInstallerOptions extends WebInstallerPage {
|
||||||
$this->getFieldsetEnd();
|
$this->getFieldsetEnd();
|
||||||
$this->addHTML( $skinHtml );
|
$this->addHTML( $skinHtml );
|
||||||
|
|
||||||
$extensions = $this->parent->findExtensions()->value;
|
$extensions = array_filter(
|
||||||
|
$this->parent->findExtensions()->value,
|
||||||
|
function ( $extensionInfo ) {
|
||||||
|
return ( $extensionInfo['type'] ?? null )
|
||||||
|
!== InstallerDBSupport::EXTENSION_TYPE_DATABASE;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
'@phan-var array[] $extensions';
|
'@phan-var array[] $extensions';
|
||||||
$dependencyMap = [];
|
$dependencyMap = [];
|
||||||
|
|
||||||
|
|
@ -182,7 +190,7 @@ class WebInstallerOptions extends WebInstallerPage {
|
||||||
'class' => 'config-ext-input'
|
'class' => 'config-ext-input'
|
||||||
];
|
];
|
||||||
$labelAttribs = [];
|
$labelAttribs = [];
|
||||||
$fullDepList = [];
|
|
||||||
if ( isset( $info['requires']['extensions'] ) ) {
|
if ( isset( $info['requires']['extensions'] ) ) {
|
||||||
$dependencyMap[$ext]['extensions'] = $info['requires']['extensions'];
|
$dependencyMap[$ext]['extensions'] = $info['requires']['extensions'];
|
||||||
$labelAttribs['class'] = 'mw-ext-with-dependencies';
|
$labelAttribs['class'] = 'mw-ext-with-dependencies';
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ use Exception;
|
||||||
use HashBagOStuff;
|
use HashBagOStuff;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
|
use MediaWiki\Installer\Services\InstallerDBSupport;
|
||||||
use Psr\Log\LoggerAwareInterface;
|
use Psr\Log\LoggerAwareInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Psr\Log\NullLogger;
|
use Psr\Log\NullLogger;
|
||||||
|
|
@ -392,7 +393,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
||||||
* @since 1.18
|
* @since 1.18
|
||||||
*/
|
*/
|
||||||
final public static function factory( $type, $params = [], $connect = self::NEW_CONNECTED ) {
|
final public static function factory( $type, $params = [], $connect = self::NEW_CONNECTED ) {
|
||||||
$class = self::getClass( $type, $params['driver'] ?? null );
|
$class = InstallerDBSupport::getInstance()->getDBDriverClass( $type );
|
||||||
|
|
||||||
if ( class_exists( $class ) && is_subclass_of( $class, IDatabase::class ) ) {
|
if ( class_exists( $class ) && is_subclass_of( $class, IDatabase::class ) ) {
|
||||||
$params += [
|
$params += [
|
||||||
|
|
@ -453,64 +454,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
|
||||||
self::ATTR_SCHEMAS_AS_TABLE_GROUPS => false
|
self::ATTR_SCHEMAS_AS_TABLE_GROUPS => false
|
||||||
];
|
];
|
||||||
|
|
||||||
$class = self::getClass( $dbType, $driver );
|
$class = InstallerDBSupport::getInstance()->getDBDriverClass( $dbType );
|
||||||
|
|
||||||
return call_user_func( [ $class, 'getAttributes' ] ) + $defaults;
|
return call_user_func( [ $class, 'getAttributes' ] ) + $defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $dbType A possible DB type (sqlite, mysql, postgres,...)
|
|
||||||
* @param string|null $driver Optional name of a specific DB client driver
|
|
||||||
* @return string Database subclass name to use
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
*/
|
|
||||||
private static function getClass( $dbType, $driver = null ) {
|
|
||||||
// For database types with built-in support, the below maps type to IDatabase
|
|
||||||
// implementations. For types with multiple driver implementations (PHP extensions),
|
|
||||||
// an array can be used, keyed by extension name. In case of an array, the
|
|
||||||
// optional 'driver' parameter can be used to force a specific driver. Otherwise,
|
|
||||||
// we auto-detect the first available driver. For types without built-in support,
|
|
||||||
// an class named "Database<Type>" us used, eg. DatabaseFoo for type 'foo'.
|
|
||||||
static $builtinTypes = [
|
|
||||||
'mysql' => [ 'mysqli' => DatabaseMysqli::class ],
|
|
||||||
'sqlite' => DatabaseSqlite::class,
|
|
||||||
'postgres' => DatabasePostgres::class,
|
|
||||||
];
|
|
||||||
|
|
||||||
$dbType = strtolower( $dbType );
|
|
||||||
$class = false;
|
|
||||||
|
|
||||||
if ( isset( $builtinTypes[$dbType] ) ) {
|
|
||||||
$possibleDrivers = $builtinTypes[$dbType];
|
|
||||||
if ( is_string( $possibleDrivers ) ) {
|
|
||||||
$class = $possibleDrivers;
|
|
||||||
} elseif ( (string)$driver !== '' ) {
|
|
||||||
if ( !isset( $possibleDrivers[$driver] ) ) {
|
|
||||||
throw new InvalidArgumentException( __METHOD__ .
|
|
||||||
" type '$dbType' does not support driver '{$driver}'" );
|
|
||||||
}
|
|
||||||
|
|
||||||
$class = $possibleDrivers[$driver];
|
|
||||||
} else {
|
|
||||||
foreach ( $possibleDrivers as $posDriver => $possibleClass ) {
|
|
||||||
if ( extension_loaded( $posDriver ) ) {
|
|
||||||
$class = $possibleClass;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$class = 'Database' . ucfirst( $dbType );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $class === false ) {
|
|
||||||
throw new InvalidArgumentException( __METHOD__ .
|
|
||||||
" no viable database extension found for type '$dbType'" );
|
|
||||||
}
|
|
||||||
|
|
||||||
return $class;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array Map of (Database::ATTR_* constant => value)
|
* @return array Map of (Database::ATTR_* constant => value)
|
||||||
* @since 1.31
|
* @since 1.31
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use MediaWiki\ExtensionInfo;
|
use MediaWiki\ExtensionInfo;
|
||||||
|
use MediaWiki\Installer\Services\InstallerDBSupport;
|
||||||
use MediaWiki\MediaWikiServices;
|
use MediaWiki\MediaWikiServices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -416,6 +417,8 @@ class SpecialVersion extends SpecialPage {
|
||||||
'antispam' => wfMessage( 'version-antispam' )->text(),
|
'antispam' => wfMessage( 'version-antispam' )->text(),
|
||||||
'skin' => wfMessage( 'version-skins' )->text(),
|
'skin' => wfMessage( 'version-skins' )->text(),
|
||||||
'api' => wfMessage( 'version-api' )->text(),
|
'api' => wfMessage( 'version-api' )->text(),
|
||||||
|
InstallerDBSupport::EXTENSION_TYPE_DATABASE =>
|
||||||
|
wfMessage( 'version-database' )->text(),
|
||||||
'other' => wfMessage( 'version-other' )->text(),
|
'other' => wfMessage( 'version-other' )->text(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3561,6 +3561,7 @@
|
||||||
"version-variables": "Variables",
|
"version-variables": "Variables",
|
||||||
"version-editors": "Editors",
|
"version-editors": "Editors",
|
||||||
"version-antispam": "Spam prevention",
|
"version-antispam": "Spam prevention",
|
||||||
|
"version-database": "Custom database support",
|
||||||
"version-api": "API",
|
"version-api": "API",
|
||||||
"version-other": "Other",
|
"version-other": "Other",
|
||||||
"version-mediahandlers": "Media handlers",
|
"version-mediahandlers": "Media handlers",
|
||||||
|
|
|
||||||
|
|
@ -3778,6 +3778,7 @@
|
||||||
"version-antispam": "Part of [[Special:Version]].\nThis message is followed by the list of SPAM prevention extensions.",
|
"version-antispam": "Part of [[Special:Version]].\nThis message is followed by the list of SPAM prevention extensions.",
|
||||||
"version-api": "{{optional}}",
|
"version-api": "{{optional}}",
|
||||||
"version-other": "{{Identical|Other}}",
|
"version-other": "{{Identical|Other}}",
|
||||||
|
"version-database": "Database type",
|
||||||
"version-mediahandlers": "Used in [[Special:Version]]. It is the title of a section for media handler extensions (e.g. [[mw:Extension:OggHandler]]).\nThere are no such extensions here, so look at [[wikipedia:Special:Version]] for an example.",
|
"version-mediahandlers": "Used in [[Special:Version]]. It is the title of a section for media handler extensions (e.g. [[mw:Extension:OggHandler]]).\nThere are no such extensions here, so look at [[wikipedia:Special:Version]] for an example.",
|
||||||
"version-hooks": "Shown in [[Special:Version]]\n{{Identical|Hook}}",
|
"version-hooks": "Shown in [[Special:Version]]\n{{Identical|Hook}}",
|
||||||
"version-parser-extensiontags": "Part of [[Special:Version]].\nThis message is followed by the list of parser extension tags like <code><nowiki><charinsert></nowiki></code>, <code><nowiki><coordinates></nowiki></code>, etc.",
|
"version-parser-extensiontags": "Part of [[Special:Version]].\nThis message is followed by the list of parser extension tags like <code><nowiki><charinsert></nowiki></code>, <code><nowiki><coordinates></nowiki></code>, etc.",
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
require_once __DIR__ . '/Maintenance.php';
|
require_once __DIR__ . '/Maintenance.php';
|
||||||
|
|
||||||
|
use MediaWiki\Installer\Services\InstallerDBSupport;
|
||||||
use MediaWiki\MediaWikiServices;
|
use MediaWiki\MediaWikiServices;
|
||||||
use Wikimedia\Rdbms\DatabaseSqlite;
|
use Wikimedia\Rdbms\DatabaseSqlite;
|
||||||
|
|
||||||
|
|
@ -141,8 +142,9 @@ class UpdateMediaWiki extends Maintenance {
|
||||||
$db = $this->getDB( DB_MASTER );
|
$db = $this->getDB( DB_MASTER );
|
||||||
|
|
||||||
# Check to see whether the database server meets the minimum requirements
|
# Check to see whether the database server meets the minimum requirements
|
||||||
/** @var DatabaseInstaller $dbInstallerClass */
|
/** @var string|DatabaseInstaller $dbInstallerClass */
|
||||||
$dbInstallerClass = Installer::getDBInstallerClass( $db->getType() );
|
$dbInstallerClass = InstallerDBSupport::getInstance()
|
||||||
|
->getDBInstallerClass( $db->getType() );
|
||||||
$status = $dbInstallerClass::meetsMinimumRequirement( $db->getServerVersion() );
|
$status = $dbInstallerClass::meetsMinimumRequirement( $db->getServerVersion() );
|
||||||
if ( !$status->isOK() ) {
|
if ( !$status->isOK() ) {
|
||||||
// This might output some wikitext like <strong> but it should be comprehensible
|
// This might output some wikitext like <strong> but it should be comprehensible
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,9 @@ class DatabaseTest extends PHPUnit\Framework\TestCase {
|
||||||
$m = Database::NEW_UNCONNECTED; // no-connect mode
|
$m = Database::NEW_UNCONNECTED; // no-connect mode
|
||||||
$p = [ 'host' => 'localhost', 'user' => 'me', 'password' => 'myself', 'dbname' => 'i' ];
|
$p = [ 'host' => 'localhost', 'user' => 'me', 'password' => 'myself', 'dbname' => 'i' ];
|
||||||
|
|
||||||
$this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'mysqli', $p, $m ) );
|
$this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'mysql', $p, $m ) );
|
||||||
$this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'MySqli', $p, $m ) );
|
$this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'MySql', $p, $m ) );
|
||||||
$this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'MySQLi', $p, $m ) );
|
$this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'MySQL', $p, $m ) );
|
||||||
$this->assertInstanceOf( DatabasePostgres::class, Database::factory( 'postgres', $p, $m ) );
|
$this->assertInstanceOf( DatabasePostgres::class, Database::factory( 'postgres', $p, $m ) );
|
||||||
$this->assertInstanceOf( DatabasePostgres::class, Database::factory( 'Postgres', $p, $m ) );
|
$this->assertInstanceOf( DatabasePostgres::class, Database::factory( 'Postgres', $p, $m ) );
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@
|
||||||
<testsuite name="languages">
|
<testsuite name="languages">
|
||||||
<directory>languages</directory>
|
<directory>languages</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
<testsuite name="rdbms">
|
||||||
|
<directory>includes/libs/rdbms</directory>
|
||||||
|
</testsuite>
|
||||||
<testsuite name="parsertests">
|
<testsuite name="parsertests">
|
||||||
<file>suites/CoreParserTestSuite.php</file>
|
<file>suites/CoreParserTestSuite.php</file>
|
||||||
<file>suites/ExtensionsParserTestSuite.php</file>
|
<file>suites/ExtensionsParserTestSuite.php</file>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue