/**
* Version of the highest supported manifest version
+ * Note: Update MANIFEST_VERSION_MW_VERSION when changing this
*/
const MANIFEST_VERSION = 2;
+ /**
+ * MediaWiki version constraint representing what the current
+ * highest MANIFEST_VERSION is supported in
+ */
+ const MANIFEST_VERSION_MW_VERSION = '>= 1.29.0';
+
/**
* Version of the oldest supported manifest version
*/
private static $instance;
/**
+ * @codeCoverageIgnore
* @return ExtensionRegistry
*/
public static function getInstance() {
} else {
throw new Exception( "$path does not exist!" );
}
+ // @codeCoverageIgnoreStart
if ( !$mtime ) {
$err = error_get_last();
throw new Exception( "Couldn't stat $path: {$err['message']}" );
+ // @codeCoverageIgnoreEnd
}
}
$this->queued[$path] = $mtime;
public function readFromQueue( array $queue ) {
global $wgVersion;
$autoloadClasses = [];
+ $autoloadNamespaces = [];
$autoloaderPaths = [];
$processor = new ExtensionProcessor();
$versionChecker = new VersionChecker( $wgVersion );
$incompatible[] = "$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;
+ $dir = dirname( $path );
+ if ( isset( $info['AutoloadClasses'] ) ) {
+ $autoload = $this->processAutoLoader( $dir, $info['AutoloadClasses'] );
+ $GLOBALS['wgAutoloadClasses'] += $autoload;
+ $autoloadClasses += $autoload;
+ }
+ if ( isset( $info['AutoloadNamespaces'] ) ) {
+ $autoloadNamespaces += $this->processAutoLoader( $dir, $info['AutoloadNamespaces'] );
+ }
// get all requirements/dependencies for this extension
$requires = $processor->getRequirements( $info );
// Get extra paths for later inclusion
$autoloaderPaths = array_merge( $autoloaderPaths,
- $processor->getExtraAutoloaderPaths( dirname( $path ), $info ) );
+ $processor->getExtraAutoloaderPaths( $dir, $info ) );
// Compatible, read and extract info
$processor->extractInfo( $path, $info, $version );
}
$data['globals']['wgAutoloadClasses'] = [];
$data['autoload'] = $autoloadClasses;
$data['autoloaderPaths'] = $autoloaderPaths;
+ $data['autoloaderNS'] = $autoloadNamespaces;
return $data;
}
// Optimistic: If the global is not set, or is an empty array, replace it entirely.
// Will be O(1) performance.
- if ( !isset( $GLOBALS[$key] ) || ( is_array( $GLOBALS[$key] ) && !$GLOBALS[$key] ) ) {
+ if ( !array_key_exists( $key, $GLOBALS ) || ( is_array( $GLOBALS[$key] ) && !$GLOBALS[$key] ) ) {
$GLOBALS[$key] = $val;
continue;
}
}
}
+ if ( isset( $info['autoloaderNS'] ) ) {
+ AutoLoader::$psr4Namespaces += $info['autoloaderNS'];
+ }
+
foreach ( $info['defines'] as $name => $val ) {
define( $name, $val );
}
foreach ( $info['autoloaderPaths'] as $path ) {
- require_once $path;
+ if ( file_exists( $path ) ) {
+ require_once $path;
+ }
}
$this->loaded += $info['credits'];
}
/**
- * Mark a thing as loaded
- *
- * @param string $name
- * @param array $credits
- */
- protected function markLoaded( $name, array $credits ) {
- $this->loaded[$name] = $credits;
- }
-
- /**
- * Register classes with the autoloader
+ * Fully expand autoloader paths
*
* @param string $dir
- * @param array $info
+ * @param array $files
* @return array
*/
- protected function processAutoLoader( $dir, array $info ) {
- if ( isset( $info['AutoloadClasses'] ) ) {
- // Make paths absolute, relative to the JSON file
- return array_map( function ( $file ) use ( $dir ) {
- return "$dir/$file";
- }, $info['AutoloadClasses'] );
- } else {
- return [];
+ protected function processAutoLoader( $dir, array $files ) {
+ // Make paths absolute, relative to the JSON file
+ foreach ( $files as &$file ) {
+ $file = "$dir/$file";
}
+ return $files;
}
}