"description": "MediaWiki extension.json schema",
"type": "object",
"properties": {
+ "manifest_version": {
+ "type": "integer",
+ "description": "Version of the extension.json schema the extension.json file is in.",
+ "required": true
+ },
"name": {
"type": "string",
"description": "The extension's canonical name.",
'config',
'ParserTestFiles',
'AutoloadClasses',
+ 'manifest_version',
);
/**
/**
* @param string $path
* @param array $info
+ * @param int $version manifest_version for info
* @return array
*/
- public function extractInfo( $path, array $info ) {
+ public function extractInfo( $path, array $info, $version ) {
$this->extractConfig( $info );
$this->extractHooks( $info );
$dir = dirname( $path );
*/
class ExtensionRegistry {
+ /**
+ * Version of the highest supported manifest version
+ */
+ const MANIFEST_VERSION = 1;
+
+ /**
+ * Version of the oldest supported manifest version
+ */
+ const OLDEST_MANIFEST_VERSION = 1;
+
/**
* @var BagOStuff
*/
if ( !is_array( $info ) ) {
throw new Exception( "$path is not a valid JSON file." );
}
+ if ( !isset( $info['manifest_version' ] ) ) {
+ // For backwards-compatability, assume a version of 1
+ $info['manifest_version'] = 1;
+ }
+ $version = $info['manifest_version'];
+ if ( $version < self::OLDEST_MANIFEST_VERSION || $version > self::MANIFEST_VERSION ) {
+ throw new Exception( "$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;
- $processor->extractInfo( $path, $info );
+ $processor->extractInfo( $path, $info, $version );
}
$data = $processor->getExtractedInfo();
// Need to set this so we can += to it later
*
* @param string $path Absolute path of JSON file
* @param array $info
+ * @param int $version manifest_version for info
* @return array "credits" information to store
*/
- public function extractInfo( $path, array $info );
+ public function extractInfo( $path, array $info, $version );
/**
* @return array With following keys:
}
}
$out += $this->json;
-
+ // Put this at the bottom
+ $out['manifest_version'] = ExtensionRegistry::MANIFEST_VERSION;
$type = $this->hasOption( 'skin' ) ? 'skin' : 'extension';
$fname = "{$this->dir}/$type.json";
$prettyJSON = FormatJson::encode( $out, "\t", FormatJson::ALL_OK );
$this->error( 'The JsonSchema library cannot be found, please install it through composer.', 1 );
}
- $retriever = new JsonSchema\Uri\UriRetriever();
- $schema = $retriever->retrieve('file://' . dirname( __DIR__ ) . '/docs/extension.schema.json' );
$path = $this->getArg( 0 );
$data = json_decode( file_get_contents( $path ) );
if ( !is_object( $data ) ) {
$this->error( "$path is not a valid JSON file.", 1 );
}
+ if ( !isset( $data->manifest_version ) ) {
+ $this->output("Warning: No manifest_version set, assuming 1.\n" );
+ // For backwards-compatability assume 1
+ $data->manifest_version = 1;
+ }
+ $version = $data->manifest_version;
+ if ( $version !== ExtensionRegistry::MANIFEST_VERSION ) {
+ $schemaPath = dirname( __DIR__ ) . "/docs/extension.schema.v$version.json";
+ } else {
+ $schemaPath = dirname( __DIR__ ) . '/docs/extension.schema.json';
+ }
+
+ if ( $version < ExtensionRegistry::OLDEST_MANIFEST_VERSION
+ || $version > ExtensionRegistry::MANIFEST_VERSION
+ ) {
+ $this->error( "Error: $path is using a non-supported schema version, it should use "
+ . ExtensionRegistry::MANIFEST_VERSION, 1 );
+ } elseif ( $version < ExtensionRegistry::MANIFEST_VERSION ) {
+ $this->output( "Warning: $path is using a deprecated schema, and should be updated to "
+ . ExtensionRegistry::MANIFEST_VERSION . "\n" );
+ }
+ $retriever = new JsonSchema\Uri\UriRetriever();
+ $schema = $retriever->retrieve('file://' . $schemaPath );
$validator = new JsonSchema\Validator();
$validator->check( $data, $schema );
if ( $validator->isValid() ) {
- $this->output( "$path validates against the schema!\n" );
+ $this->output( "$path validates against the version $version schema!\n" );
} else {
foreach ( $validator->getErrors() as $error ) {
$this->output( "[{$error['property']}] {$error['message']}\n" );
'@metadata' => array( 'foobarbaz' ),
'AnAttribute' => array( 'omg' ),
'AutoloadClasses' => array( 'FooBar' => 'includes/FooBar.php' ),
- ) );
+ ), 1 );
$extracted = $processor->getExtractedInfo();
$attributes = $extracted['attributes'];
*/
public function testRegisterHooks( $pre, $info, $expected ) {
$processor = new MockExtensionProcessor( array( 'wgHooks' => $pre ) );
- $processor->extractInfo( $this->dir, $info );
+ $processor->extractInfo( $this->dir, $info, 1 );
$extracted = $processor->getExtractedInfo();
$this->assertEquals( $expected, $extracted['globals']['wgHooks'] );
}
'@IGNORED' => 'yes',
),
) + self::$default;
- $processor->extractInfo( $this->dir, $info );
+ $processor->extractInfo( $this->dir, $info, 1 );
$extracted = $processor->getExtractedInfo();
$this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
$this->assertEquals( 10, $extracted['globals']['wgFoo'] );
*/
public function testExtracttExtensionMessagesFiles( $input, $expected ) {
$processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default );
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
$out = $processor->getExtractedInfo();
foreach ( $expected as $key => $value ) {
$this->assertEquals( $value, $out['globals'][$key] );
*/
public function testExtractMessagesDirs( $input, $expected ) {
$processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default );
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
$out = $processor->getExtractedInfo();
foreach ( $expected as $key => $value ) {
$this->assertEquals( $value, $out['globals'][$key] );
*/
public function testExtractResourceLoaderModules( $input, $expected ) {
$processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default );
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
$out = $processor->getExtractedInfo();
foreach ( $expected as $key => $value ) {
$this->assertEquals( $value, $out['globals'][$key] );