diff options
Diffstat (limited to 'includes/registration')
-rw-r--r-- | includes/registration/CoreVersionChecker.php | 68 | ||||
-rw-r--r-- | includes/registration/ExtensionProcessor.php | 27 | ||||
-rw-r--r-- | includes/registration/ExtensionRegistry.php | 52 | ||||
-rw-r--r-- | includes/registration/Processor.php | 20 |
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 ); } |