Florianschmidtwelzow has uploaded a new change for review.
https://gerrit.wikimedia.org/r/250060
Change subject: ExtensionRegistration: Implement Extension dependencies
......................................................................
ExtensionRegistration: Implement Extension dependencies
There are some extensions, that depend on another extension or skin,
which actually is checked in php with:
- A constant, that is added in the dependency extension and checked in
the other one.
-> the problem: The dependency extension needs to be loaded before the
one, that depends on it
- A check is a specific class is loaded with "class_exists" or
"ExtensionRegistry::getInstance()->isLoaded( 'ExtensionName' )", if the
extension is loaded with ExtensionRegistration
-> Both doesn't support version checks (if a specific version of a
dependency is installed or not) and both needs code written in php.
Both solutions are, by the way, not machine readable and can differ in compared
extensions by "Where they are implemented, extension.php entry point,
wgExtensionFunctions,
or maybe an extension.json callback)" and "What check is implemented". That
makes it hard
to define and document the "right" way. It would be great, if
ExtensionRegistration could
handle such dependencies for a developer.
This change implements the possibility to name extensions, and a specific
version constraint
for each one, that this extension depends on. It uses the requires section for
that, which
already handles a dependency to MediaWiki core. An example for an
extension.json, that depends
on FakeExtension in version 1.2.0 or greater, would be:
"requires": {
"MediaWiki": ">= 1.25.0", // a dependency to MediaWiki core
"ext-FakeExtension": "1.2.0" // a dependency to FakeExtension
at least with version 1.2.0
},
A developer needs to add the "ext-" prefix to all requirements, that are
extensions. That allows
(hopefully) the implementation of other requirements (that maybe follows, I
don't know), if needed. So
all dependencies can be distinguished.
Bug: T117277
Change-Id: If1cccee1a16a867a71bb0285691c400443d8a30a
---
M autoload.php
A includes/registration/ExtVersionChecker.php
M includes/registration/ExtensionProcessor.php
M includes/registration/ExtensionRegistry.php
4 files changed, 114 insertions(+), 8 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/60/250060/1
diff --git a/autoload.php b/autoload.php
index 65a84bf..06d1548 100644
--- a/autoload.php
+++ b/autoload.php
@@ -393,6 +393,7 @@
'ExplodeIterator' => __DIR__ . '/includes/libs/ExplodeIterator.php',
'ExportProgressFilter' => __DIR__ . '/maintenance/backup.inc',
'ExportSites' => __DIR__ . '/maintenance/exportSites.php',
+ 'ExtVersionChecker' => __DIR__ .
'/includes/registration/ExtVersionChecker.php',
'ExtensionLanguages' => __DIR__ . '/maintenance/language/languages.inc',
'ExtensionProcessor' => __DIR__ .
'/includes/registration/ExtensionProcessor.php',
'ExtensionRegistry' => __DIR__ .
'/includes/registration/ExtensionRegistry.php',
diff --git a/includes/registration/ExtVersionChecker.php
b/includes/registration/ExtVersionChecker.php
new file mode 100644
index 0000000..78ac07e
--- /dev/null
+++ b/includes/registration/ExtVersionChecker.php
@@ -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
+ */
+
+use Composer\Semver\VersionParser;
+use Composer\Semver\Constraint\Constraint;
+
+/**
+ * @since 1.27
+ */
+class ExtVersionChecker {
+ /**
+ * @var ExtensionRegistry
+ */
+ private $versionParser;
+
+ /**
+ * @param string $coreVersion Current version of core
+ */
+ public function __construct() {
+ $this->versionParser = new VersionParser();
+ }
+
+ /**
+ * Check all given dependencies if they are compatible with the named
+ * installed extensions in the $credits array.
+ *
+ * Example $extDependencies:
+ * array (
+ * 'GoogleAPIClient' => array(
+ * 'ext-FakeExtension' => '>= 1.25.0'
+ * )
+ * )
+ *
+ * @param array $extDependencies All extensions, that depends on
another one
+ * @param array $credits An array of installed extensions with the
credits of them
+ * @return bool
+ */
+ public function checkArray( array $extDependencies, array $credits ) {
+ $incompatible = array();
+ foreach ( $extDependencies as $extension => $dependencies ) {
+ foreach ( $dependencies as $dependency => $constraint )
{
+ // limit to dependencies, that are extensions
+ $dependencyName = str_replace( 'ext-', '',
$dependency, $replaceCount );
+ if ( $replaceCount !== 1 ) {
+ // extension dependencies need to be
prefixed with "ext-"
+ continue;
+ }
+ // check, if the dependency is installed or not
+ if ( !isset( $credits[$dependencyName] ) ) {
+ $incompatible[] = "{$extension}
requires {$dependencyName} to be installed.";
+ continue;
+ }
+ // check, if the extension has it's version
mentioned in extension.json and set as incompatible if not
+ if ( !isset(
$credits[$dependencyName]['version'] ) ) {
+ // if the extension doesn't need a
special version of the dependency, just log an info, that the version is missing
+ if ( $constraint === '*' ) {
+ wfDebug( "{$dependencyName}
does not expose it's version, but {$extension}
+ mentions it with
constraint '*'. Assume it's ok so." );
+ } else {
+ // otherwise: mark as
incompatible
+ $incompatible[] =
"{$dependencyName} does not expose it's version, but {$extension}
+ requires:
{$constraint}.";
+ }
+ }
+
+ // try to get a constraint for the dependency
version
+ try {
+ $installedVersion = new Constraint(
+ '==',
+
$this->versionParser->normalize( $credits[$dependencyName]['version'] )
+ );
+ } catch ( UnexpectedValueException $e ) {
+ // Non-parsable version, don't fatal.
+ continue;
+ }
+ // finally, check constraint against dependency
version
+ // check and parse constraint
+ if ( !$this->versionParser->parseConstraints(
$constraint )->matches( $installedVersion ) ) {
+ $incompatible[] = "{$extension} is not
compatible with the current "
+ . "installed version of
{$dependencyName} (version {$credits[$dependencyName]['version']}),"
+ . "it requires: " . $constraint
. '.';
+ }
+ }
+ }
+
+ return $incompatible;
+ }
+}
diff --git a/includes/registration/ExtensionProcessor.php
b/includes/registration/ExtensionProcessor.php
index 84e873d..5be4628 100644
--- a/includes/registration/ExtensionProcessor.php
+++ b/includes/registration/ExtensionProcessor.php
@@ -193,13 +193,7 @@
}
public function getRequirements( array $info ) {
- $requirements = array();
- $key = ExtensionRegistry::MEDIAWIKI_CORE;
- if ( isset( $info['requires'][$key] ) ) {
- $requirements[$key] = $info['requires'][$key];
- }
-
- return $requirements;
+ return isset( $info['requires'] ) ? $info['requires'] : array();
}
protected function extractHooks( array $info ) {
diff --git a/includes/registration/ExtensionRegistry.php
b/includes/registration/ExtensionRegistry.php
index 59b9249..9f73e2e 100644
--- a/includes/registration/ExtensionRegistry.php
+++ b/includes/registration/ExtensionRegistry.php
@@ -176,6 +176,8 @@
$processor = new ExtensionProcessor();
$incompatible = array();
$coreVersionParser = new CoreVersionChecker( $wgVersion );
+ $extVersionParser = new ExtVersionChecker();
+ $extDependencies = array();
foreach ( $queue as $path => $mtime ) {
$json = file_get_contents( $path );
if ( $json === false ) {
@@ -208,9 +210,15 @@
. '.';
continue;
}
+ if ( is_array( $requires ) && $requires &&
isset($info['name']) ) {
+ $extDependencies[$info['name']] = $requires;
+ }
// Compatible, read and extract info
$processor->extractInfo( $path, $info, $version );
}
+ $data = $processor->getExtractedInfo();
+ // check for incompatible extensions and add them to the list
of incompatible extensions
+ $incompatible += $extVersionParser->checkArray(
$extDependencies, $data['credits'] );
if ( $incompatible ) {
if ( count( $incompatible ) === 1 ) {
throw new Exception( $incompatible[0] );
@@ -218,7 +226,6 @@
throw new Exception( implode( "\n",
$incompatible ) );
}
}
- $data = $processor->getExtractedInfo();
// Need to set this so we can += to it later
$data['globals']['wgAutoloadClasses'] = array();
foreach ( $data['credits'] as $credit ) {
--
To view, visit https://gerrit.wikimedia.org/r/250060
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If1cccee1a16a867a71bb0285691c400443d8a30a
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Florianschmidtwelzow <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits