From: MGChecker Date: Mon, 24 Sep 2018 21:55:16 +0000 (+0200) Subject: registration: Let extensions add PHP extension requirements X-Git-Tag: 1.34.0-rc.0~3897^2 X-Git-Url: http://git.cyclocoop.org/%28?a=commitdiff_plain;h=c7e45b62113b1d9d6ff80705eff25ee93b722e19;p=lhc%2Fweb%2Fwiklou.git registration: Let extensions add PHP extension requirements This change adds the possibility to specify ext-* keys under the 'platform' key introduced in I6744cc0be2 to require given PHP extensions. Note that it's impossible to add constraints different from '*', as there is no universal way to retrieve PHP extension versions. Bug: T197535 Change-Id: I510de1e6d80f5c1d92dc1d1665aaa6c25bf28bf7 --- diff --git a/docs/extension.schema.v1.json b/docs/extension.schema.v1.json index e6ec971e51..f6f3b2188f 100644 --- a/docs/extension.schema.v1.json +++ b/docs/extension.schema.v1.json @@ -71,6 +71,13 @@ "type": "string", "description": "Version constraint string against PHP." } + }, + "patternProprties": { + "^ext-": { + "type": "string", + "description": "Required PHP extension.", + "const": "*" + } } }, "extensions": { diff --git a/docs/extension.schema.v2.json b/docs/extension.schema.v2.json index 93bf0d908a..8ade991d4d 100644 --- a/docs/extension.schema.v2.json +++ b/docs/extension.schema.v2.json @@ -72,6 +72,13 @@ "type": "string", "description": "Version constraint string against PHP." } + }, + "patternProprties": { + "^ext-": { + "type": "string", + "description": "Required PHP extension.", + "const": "*" + } } }, "extensions": { diff --git a/includes/registration/ExtensionDependencyError.php b/includes/registration/ExtensionDependencyError.php index dfd598541d..c27cd2c18c 100644 --- a/includes/registration/ExtensionDependencyError.php +++ b/includes/registration/ExtensionDependencyError.php @@ -53,6 +53,11 @@ class ExtensionDependencyError extends Exception { */ public $incompatiblePhp = false; + /** + * @var string[] + */ + public $missingPhpExtensions = []; + /** * @param array $errors Each error has a 'msg' and 'type' key at minimum */ @@ -67,6 +72,9 @@ class ExtensionDependencyError extends Exception { case 'incompatible-php': $this->incompatiblePhp = true; break; + case 'missing-phpExtension': + $this->missingPhpExtensions[] = $info['missing']; + break; case 'missing-skins': $this->missingSkins[] = $info['missing']; break; diff --git a/includes/registration/ExtensionRegistry.php b/includes/registration/ExtensionRegistry.php index 3138b37a04..e462a0bc85 100644 --- a/includes/registration/ExtensionRegistry.php +++ b/includes/registration/ExtensionRegistry.php @@ -213,8 +213,11 @@ class ExtensionRegistry { $autoloadNamespaces = []; $autoloaderPaths = []; $processor = new ExtensionProcessor(); - $phpVersion = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION; - $versionChecker = new VersionChecker( $wgVersion, $phpVersion ); + $versionChecker = new VersionChecker( + $wgVersion, + PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + get_loaded_extensions() + ); $extDependencies = []; $incompatible = []; $warnings = false; diff --git a/includes/registration/VersionChecker.php b/includes/registration/VersionChecker.php index 93b4a14301..586729d057 100644 --- a/includes/registration/VersionChecker.php +++ b/includes/registration/VersionChecker.php @@ -40,6 +40,11 @@ class VersionChecker { */ private $phpVersion = false; + /** + * @var string[] List of installed PHP extensions + */ + private $phpExtensions = []; + /** * @var array Loaded extensions */ @@ -52,11 +57,14 @@ class VersionChecker { /** * @param string $coreVersion Current version of core + * @param string $phpVersion Current PHP version + * @param string[] $phpExtensions List of installed PHP extensions */ - public function __construct( $coreVersion, $phpVersion ) { + public function __construct( $coreVersion, $phpVersion, array $phpExtensions ) { $this->versionParser = new VersionParser(); $this->setCoreVersion( $coreVersion ); $this->setPhpVersion( $phpVersion ); + $this->phpExtensions = $phpExtensions; } /** @@ -112,7 +120,8 @@ class VersionChecker { * 'FooBar' => { * 'MediaWiki' => '>= 1.25.0', * 'platform': { - * 'php': '>= 7.0.0' + * 'php': '>= 7.0.0', + * 'ext-foo': '*' * }, * 'extensions' => { * 'FooBaz' => '>= 1.25.0' @@ -151,6 +160,7 @@ class VersionChecker { case 'platform': foreach ( $values as $dependency => $constraint ) { if ( $dependency === 'php' ) { + // PHP version $phpError = $this->handleDependency( $this->phpVersion, $constraint, @@ -166,6 +176,23 @@ class VersionChecker { 'type' => 'incompatible-php', ]; } + } elseif ( substr( $dependency, 0, 4 ) === 'ext-' ) { + // PHP extensions + $phpExtension = substr( $dependency, 4 ); + if ( $constraint !== '*' ) { + throw new UnexpectedValueException( 'Version constraints for ' + . 'PHP extensions are not supported in ' . $extension ); + } + if ( !in_array( $phpExtension, $this->phpExtensions, true ) ) { + $errors[] = [ + 'msg' => + "{$extension} requires {$phpExtension} PHP extension " + . "to be installed." + , + 'type' => 'missing-phpExtension', + 'missing' => $phpExtension, + ]; + } } else { // add other platform dependencies here throw new UnexpectedValueException( 'Dependency type ' . $dependency . diff --git a/tests/phpunit/includes/registration/VersionCheckerTest.php b/tests/phpunit/includes/registration/VersionCheckerTest.php index 20f97bf581..6b92444442 100644 --- a/tests/phpunit/includes/registration/VersionCheckerTest.php +++ b/tests/phpunit/includes/registration/VersionCheckerTest.php @@ -12,7 +12,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { * @dataProvider provideMediaWikiCheck */ public function testMediaWikiCheck( $coreVersion, $constraint, $expected ) { - $checker = new VersionChecker( $coreVersion, '7.0.0' ); + $checker = new VersionChecker( $coreVersion, '7.0.0', [] ); $this->assertEquals( $expected, !(bool)$checker->checkArray( [ 'FakeExtension' => [ 'MediaWiki' => $constraint, @@ -48,7 +48,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { * @dataProvider providePhpValidCheck */ public function testPhpValidCheck( $phpVersion, $constraint, $expected ) { - $checker = new VersionChecker( '1.0.0', $phpVersion ); + $checker = new VersionChecker( '1.0.0', $phpVersion, [] ); $this->assertEquals( $expected, !(bool)$checker->checkArray( [ 'FakeExtension' => [ 'platform' => [ @@ -71,7 +71,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { * @expectedException UnexpectedValueException */ public function testPhpInvalidConstraint() { - $checker = new VersionChecker( '1.0.0', '7.0.0' ); + $checker = new VersionChecker( '1.0.0', '7.0.0', [] ); $checker->checkArray( [ 'FakeExtension' => [ 'platform' => [ @@ -86,7 +86,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { * @expectedException UnexpectedValueException */ public function testPhpInvalidVersion( $phpVersion ) { - $checker = new VersionChecker( '1.0.0', $phpVersion ); + $checker = new VersionChecker( '1.0.0', $phpVersion, [] ); } public static function providePhpInvalidVersion() { @@ -101,7 +101,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { * @dataProvider provideType */ public function testType( $given, $expected ) { - $checker = new VersionChecker( '1.0.0', '7.0.0' ); + $checker = new VersionChecker( '1.0.0', '7.0.0', [ 'phpLoadedExtension' ] ); $checker->setLoadedExtensionsAndSkins( [ 'FakeDependency' => [ 'version' => '1.0.0', @@ -195,6 +195,29 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { ], ], ], + [ + [ + 'platform' => [ + 'ext-phpLoadedExtension' => '*', + ], + ], + [], + ], + [ + [ + 'platform' => [ + 'ext-phpMissingExtension' => '*', + ], + ], + [ + [ + 'missing' => 'phpMissingExtension', + 'type' => 'missing-phpExtension', + // phpcs:ignore Generic.Files.LineLength.TooLong + 'msg' => 'FakeExtension requires phpMissingExtension PHP extension to be installed.', + ], + ], + ], ]; } @@ -203,7 +226,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { * returns any error message. */ public function testInvalidConstraint() { - $checker = new VersionChecker( '1.0.0', '7.0.0' ); + $checker = new VersionChecker( '1.0.0', '7.0.0', [] ); $checker->setLoadedExtensionsAndSkins( [ 'FakeDependency' => [ 'version' => 'not really valid', @@ -222,7 +245,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { ], ] ) ); - $checker = new VersionChecker( '1.0.0', '7.0.0' ); + $checker = new VersionChecker( '1.0.0', '7.0.0', [] ); $checker->setLoadedExtensionsAndSkins( [ 'FakeDependency' => [ 'version' => '1.24.3', @@ -249,6 +272,16 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { ], 'undefinedPlatformDependency', ], + [ + [ + 'FakeExtension' => [ + 'platform' => [ + 'phpLoadedExtension' => '*', + ], + ], + ], + 'phpLoadedExtension', + ], [ [ 'FakeExtension' => [ @@ -275,11 +308,26 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { * @dataProvider provideInvalidDependency */ public function testInvalidDependency( $depencency, $type ) { - $checker = new VersionChecker( '1.0.0', '7.0.0' ); + $checker = new VersionChecker( '1.0.0', '7.0.0', [ 'phpLoadedExtension' ] ); $this->setExpectedException( UnexpectedValueException::class, "Dependency type $type unknown in FakeExtension" ); $checker->checkArray( $depencency ); } + + public function testInvalidPhpExtensionConstraint() { + $checker = new VersionChecker( '1.0.0', '7.0.0', [ 'phpLoadedExtension' ] ); + $this->setExpectedException( + UnexpectedValueException::class, + 'Version constraints for PHP extensions are not supported in FakeExtension' + ); + $checker->checkArray( [ + 'FakeExtension' => [ + 'platform' => [ + 'ext-phpLoadedExtension' => '1.0.0', + ], + ], + ] ); + } }