cuddlefish.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. 'use strict';
  5. module.metadata = {
  6. "stability": "unstable"
  7. };
  8. // This module is manually loaded by bootstrap.js in a sandbox and immediatly
  9. // put in module cache so that it is never loaded in any other way.
  10. /* Workarounds to include dependencies in the manifest
  11. require('chrome') // Otherwise CFX will complain about Components
  12. require('toolkit/loader') // Otherwise CFX will stip out loader.js
  13. require('sdk/addon/runner') // Otherwise CFX will stip out addon/runner.js
  14. require('sdk/system/xul-app') // Otherwise CFX will stip out sdk/system/xul-app
  15. */
  16. const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
  17. // `loadSandbox` is exposed by bootstrap.js
  18. const loaderURI = module.uri.replace("sdk/loader/cuddlefish.js",
  19. "toolkit/loader.js");
  20. const xulappURI = module.uri.replace("loader/cuddlefish.js",
  21. "system/xul-app.js");
  22. // We need to keep a reference to the sandbox in order to unload it in
  23. // bootstrap.js
  24. const loaderSandbox = loadSandbox(loaderURI);
  25. const loaderModule = loaderSandbox.exports;
  26. const xulappSandbox = loadSandbox(xulappURI);
  27. const xulappModule = xulappSandbox.exports;
  28. const { override, load } = loaderModule;
  29. /**
  30. * Ensure the current application satisfied the requirements specified in the
  31. * module given. If not, an exception related to the incompatibility is
  32. * returned; `null` otherwise.
  33. *
  34. * @param {Object} module
  35. * The module to check
  36. * @returns {Error}
  37. */
  38. function incompatibility(module) {
  39. let { metadata, id } = module;
  40. // if metadata or engines are not specified we assume compatibility is not
  41. // an issue.
  42. if (!metadata || !("engines" in metadata))
  43. return null;
  44. let { engines } = metadata;
  45. if (engines === null || typeof(engines) !== "object")
  46. return new Error("Malformed engines' property in metadata");
  47. let applications = Object.keys(engines);
  48. let versionRange;
  49. applications.forEach(function(name) {
  50. if (xulappModule.is(name)) {
  51. versionRange = engines[name];
  52. // Continue iteration. We want to ensure the module doesn't
  53. // contain a typo in the applications' name or some unknown
  54. // application - `is` function throws an exception in that case.
  55. }
  56. });
  57. if (typeof(versionRange) === "string") {
  58. if (xulappModule.satisfiesVersion(versionRange))
  59. return null;
  60. return new Error("Unsupported Application version: The module " + id +
  61. " currently supports only version " + versionRange + " of " +
  62. xulappModule.name + ".");
  63. }
  64. return new Error("Unsupported Application: The module " + id +
  65. " currently supports only " + applications.join(", ") + ".")
  66. }
  67. function CuddlefishLoader(options) {
  68. let { manifest } = options;
  69. options = override(options, {
  70. // Put `api-utils/loader` and `api-utils/cuddlefish` loaded as JSM to module
  71. // cache to avoid subsequent loads via `require`.
  72. modules: override({
  73. 'toolkit/loader': loaderModule,
  74. 'sdk/loader/cuddlefish': exports,
  75. 'sdk/system/xul-app': xulappModule
  76. }, options.modules),
  77. resolve: function resolve(id, requirer) {
  78. let entry = requirer && requirer in manifest && manifest[requirer];
  79. let uri = null;
  80. // If manifest entry for this requirement is present we follow manifest.
  81. // Note: Standard library modules like 'panel' will be present in
  82. // manifest unless they were moved to platform.
  83. if (entry) {
  84. let requirement = entry.requirements[id];
  85. // If requirer entry is in manifest and it's requirement is not, than
  86. // it has no authority to load since linker was not able to find it.
  87. if (!requirement)
  88. throw Error('Module: ' + requirer + ' has no authority to load: '
  89. + id, requirer);
  90. uri = requirement;
  91. } else {
  92. // If requirer is off manifest than it's a system module and we allow it
  93. // to go off manifest by resolving a relative path.
  94. uri = loaderModule.resolve(id, requirer);
  95. }
  96. return uri;
  97. },
  98. load: function(loader, module) {
  99. let result;
  100. let error;
  101. // In order to get the module's metadata, we need to load the module.
  102. // if an exception is raised here, it could be that is due to application
  103. // incompatibility. Therefore the exception is stored, and thrown again
  104. // only if the module seems be compatible with the application currently
  105. // running. Otherwise the incompatibility message takes the precedence.
  106. try {
  107. result = load(loader, module);
  108. }
  109. catch (e) {
  110. error = e;
  111. }
  112. error = incompatibility(module) || error;
  113. if (error)
  114. throw error;
  115. return result;
  116. }
  117. });
  118. let loader = loaderModule.Loader(options);
  119. // Hack to allow loading from `toolkit/loader`.
  120. loader.modules[loaderURI] = loaderSandbox;
  121. return loader;
  122. }
  123. exports = override(loaderModule, {
  124. Loader: CuddlefishLoader
  125. });