addon-sdk/source/lib/sdk/loader/cuddlefish.js

changeset 0
6474c204b198
     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 +});

mercurial