1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/loader/cuddlefish.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,152 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +'use strict'; 1.8 + 1.9 +module.metadata = { 1.10 + "stability": "unstable" 1.11 +}; 1.12 + 1.13 +// This module is manually loaded by bootstrap.js in a sandbox and immediatly 1.14 +// put in module cache so that it is never loaded in any other way. 1.15 + 1.16 +/* Workarounds to include dependencies in the manifest 1.17 +require('chrome') // Otherwise CFX will complain about Components 1.18 +require('toolkit/loader') // Otherwise CFX will stip out loader.js 1.19 +require('sdk/addon/runner') // Otherwise CFX will stip out addon/runner.js 1.20 +require('sdk/system/xul-app') // Otherwise CFX will stip out sdk/system/xul-app 1.21 +*/ 1.22 + 1.23 +const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components; 1.24 + 1.25 +// `loadSandbox` is exposed by bootstrap.js 1.26 +const loaderURI = module.uri.replace("sdk/loader/cuddlefish.js", 1.27 + "toolkit/loader.js"); 1.28 +const xulappURI = module.uri.replace("loader/cuddlefish.js", 1.29 + "system/xul-app.js"); 1.30 +// We need to keep a reference to the sandbox in order to unload it in 1.31 +// bootstrap.js 1.32 + 1.33 +const loaderSandbox = loadSandbox(loaderURI); 1.34 +const loaderModule = loaderSandbox.exports; 1.35 + 1.36 +const xulappSandbox = loadSandbox(xulappURI); 1.37 +const xulappModule = xulappSandbox.exports; 1.38 + 1.39 +const { override, load } = loaderModule; 1.40 + 1.41 +/** 1.42 + * Ensure the current application satisfied the requirements specified in the 1.43 + * module given. If not, an exception related to the incompatibility is 1.44 + * returned; `null` otherwise. 1.45 + * 1.46 + * @param {Object} module 1.47 + * The module to check 1.48 + * @returns {Error} 1.49 + */ 1.50 +function incompatibility(module) { 1.51 + let { metadata, id } = module; 1.52 + 1.53 + // if metadata or engines are not specified we assume compatibility is not 1.54 + // an issue. 1.55 + if (!metadata || !("engines" in metadata)) 1.56 + return null; 1.57 + 1.58 + let { engines } = metadata; 1.59 + 1.60 + if (engines === null || typeof(engines) !== "object") 1.61 + return new Error("Malformed engines' property in metadata"); 1.62 + 1.63 + let applications = Object.keys(engines); 1.64 + 1.65 + let versionRange; 1.66 + applications.forEach(function(name) { 1.67 + if (xulappModule.is(name)) { 1.68 + versionRange = engines[name]; 1.69 + // Continue iteration. We want to ensure the module doesn't 1.70 + // contain a typo in the applications' name or some unknown 1.71 + // application - `is` function throws an exception in that case. 1.72 + } 1.73 + }); 1.74 + 1.75 + if (typeof(versionRange) === "string") { 1.76 + if (xulappModule.satisfiesVersion(versionRange)) 1.77 + return null; 1.78 + 1.79 + return new Error("Unsupported Application version: The module " + id + 1.80 + " currently supports only version " + versionRange + " of " + 1.81 + xulappModule.name + "."); 1.82 + } 1.83 + 1.84 + return new Error("Unsupported Application: The module " + id + 1.85 + " currently supports only " + applications.join(", ") + ".") 1.86 +} 1.87 + 1.88 +function CuddlefishLoader(options) { 1.89 + let { manifest } = options; 1.90 + 1.91 + options = override(options, { 1.92 + // Put `api-utils/loader` and `api-utils/cuddlefish` loaded as JSM to module 1.93 + // cache to avoid subsequent loads via `require`. 1.94 + modules: override({ 1.95 + 'toolkit/loader': loaderModule, 1.96 + 'sdk/loader/cuddlefish': exports, 1.97 + 'sdk/system/xul-app': xulappModule 1.98 + }, options.modules), 1.99 + resolve: function resolve(id, requirer) { 1.100 + let entry = requirer && requirer in manifest && manifest[requirer]; 1.101 + let uri = null; 1.102 + 1.103 + // If manifest entry for this requirement is present we follow manifest. 1.104 + // Note: Standard library modules like 'panel' will be present in 1.105 + // manifest unless they were moved to platform. 1.106 + if (entry) { 1.107 + let requirement = entry.requirements[id]; 1.108 + // If requirer entry is in manifest and it's requirement is not, than 1.109 + // it has no authority to load since linker was not able to find it. 1.110 + if (!requirement) 1.111 + throw Error('Module: ' + requirer + ' has no authority to load: ' 1.112 + + id, requirer); 1.113 + 1.114 + uri = requirement; 1.115 + } else { 1.116 + // If requirer is off manifest than it's a system module and we allow it 1.117 + // to go off manifest by resolving a relative path. 1.118 + uri = loaderModule.resolve(id, requirer); 1.119 + } 1.120 + return uri; 1.121 + }, 1.122 + load: function(loader, module) { 1.123 + let result; 1.124 + let error; 1.125 + 1.126 + // In order to get the module's metadata, we need to load the module. 1.127 + // if an exception is raised here, it could be that is due to application 1.128 + // incompatibility. Therefore the exception is stored, and thrown again 1.129 + // only if the module seems be compatible with the application currently 1.130 + // running. Otherwise the incompatibility message takes the precedence. 1.131 + try { 1.132 + result = load(loader, module); 1.133 + } 1.134 + catch (e) { 1.135 + error = e; 1.136 + } 1.137 + 1.138 + error = incompatibility(module) || error; 1.139 + 1.140 + if (error) 1.141 + throw error; 1.142 + 1.143 + return result; 1.144 + } 1.145 + }); 1.146 + 1.147 + let loader = loaderModule.Loader(options); 1.148 + // Hack to allow loading from `toolkit/loader`. 1.149 + loader.modules[loaderURI] = loaderSandbox; 1.150 + return loader; 1.151 +} 1.152 + 1.153 +exports = override(loaderModule, { 1.154 + Loader: CuddlefishLoader 1.155 +});