summaryrefslogtreecommitdiff
path: root/includes/registration
diff options
context:
space:
mode:
Diffstat (limited to 'includes/registration')
-rw-r--r--includes/registration/CoreVersionChecker.php68
-rw-r--r--includes/registration/ExtensionProcessor.php27
-rw-r--r--includes/registration/ExtensionRegistry.php52
-rw-r--r--includes/registration/Processor.php20
4 files changed, 152 insertions, 15 deletions
diff --git a/includes/registration/CoreVersionChecker.php b/includes/registration/CoreVersionChecker.php
new file mode 100644
index 00000000..f64d826d
--- /dev/null
+++ b/includes/registration/CoreVersionChecker.php
@@ -0,0 +1,68 @@
+<?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
+ */
+
+use Composer\Semver\VersionParser;
+use Composer\Semver\Constraint\Constraint;
+
+/**
+ * @since 1.26
+ */
+class CoreVersionChecker {
+
+ /**
+ * @var Constraint|bool representing $wgVersion
+ */
+ private $coreVersion = false;
+
+ /**
+ * @var VersionParser
+ */
+ private $versionParser;
+
+ /**
+ * @param string $coreVersion Current version of core
+ */
+ public function __construct( $coreVersion ) {
+ $this->versionParser = new VersionParser();
+ try {
+ $this->coreVersion = new Constraint(
+ '==',
+ $this->versionParser->normalize( $coreVersion )
+ );
+ } catch ( UnexpectedValueException $e ) {
+ // Non-parsable version, don't fatal.
+ }
+ }
+
+ /**
+ * Check that the provided constraint is compatible with the current version of core
+ *
+ * @param string $constraint Something like ">= 1.26"
+ * @return bool
+ */
+ public function check( $constraint ) {
+ if ( $this->coreVersion === false ) {
+ // Couldn't parse the core version, so we can't check anything
+ return true;
+ }
+
+ return $this->versionParser->parseConstraints( $constraint )
+ ->matches( $this->coreVersion );
+ }
+}
diff --git a/includes/registration/ExtensionProcessor.php b/includes/registration/ExtensionProcessor.php
index 0b594b42..a286f6bf 100644
--- a/includes/registration/ExtensionProcessor.php
+++ b/includes/registration/ExtensionProcessor.php
@@ -62,6 +62,8 @@ class ExtensionProcessor implements Processor {
'wgExtraGenderNamespaces' => 'array_plus',
'wgNamespacesWithSubpages' => 'array_plus',
'wgNamespaceContentModels' => 'array_plus',
+ 'wgNamespaceProtection' => 'array_plus',
+ 'wgCapitalLinkOverrides' => 'array_plus',
);
/**
@@ -144,9 +146,10 @@ class ExtensionProcessor implements Processor {
/**
* @param string $path
* @param array $info
+ * @param int $version manifest_version for info
* @return array
*/
- public function extractInfo( $path, array $info ) {
+ public function extractInfo( $path, array $info, $version ) {
$this->extractConfig( $info );
$this->extractHooks( $info );
$dir = dirname( $path );
@@ -189,6 +192,16 @@ class ExtensionProcessor implements Processor {
);
}
+ public function getRequirements( array $info ) {
+ $requirements = array();
+ $key = ExtensionRegistry::MEDIAWIKI_CORE;
+ if ( isset( $info['requires'][$key] ) ) {
+ $requirements[$key] = $info['requires'][$key];
+ }
+
+ return $requirements;
+ }
+
protected function extractHooks( array $info ) {
if ( isset( $info['Hooks'] ) ) {
foreach ( $info['Hooks'] as $name => $value ) {
@@ -222,6 +235,12 @@ class ExtensionProcessor implements Processor {
if ( isset( $ns['defaultcontentmodel'] ) ) {
$this->globals['wgNamespaceContentModels'][$id] = $ns['defaultcontentmodel'];
}
+ if ( isset( $ns['protection'] ) ) {
+ $this->globals['wgNamespaceProtection'][$id] = $ns['protection'];
+ }
+ if ( isset( $ns['capitallinkoverride'] ) ) {
+ $this->globals['wgCapitalLinkOverrides'][$id] = $ns['capitallinkoverride'];
+ }
}
}
}
@@ -320,10 +339,14 @@ class ExtensionProcessor implements Processor {
/**
* @param string $name
- * @param mixed $value
+ * @param array $value
* @param array &$array
+ * @throws InvalidArgumentException
*/
protected function storeToArray( $name, $value, &$array ) {
+ if ( !is_array( $value ) ) {
+ throw new InvalidArgumentException( "The value for '$name' should be an array" );
+ }
if ( isset( $array[$name] ) ) {
$array[$name] = array_merge_recursive( $array[$name], $value );
} else {
diff --git a/includes/registration/ExtensionRegistry.php b/includes/registration/ExtensionRegistry.php
index 16d83356..23e29d88 100644
--- a/includes/registration/ExtensionRegistry.php
+++ b/includes/registration/ExtensionRegistry.php
@@ -12,6 +12,11 @@
class ExtensionRegistry {
/**
+ * "requires" key that applies to MediaWiki core/$wgVersion
+ */
+ const MEDIAWIKI_CORE = 'MediaWiki';
+
+ /**
* Version of the highest supported manifest version
*/
const MANIFEST_VERSION = 1;
@@ -81,7 +86,7 @@ class ExtensionRegistry {
// we don't want to fail here if $wgObjectCaches is not configured
// properly for APC setup
try {
- $this->cache = ObjectCache::newAccelerator( array() );
+ $this->cache = ObjectCache::newAccelerator();
} catch ( MWException $e ) {
$this->cache = new EmptyBagOStuff();
}
@@ -156,20 +161,52 @@ class ExtensionRegistry {
* @throws Exception
*/
public function readFromQueue( array $queue ) {
- $data = array( 'globals' => array( 'wgAutoloadClasses' => array() ) );
+ global $wgVersion;
$autoloadClasses = array();
$processor = new ExtensionProcessor();
+ $incompatible = array();
+ $coreVersionParser = new CoreVersionChecker( $wgVersion );
foreach ( $queue as $path => $mtime ) {
$json = file_get_contents( $path );
+ if ( $json === false ) {
+ throw new Exception( "Unable to read $path, does it exist?" );
+ }
$info = json_decode( $json, /* $assoc = */ true );
if ( !is_array( $info ) ) {
throw new Exception( "$path is not a valid JSON file." );
}
+ if ( !isset( $info['manifest_version'] ) ) {
+ // For backwards-compatability, assume a version of 1
+ $info['manifest_version'] = 1;
+ }
+ $version = $info['manifest_version'];
+ if ( $version < self::OLDEST_MANIFEST_VERSION || $version > self::MANIFEST_VERSION ) {
+ throw new Exception( "$path: unsupported manifest_version: {$version}" );
+ }
$autoload = $this->processAutoLoader( dirname( $path ), $info );
// Set up the autoloader now so custom processors will work
$GLOBALS['wgAutoloadClasses'] += $autoload;
$autoloadClasses += $autoload;
- $processor->extractInfo( $path, $info );
+ // Check any constraints against MediaWiki core
+ $requires = $processor->getRequirements( $info );
+ if ( isset( $requires[self::MEDIAWIKI_CORE] )
+ && !$coreVersionParser->check( $requires[self::MEDIAWIKI_CORE] )
+ ) {
+ // Doesn't match, mark it as incompatible.
+ $incompatible[] = "{$info['name']} is not compatible with the current "
+ . "MediaWiki core (version {$wgVersion}), it requires: ". $requires[self::MEDIAWIKI_CORE]
+ . '.';
+ continue;
+ }
+ // Compatible, read and extract info
+ $processor->extractInfo( $path, $info, $version );
+ }
+ if ( $incompatible ) {
+ if ( count( $incompatible ) === 1 ) {
+ throw new Exception( $incompatible[0] );
+ } else {
+ throw new Exception( implode( "\n", $incompatible ) );
+ }
}
$data = $processor->getExtractedInfo();
// Need to set this so we can += to it later
@@ -212,14 +249,7 @@ class ExtensionRegistry {
$GLOBALS[$key] = array_merge_recursive( $GLOBALS[$key], $val );
break;
case 'array_plus_2d':
- // First merge items that are in both arrays
- foreach ( $GLOBALS[$key] as $name => &$groupVal ) {
- if ( isset( $val[$name] ) ) {
- $groupVal += $val[$name];
- }
- }
- // Now add items that didn't exist yet
- $GLOBALS[$key] += $val;
+ $GLOBALS[$key] = wfArrayPlus2d( $GLOBALS[$key], $val );
break;
case 'array_plus':
$GLOBALS[$key] += $val;
diff --git a/includes/registration/Processor.php b/includes/registration/Processor.php
index e930fd3e..e5669d27 100644
--- a/includes/registration/Processor.php
+++ b/includes/registration/Processor.php
@@ -16,12 +16,28 @@ interface Processor {
*
* @param string $path Absolute path of JSON file
* @param array $info
+ * @param int $version manifest_version for info
* @return array "credits" information to store
*/
- public function extractInfo( $path, array $info );
+ public function extractInfo( $path, array $info, $version );
/**
- * @return array With 'globals', 'defines', 'callbacks', 'credits' keys.
+ * @return array With following keys:
+ * 'globals' - variables to be set to $GLOBALS
+ * 'defines' - constants to define
+ * 'callbacks' - functions to be executed by the registry
+ * 'credits' - metadata to be stored by registry
+ * 'attributes' - registration info which isn't a global variable
*/
public function getExtractedInfo();
+
+ /**
+ * Get the requirements for the provided info
+ *
+ * @since 1.26
+ * @param array $info
+ * @return array Where keys are the name to have a constraint on,
+ * like 'MediaWiki'. Values are a constraint string like "1.26.1".
+ */
+ public function getRequirements( array $info );
}