diff options
Diffstat (limited to 'toolkit/jetpack/sdk/addon/runner.js')
-rw-r--r-- | toolkit/jetpack/sdk/addon/runner.js | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/toolkit/jetpack/sdk/addon/runner.js b/toolkit/jetpack/sdk/addon/runner.js new file mode 100644 index 000000000..3977a04e4 --- /dev/null +++ b/toolkit/jetpack/sdk/addon/runner.js @@ -0,0 +1,180 @@ +/* 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/. */ + +module.metadata = { + "stability": "experimental" +}; + +const { Cc, Ci, Cu } = require('chrome'); +const { rootURI, metadata, isNative } = require('@loader/options'); +const { id, loadReason } = require('../self'); +const { descriptor, Sandbox, evaluate, main, resolveURI } = require('toolkit/loader'); +const { once } = require('../system/events'); +const { exit, env, staticArgs } = require('../system'); +const { when: unload } = require('../system/unload'); +const globals = require('../system/globals'); +const xulApp = require('../system/xul-app'); +const { get } = require('../preferences/service'); +const appShellService = Cc['@mozilla.org/appshell/appShellService;1']. + getService(Ci.nsIAppShellService); +const { preferences } = metadata; + +const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function () { + return Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {}). + BrowserToolboxProcess; +}); + +// Initializes default preferences +function setDefaultPrefs(prefsURI) { + const prefs = Cc['@mozilla.org/preferences-service;1']. + getService(Ci.nsIPrefService). + QueryInterface(Ci.nsIPrefBranch2); + const branch = prefs.getDefaultBranch(''); + const sandbox = Sandbox({ + name: prefsURI, + prototype: { + pref: function(key, val) { + switch (typeof val) { + case 'boolean': + branch.setBoolPref(key, val); + break; + case 'number': + if (val % 1 == 0) // number must be a integer, otherwise ignore it + branch.setIntPref(key, val); + break; + case 'string': + branch.setCharPref(key, val); + break; + } + } + } + }); + // load preferences. + evaluate(sandbox, prefsURI); +} + +function definePseudo(loader, id, exports) { + let uri = resolveURI(id, loader.mapping); + loader.modules[uri] = { exports: exports }; +} + +function startup(reason, options) { + return Startup.onceInitialized.then(() => { + // Inject globals ASAP in order to have console API working ASAP + Object.defineProperties(options.loader.globals, descriptor(globals)); + + // NOTE: Module is intentionally required only now because it relies + // on existence of hidden window, which does not exists until startup. + let { ready } = require('../addon/window'); + // Load localization manifest and .properties files. + // Run the addon even in case of error (best effort approach) + require('../l10n/loader'). + load(rootURI). + then(null, function failure(error) { + if (!isNative) + console.info("Error while loading localization: " + error.message); + }). + then(function onLocalizationReady(data) { + // Exports data to a pseudo module so that api-utils/l10n/core + // can get access to it + definePseudo(options.loader, '@l10n/data', data ? data : null); + return ready; + }).then(function() { + run(options); + }).then(null, console.exception); + return void 0; // otherwise we raise a warning, see bug 910304 + }); +} + +function run(options) { + try { + // Try initializing HTML localization before running main module. Just print + // an exception in case of error, instead of preventing addon to be run. + try { + // Do not enable HTML localization while running test as it is hard to + // disable. Because unit tests are evaluated in a another Loader who + // doesn't have access to this current loader. + if (options.main !== 'sdk/test/runner') { + require('../l10n/html').enable(); + } + } + catch(error) { + console.exception(error); + } + + // native-options does stuff directly with preferences key from package.json + if (preferences && preferences.length > 0) { + try { + require('../preferences/native-options'). + enable({ preferences: preferences, id: id }). + catch(console.exception); + } + catch (error) { + console.exception(error); + } + } + else { + // keeping support for addons packaged with older SDK versions, + // when cfx didn't include the 'preferences' key in @loader/options + + // Initialize inline options localization, without preventing addon to be + // run in case of error + try { + require('../l10n/prefs').enable(); + } + catch(error) { + console.exception(error); + } + + // TODO: When bug 564675 is implemented this will no longer be needed + // Always set the default prefs, because they disappear on restart + if (options.prefsURI) { + // Only set if `prefsURI` specified + try { + setDefaultPrefs(options.prefsURI); + } + catch (err) { + // cfx bootstrap always passes prefsURI, even in addons without prefs + } + } + } + + // this is where the addon's main.js finally run. + let program = main(options.loader, options.main); + + if (typeof(program.onUnload) === 'function') + unload(program.onUnload); + + if (typeof(program.main) === 'function') { + program.main({ + loadReason: loadReason, + staticArgs: staticArgs + }, { + print: function print(_) { dump(_ + '\n') }, + quit: exit + }); + } + + if (get("extensions." + id + ".sdk.debug.show", false)) { + BrowserToolboxProcess.init({ addonID: id }); + } + } catch (error) { + console.exception(error); + throw error; + } +} +exports.startup = startup; + +// If add-on is lunched via `cfx run` we need to use `system.exit` to let +// cfx know we're done (`cfx test` will take care of exit so we don't do +// anything here). +if (env.CFX_COMMAND === 'run') { + unload(function(reason) { + if (reason === 'shutdown') + exit(0); + }); +} |