diff -r 000000000000 -r 6474c204b198 addon-sdk/source/lib/sdk/loader/cuddlefish.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addon-sdk/source/lib/sdk/loader/cuddlefish.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,152 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +'use strict'; + +module.metadata = { + "stability": "unstable" +}; + +// This module is manually loaded by bootstrap.js in a sandbox and immediatly +// put in module cache so that it is never loaded in any other way. + +/* Workarounds to include dependencies in the manifest +require('chrome') // Otherwise CFX will complain about Components +require('toolkit/loader') // Otherwise CFX will stip out loader.js +require('sdk/addon/runner') // Otherwise CFX will stip out addon/runner.js +require('sdk/system/xul-app') // Otherwise CFX will stip out sdk/system/xul-app +*/ + +const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components; + +// `loadSandbox` is exposed by bootstrap.js +const loaderURI = module.uri.replace("sdk/loader/cuddlefish.js", + "toolkit/loader.js"); +const xulappURI = module.uri.replace("loader/cuddlefish.js", + "system/xul-app.js"); +// We need to keep a reference to the sandbox in order to unload it in +// bootstrap.js + +const loaderSandbox = loadSandbox(loaderURI); +const loaderModule = loaderSandbox.exports; + +const xulappSandbox = loadSandbox(xulappURI); +const xulappModule = xulappSandbox.exports; + +const { override, load } = loaderModule; + +/** + * Ensure the current application satisfied the requirements specified in the + * module given. If not, an exception related to the incompatibility is + * returned; `null` otherwise. + * + * @param {Object} module + * The module to check + * @returns {Error} + */ +function incompatibility(module) { + let { metadata, id } = module; + + // if metadata or engines are not specified we assume compatibility is not + // an issue. + if (!metadata || !("engines" in metadata)) + return null; + + let { engines } = metadata; + + if (engines === null || typeof(engines) !== "object") + return new Error("Malformed engines' property in metadata"); + + let applications = Object.keys(engines); + + let versionRange; + applications.forEach(function(name) { + if (xulappModule.is(name)) { + versionRange = engines[name]; + // Continue iteration. We want to ensure the module doesn't + // contain a typo in the applications' name or some unknown + // application - `is` function throws an exception in that case. + } + }); + + if (typeof(versionRange) === "string") { + if (xulappModule.satisfiesVersion(versionRange)) + return null; + + return new Error("Unsupported Application version: The module " + id + + " currently supports only version " + versionRange + " of " + + xulappModule.name + "."); + } + + return new Error("Unsupported Application: The module " + id + + " currently supports only " + applications.join(", ") + ".") +} + +function CuddlefishLoader(options) { + let { manifest } = options; + + options = override(options, { + // Put `api-utils/loader` and `api-utils/cuddlefish` loaded as JSM to module + // cache to avoid subsequent loads via `require`. + modules: override({ + 'toolkit/loader': loaderModule, + 'sdk/loader/cuddlefish': exports, + 'sdk/system/xul-app': xulappModule + }, options.modules), + resolve: function resolve(id, requirer) { + let entry = requirer && requirer in manifest && manifest[requirer]; + let uri = null; + + // If manifest entry for this requirement is present we follow manifest. + // Note: Standard library modules like 'panel' will be present in + // manifest unless they were moved to platform. + if (entry) { + let requirement = entry.requirements[id]; + // If requirer entry is in manifest and it's requirement is not, than + // it has no authority to load since linker was not able to find it. + if (!requirement) + throw Error('Module: ' + requirer + ' has no authority to load: ' + + id, requirer); + + uri = requirement; + } else { + // If requirer is off manifest than it's a system module and we allow it + // to go off manifest by resolving a relative path. + uri = loaderModule.resolve(id, requirer); + } + return uri; + }, + load: function(loader, module) { + let result; + let error; + + // In order to get the module's metadata, we need to load the module. + // if an exception is raised here, it could be that is due to application + // incompatibility. Therefore the exception is stored, and thrown again + // only if the module seems be compatible with the application currently + // running. Otherwise the incompatibility message takes the precedence. + try { + result = load(loader, module); + } + catch (e) { + error = e; + } + + error = incompatibility(module) || error; + + if (error) + throw error; + + return result; + } + }); + + let loader = loaderModule.Loader(options); + // Hack to allow loading from `toolkit/loader`. + loader.modules[loaderURI] = loaderSandbox; + return loader; +} + +exports = override(loaderModule, { + Loader: CuddlefishLoader +});