'AutoLoader' => __DIR__ . '/includes/AutoLoader.php',
'AutoloadGenerator' => __DIR__ . '/includes/utils/AutoloadGenerator.php',
'Autopromote' => __DIR__ . '/includes/Autopromote.php',
+ 'AvroValidator' => __DIR__ . '/includes/utils/AvroValidator.php',
'BacklinkCache' => __DIR__ . '/includes/cache/BacklinkCache.php',
'BacklinkJobUtils' => __DIR__ . '/includes/jobqueue/utils/BacklinkJobUtils.php',
'BackupDumper' => __DIR__ . '/maintenance/backup.inc',
'CopyJobQueue' => __DIR__ . '/maintenance/copyJobQueue.php',
'CoreParserFunctions' => __DIR__ . '/includes/parser/CoreParserFunctions.php',
'CoreTagHooks' => __DIR__ . '/includes/parser/CoreTagHooks.php',
+ 'CoreVersionChecker' => __DIR__ . '/includes/registration/CoreVersionChecker.php',
'CreateAndPromote' => __DIR__ . '/maintenance/createAndPromote.php',
'CreateFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'CreditsAction' => __DIR__ . '/includes/actions/CreditsAction.php',
'MWOldPassword' => __DIR__ . '/includes/password/MWOldPassword.php',
'MWSaltedPassword' => __DIR__ . '/includes/password/MWSaltedPassword.php',
'MWTidy' => __DIR__ . '/includes/parser/MWTidy.php',
- 'MWTidyWrapper' => __DIR__ . '/includes/parser/MWTidy.php',
'MWTimestamp' => __DIR__ . '/includes/MWTimestamp.php',
'MachineReadableRCFeedFormatter' => __DIR__ . '/includes/rcfeed/MachineReadableRCFeedFormatter.php',
'MagicWord' => __DIR__ . '/includes/MagicWord.php',
'MediaWiki\\Logger\\LegacySpi' => __DIR__ . '/includes/debug/logger/LegacySpi.php',
'MediaWiki\\Logger\\LoggerFactory' => __DIR__ . '/includes/debug/logger/LoggerFactory.php',
'MediaWiki\\Logger\\MonologSpi' => __DIR__ . '/includes/debug/logger/MonologSpi.php',
+ 'MediaWiki\\Logger\\Monolog\\AvroFormatter' => __DIR__ . '/includes/debug/logger/monolog/AvroFormatter.php',
+ 'MediaWiki\\Logger\\Monolog\\BufferHandler' => __DIR__ . '/includes/debug/logger/monolog/BufferHandler.php',
+ 'MediaWiki\\Logger\\Monolog\\KafkaHandler' => __DIR__ . '/includes/debug/logger/monolog/KafkaHandler.php',
'MediaWiki\\Logger\\Monolog\\LegacyFormatter' => __DIR__ . '/includes/debug/logger/monolog/LegacyFormatter.php',
'MediaWiki\\Logger\\Monolog\\LegacyHandler' => __DIR__ . '/includes/debug/logger/monolog/LegacyHandler.php',
'MediaWiki\\Logger\\Monolog\\LineFormatter' => __DIR__ . '/includes/debug/logger/monolog/LineFormatter.php',
'MediaWiki\\Logger\\Monolog\\WikiProcessor' => __DIR__ . '/includes/debug/logger/monolog/WikiProcessor.php',
'MediaWiki\\Logger\\NullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php',
'MediaWiki\\Logger\\Spi' => __DIR__ . '/includes/debug/logger/Spi.php',
+ 'MediaWiki\\Tidy\\Html5Depurate' => __DIR__ . '/includes/tidy/Html5Depurate.php',
+ 'MediaWiki\\Tidy\\RaggettBase' => __DIR__ . '/includes/tidy/RaggettBase.php',
+ 'MediaWiki\\Tidy\\RaggettExternal' => __DIR__ . '/includes/tidy/RaggettExternal.php',
+ 'MediaWiki\\Tidy\\RaggettInternalHHVM' => __DIR__ . '/includes/tidy/RaggettInternalHHVM.php',
+ 'MediaWiki\\Tidy\\RaggettInternalPHP' => __DIR__ . '/includes/tidy/RaggettInternalPHP.php',
+ 'MediaWiki\\Tidy\\RaggettWrapper' => __DIR__ . '/includes/tidy/RaggettWrapper.php',
+ 'MediaWiki\\Tidy\\TidyDriverBase' => __DIR__ . '/includes/tidy/TidyDriverBase.php',
'MediaWiki\\Widget\\ComplexNamespaceInputWidget' => __DIR__ . '/includes/widget/ComplexNamespaceInputWidget.php',
+ 'MediaWiki\\Widget\\ComplexTitleInputWidget' => __DIR__ . '/includes/widget/ComplexTitleInputWidget.php',
'MediaWiki\\Widget\\NamespaceInputWidget' => __DIR__ . '/includes/widget/NamespaceInputWidget.php',
'MediaWiki\\Widget\\TitleInputWidget' => __DIR__ . '/includes/widget/TitleInputWidget.php',
'MediaWiki\\Widget\\UserInputWidget' => __DIR__ . '/includes/widget/UserInputWidget.php',
"wiki": "https://www.mediawiki.org/"
},
"require": {
+ "composer/semver": "0.1.0",
"cssjanus/cssjanus": "1.1.1",
"ext-iconv": "*",
- "leafo/lessphp": "0.5.0",
"liuggio/statsd-php-client": "1.0.16",
- "mediawiki/at-ease": "1.0.0",
- "oojs/oojs-ui": "0.12.6",
+ "oyejorge/less.php": "1.7.0.5",
+ "mediawiki/at-ease": "1.1.0",
+ "oojs/oojs-ui": "0.12.8.1",
"php": ">=5.3.3",
"psr/log": "1.0.0",
"wikimedia/assert": "0.2.2",
- "wikimedia/cdb": "1.0.1",
+ "wikimedia/cdb": "1.3.0",
"wikimedia/composer-merge-plugin": "1.2.1",
"wikimedia/ip-set": "1.0.1",
- "wikimedia/utfnormal": "1.0.2",
+ "wikimedia/utfnormal": "1.0.3",
"wikimedia/wrappedstring": "2.0.0",
"zordius/lightncandy": "0.21"
},
"ext-wikidiff2": "Diff accelerator",
"ext-apc": "Local data and opcode cache",
"monolog/monolog": "Flexible debug logging system",
+ "nmred/kafka-php": "Send debug log events to kafka",
"pear/mail": "Mail sending support",
"pear/mail_mime": "Mail sending support",
- "pear/mail_mime-decode": "Mail sending support"
+ "pear/mail_mime-decode": "Mail sending support",
+ "wikimedia/avro": "Binary serialization format used with kafka"
},
"autoload": {
"psr-0": {
"Unlicense"
]
},
+ "requires": {
+ "type": "object",
+ "description": "Indicates what versions of MediaWiki core are required. This syntax may be extended in the future, for example to check dependencies between other extensions.",
+ "properties": {
+ "MediaWiki": {
+ "type": "string",
+ "description": "Version constraint string against MediaWiki core."
+ }
+ }
+ },
"ResourceFileModulePaths": {
"type": "object",
"description": "Default paths to use for all ResourceLoader file modules",
"type": "object",
"description": "ResourceLoader LESS variables"
},
- "ResourceLoaderLESSFunctions": {
- "type": "object",
- "description": "ResourceLoader LESS functions"
- },
"ResourceLoaderLESSImportPaths": {
"type": "object",
"description": "ResourceLoader import paths"
"config": {
"type": "object",
"description": "Configuration options for this extension",
+ "properties": {
+ "_prefix": {
+ "type": "string",
+ "default": "wg",
+ "description": "Prefix to put in front of configuration settings when exporting them to $GLOBALS"
+ }
+ },
"patternProperties": {
"^[a-zA-Z_\u007f-\u00ff][a-zA-Z0-9_\u007f-\u00ff]*$": {
"type": ["object", "array", "string", "integer", "null", "boolean"],
*
* @param string $ext Name of the extension to load
* @param string|null $path Absolute path of where to find the extension.json file
+ * @since 1.25
*/
function wfLoadExtension( $ext, $path = null ) {
if ( !$path ) {
*
* @see wfLoadExtension
* @param string[] $exts Array of extension names to load
+ * @since 1.25
*/
function wfLoadExtensions( array $exts ) {
global $wgExtensionDirectory;
* @see wfLoadExtension
* @param string $skin Name of the extension to load
* @param string|null $path Absolute path of where to find the skin.json file
+ * @since 1.25
*/
function wfLoadSkin( $skin, $path = null ) {
if ( !$path ) {
*
* @see wfLoadExtensions
* @param string[] $skins Array of extension names to load
+ * @since 1.25
*/
function wfLoadSkins( array $skins ) {
global $wgStyleDirectory;
$wgDisableOutputCompression = true;
}
while ( $status = ob_get_status() ) {
- if ( $status['type'] == 0 /* PHP_OUTPUT_HANDLER_INTERNAL */ ) {
- // Probably from zlib.output_compression or other
- // PHP-internal setting which can't be removed.
- //
+ if ( isset( $status['flags'] ) ) {
+ $flags = PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_REMOVABLE;
+ $deleteable = ( $status['flags'] & $flags ) === $flags;
+ } elseif ( isset( $status['del'] ) ) {
+ $deleteable = $status['del'];
+ } else {
+ // Guess that any PHP-internal setting can't be removed.
+ $deleteable = $status['type'] !== 0; /* PHP_OUTPUT_HANDLER_INTERNAL */
+ }
+ if ( !$deleteable ) {
// Give up, and hope the result doesn't break
// output behavior.
break;
}
+ if ( $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier' ) {
+ // Unit testing barrier to prevent this function from breaking PHPUnit.
+ break;
+ }
if ( !ob_end_clean() ) {
// Could not remove output buffer handler; abort now
// to avoid getting in some kind of infinite loop.
*
* @see perldoc -f use
*
+ * @deprecated since 1.26, use the "requires' property of extension.json
* @param string|int|float $req_ver The version to check, can be a string, an integer, or a float
* @throws MWException
*/
return true;
}
+
+/**
+ * Merges two (possibly) 2 dimensional arrays into the target array ($baseArray).
+ *
+ * Values that exist in both values will be combined with += (all values of the array
+ * of $newValues will be added to the values of the array of $baseArray, while values,
+ * that exists in both, the value of $baseArray will be used).
+ *
+ * @param array $baseArray The array where you want to add the values of $newValues to
+ * @param array $newValues An array with new values
+ * @return array The combined array
+ * @since 1.26
+ */
+function wfArrayPlus2d( array $baseArray, array $newValues ) {
+ // First merge items that are in both arrays
+ foreach ( $baseArray as $name => &$groupVal ) {
+ if ( isset( $newValues[$name] ) ) {
+ $groupVal += $newValues[$name];
+ }
+ }
+ // Now add items that didn't exist yet
+ $baseArray += $newValues;
+
+ return $baseArray;
+}
);
}
+ 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 ) {
*/
protected function extractConfig( array $info ) {
if ( isset( $info['config'] ) ) {
+ if ( isset( $info['config']['_prefix'] ) ) {
+ $prefix = $info['config']['_prefix'];
+ unset( $info['config']['_prefix'] );
+ } else {
+ $prefix = 'wg';
+ }
foreach ( $info['config'] as $key => $val ) {
if ( $key[0] !== '@' ) {
- $this->globals["wg$key"] = $val;
+ $this->globals["$prefix$key"] = $val;
}
}
}
*/
class ExtensionRegistry {
+ /**
+ * "requires" key that applies to MediaWiki core/$wgVersion
+ */
+ const MEDIAWIKI_CORE = 'MediaWiki';
+
/**
* Version of the highest supported manifest version
*/
* @throws Exception
*/
public function readFromQueue( array $queue ) {
+ 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 ) {
// Set up the autoloader now so custom processors will work
$GLOBALS['wgAutoloadClasses'] += $autoload;
$autoloadClasses += $autoload;
+ // 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
$data['globals']['wgAutoloadClasses'] = array();
$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 + $GLOBALS[$key];
+ $GLOBALS[$key] += $val;
break;
case 'array_merge':
$GLOBALS[$key] = array_merge( $val, $GLOBALS[$key] );