MediaWiki REL1_35
VersionChecker.php
Go to the documentation of this file.
1<?php
2
23use Composer\Semver\Constraint\Constraint;
24use Composer\Semver\VersionParser;
25
36 private $coreVersion = false;
37
41 private $phpVersion = false;
42
46 private $phpExtensions = [];
47
51 private $abilities = [];
52
56 private $abilityErrors = [];
57
61 private $loaded = [];
62
67
75 public function __construct(
77 array $abilities = [], array $abilityErrors = []
78 ) {
79 $this->versionParser = new VersionParser();
81 $this->setPhpVersion( $phpVersion );
82 $this->phpExtensions = $phpExtensions;
83 $this->abilities = $abilities;
84 $this->abilityErrors = $abilityErrors;
85 }
86
93 public function setLoadedExtensionsAndSkins( array $credits ) {
94 $this->loaded = $credits;
95
96 return $this;
97 }
98
104 private function setCoreVersion( $coreVersion ) {
105 try {
106 $this->coreVersion = new Constraint(
107 '==',
108 $this->versionParser->normalize( $coreVersion )
109 );
110 $this->coreVersion->setPrettyString( $coreVersion );
111 } catch ( UnexpectedValueException $e ) {
112 // Non-parsable version, don't fatal.
113 }
114 }
115
122 private function setPhpVersion( $phpVersion ) {
123 // normalize to make this throw an exception if the version is invalid
124 $this->phpVersion = new Constraint(
125 '==',
126 $this->versionParser->normalize( $phpVersion )
127 );
128 $this->phpVersion->setPrettyString( $phpVersion );
129 }
130
156 public function checkArray( array $extDependencies ) {
157 $errors = [];
158 foreach ( $extDependencies as $extension => $dependencies ) {
159 foreach ( $dependencies as $dependencyType => $values ) {
160 switch ( $dependencyType ) {
161 case ExtensionRegistry::MEDIAWIKI_CORE:
162 $mwError = $this->handleDependency(
163 $this->coreVersion,
164 $values,
165 $extension
166 );
167 if ( $mwError !== false ) {
168 $errors[] = [
169 'msg' =>
170 "{$extension} is not compatible with the current MediaWiki "
171 . "core (version {$this->coreVersion->getPrettyString()}), "
172 . "it requires: $values."
173 ,
174 'type' => 'incompatible-core',
175 ];
176 }
177 break;
178 case 'platform':
179 foreach ( $values as $dependency => $constraint ) {
180 if ( $dependency === 'php' ) {
181 // PHP version
182 $phpError = $this->handleDependency(
183 $this->phpVersion,
184 $constraint,
185 $extension
186 );
187 if ( $phpError !== false ) {
188 $errors[] = [
189 'msg' =>
190 "{$extension} is not compatible with the current PHP "
191 . "version {$this->phpVersion->getPrettyString()}), "
192 . "it requires: $constraint."
193 ,
194 'type' => 'incompatible-php',
195 ];
196 }
197 } elseif ( substr( $dependency, 0, 4 ) === 'ext-' ) {
198 // PHP extensions
199 $phpExtension = substr( $dependency, 4 );
200 if ( $constraint !== '*' ) {
201 throw new UnexpectedValueException( 'Version constraints for '
202 . 'PHP extensions are not supported in ' . $extension );
203 }
204 if ( !in_array( $phpExtension, $this->phpExtensions, true ) ) {
205 $errors[] = [
206 'msg' =>
207 "{$extension} requires {$phpExtension} PHP extension "
208 . "to be installed."
209 ,
210 'type' => 'missing-phpExtension',
211 'missing' => $phpExtension,
212 ];
213 }
214 } elseif ( substr( $dependency, 0, 8 ) === 'ability-' ) {
215 // Other abilities the environment might provide.
216 $ability = substr( $dependency, 8 );
217 if ( !isset( $this->abilities[$ability] ) ) {
218 throw new UnexpectedValueException( 'Dependency type '
219 . $dependency . ' unknown in ' . $extension );
220 }
221 if ( !is_bool( $constraint ) ) {
222 throw new UnexpectedValueException( 'Only booleans are '
223 . 'allowed to to indicate the presence of abilities '
224 . 'in ' . $extension );
225 }
226
227 if ( $constraint === true &&
228 $this->abilities[$ability] !== true
229 ) {
230 // add custom error message for missing ability if specified
231 $customMessage = '';
232 if ( isset( $this->abilityErrors[$ability] ) ) {
233 $customMessage = ': ' . $this->abilityErrors[$ability];
234 }
235
236 $errors[] = [
237 'msg' =>
238 "{$extension} requires \"{$ability}\" ability"
239 . $customMessage
240 ,
241 'type' => 'missing-ability',
242 'missing' => $ability,
243 ];
244 }
245 } else {
246 // add other platform dependencies here
247 throw new UnexpectedValueException( 'Dependency type ' . $dependency .
248 ' unknown in ' . $extension );
249 }
250 }
251 break;
252 case 'extensions':
253 case 'skins':
254 foreach ( $values as $dependency => $constraint ) {
255 $extError = $this->handleExtensionDependency(
256 $dependency, $constraint, $extension, $dependencyType
257 );
258 if ( $extError !== false ) {
259 $errors[] = $extError;
260 }
261 }
262 break;
263 default:
264 throw new UnexpectedValueException( 'Dependency type ' . $dependencyType .
265 ' unknown in ' . $extension );
266 }
267 }
268 }
269
270 return $errors;
271 }
272
282 private function handleDependency( $version, $constraint, $checkedExt ) {
283 if ( $version === false ) {
284 // Couldn't parse the version, so we can't check anything
285 return false;
286 }
287
288 // if the installed and required version are compatible, return an empty array
289 if ( $this->versionParser->parseConstraints( $constraint )
290 ->matches( $version ) ) {
291 return false;
292 }
293
294 return true;
295 }
296
306 private function handleExtensionDependency( $dependencyName, $constraint, $checkedExt,
307 $type
308 ) {
309 // Check if the dependency is even installed
310 if ( !isset( $this->loaded[$dependencyName] ) ) {
311 return [
312 'msg' => "{$checkedExt} requires {$dependencyName} to be installed.",
313 'type' => "missing-$type",
314 'missing' => $dependencyName,
315 ];
316 }
317 if ( $constraint === '*' ) {
318 // short-circuit since any version is OK.
319 return false;
320 }
321 // Check if the dependency has specified a version
322 if ( !isset( $this->loaded[$dependencyName]['version'] ) ) {
323 $msg = "{$dependencyName} does not expose its version, but {$checkedExt}"
324 . " requires: {$constraint}.";
325 return [
326 'msg' => $msg,
327 'type' => "incompatible-$type",
328 'incompatible' => $checkedExt,
329 ];
330 } else {
331 // Try to get a constraint for the dependency version
332 try {
333 $installedVersion = new Constraint(
334 '==',
335 $this->versionParser->normalize( $this->loaded[$dependencyName]['version'] )
336 );
337 } catch ( UnexpectedValueException $e ) {
338 // Non-parsable version, output an error message that the version
339 // string is invalid
340 return [
341 'msg' => "$dependencyName does not have a valid version string.",
342 'type' => 'invalid-version',
343 ];
344 }
345 // Check if the constraint actually matches...
346 if (
347 !$this->versionParser->parseConstraints( $constraint )->matches( $installedVersion )
348 ) {
349 $msg = "{$checkedExt} is not compatible with the current "
350 . "installed version of {$dependencyName} "
351 . "({$this->loaded[$dependencyName]['version']}), "
352 . "it requires: " . $constraint . '.';
353 return [
354 'msg' => $msg,
355 'type' => "incompatible-$type",
356 'incompatible' => $checkedExt,
357 ];
358 }
359 }
360
361 return false;
362 }
363}
Provides functions to check a set of extensions with dependencies against a set of loaded extensions ...
handleExtensionDependency( $dependencyName, $constraint, $checkedExt, $type)
Handle a dependency to another extension.
Constraint bool $coreVersion
representing MediaWiki core
setLoadedExtensionsAndSkins(array $credits)
Set an array with credits of all loaded extensions and skins.
handleDependency( $version, $constraint, $checkedExt)
Handle a simple dependency to MediaWiki core or PHP.
checkArray(array $extDependencies)
Check all given dependencies if they are compatible with the named installed extensions in the $credi...
string[] $abilityErrors
List of provided ability errors.
Constraint bool $phpVersion
representing the PHP engine
array $loaded
Loaded extensions.
VersionParser $versionParser
setCoreVersion( $coreVersion)
Set MediaWiki core version.
setPhpVersion( $phpVersion)
Set PHP version.
__construct( $coreVersion, $phpVersion, array $phpExtensions, array $abilities=[], array $abilityErrors=[])
bool[] $abilities
List of provided abilities.
string[] $phpExtensions
List of installed PHP extensions.