diff options
Diffstat (limited to 'addon-sdk/source/lib/sdk/addon')
-rw-r--r-- | addon-sdk/source/lib/sdk/addon/bootstrap.js | 182 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/addon/events.js | 56 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/addon/host.js | 12 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/addon/installer.js | 121 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/addon/manager.js | 18 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/addon/runner.js | 180 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/addon/window.js | 66 |
7 files changed, 0 insertions, 635 deletions
diff --git a/addon-sdk/source/lib/sdk/addon/bootstrap.js b/addon-sdk/source/lib/sdk/addon/bootstrap.js deleted file mode 100644 index 0397d91e5..000000000 --- a/addon-sdk/source/lib/sdk/addon/bootstrap.js +++ /dev/null @@ -1,182 +0,0 @@ -/* 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"; - -const { Cu } = require("chrome"); -const { NetUtil } = require("resource://gre/modules/NetUtil.jsm"); -const { Task: { spawn } } = require("resource://gre/modules/Task.jsm"); -const { readURI } = require("sdk/net/url"); -const { mount, unmount } = require("sdk/uri/resource"); -const { setTimeout } = require("sdk/timers"); -const { Loader, Require, Module, main, unload } = require("toolkit/loader"); -const prefs = require("sdk/preferences/service"); - -// load below now, so that it can be used by sdk/addon/runner -// see bug https://bugzilla.mozilla.org/show_bug.cgi?id=1042239 -const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}); - -const REASON = [ "unknown", "startup", "shutdown", "enable", "disable", - "install", "uninstall", "upgrade", "downgrade" ]; - -const UUID_PATTERN = /^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/; -// Takes add-on ID and normalizes it to a domain name so that add-on -// can be mapped to resource://domain/ -const readDomain = id => - // If only `@` character is the first one, than just substract it, - // otherwise fallback to legacy normalization code path. Note: `.` - // is valid character for resource substitutaiton & we intend to - // make add-on URIs intuitive, so it's best to just stick to an - // add-on author typed input. - id.lastIndexOf("@") === 0 ? id.substr(1).toLowerCase() : - id.toLowerCase(). - replace(/@/g, "-at-"). - replace(/\./g, "-dot-"). - replace(UUID_PATTERN, "$1"); - -const readPaths = id => { - const base = `extensions.modules.${id}.path.`; - const domain = readDomain(id); - return prefs.keys(base).reduce((paths, key) => { - const value = prefs.get(key); - const name = key.replace(base, ""); - const path = name.split(".").join("/"); - const prefix = path.length ? `${path}/` : path; - const uri = value.endsWith("/") ? value : `${value}/`; - const root = `extensions.modules.${domain}.commonjs.path.${name}`; - - mount(root, uri); - - paths[prefix] = `resource://${root}/`; - return paths; - }, {}); -}; - -const Bootstrap = function(mountURI) { - this.mountURI = mountURI; - this.install = this.install.bind(this); - this.uninstall = this.uninstall.bind(this); - this.startup = this.startup.bind(this); - this.shutdown = this.shutdown.bind(this); -}; -Bootstrap.prototype = { - constructor: Bootstrap, - mount(domain, rootURI) { - mount(domain, rootURI); - this.domain = domain; - }, - unmount() { - if (this.domain) { - unmount(this.domain); - this.domain = null; - } - }, - install(addon, reason) { - return new Promise(resolve => resolve()); - }, - uninstall(addon, reason) { - return new Promise(resolve => { - const {id} = addon; - - prefs.reset(`extensions.${id}.sdk.domain`); - prefs.reset(`extensions.${id}.sdk.version`); - prefs.reset(`extensions.${id}.sdk.rootURI`); - prefs.reset(`extensions.${id}.sdk.baseURI`); - prefs.reset(`extensions.${id}.sdk.load.reason`); - - resolve(); - }); - }, - startup(addon, reasonCode) { - const { id, version, resourceURI: { spec: addonURI } } = addon; - const rootURI = this.mountURI || addonURI; - const reason = REASON[reasonCode]; - const self = this; - - return spawn(function*() { - const metadata = JSON.parse(yield readURI(`${rootURI}package.json`)); - const domain = readDomain(id); - const baseURI = `resource://${domain}/`; - - this.mount(domain, rootURI); - - prefs.set(`extensions.${id}.sdk.domain`, domain); - prefs.set(`extensions.${id}.sdk.version`, version); - prefs.set(`extensions.${id}.sdk.rootURI`, rootURI); - prefs.set(`extensions.${id}.sdk.baseURI`, baseURI); - prefs.set(`extensions.${id}.sdk.load.reason`, reason); - - const command = prefs.get(`extensions.${id}.sdk.load.command`); - - const loader = Loader({ - id, - isNative: true, - checkCompatibility: true, - prefixURI: baseURI, - rootURI: baseURI, - name: metadata.name, - paths: Object.assign({ - "": "resource://gre/modules/commonjs/", - "devtools/": "resource://devtools/", - "./": baseURI - }, readPaths(id)), - manifest: metadata, - metadata: metadata, - modules: { - "@test/options": {}, - }, - noQuit: prefs.get(`extensions.${id}.sdk.test.no-quit`, false) - }); - self.loader = loader; - - const module = Module("package.json", `${baseURI}package.json`); - const require = Require(loader, module); - const main = command === "test" ? "sdk/test/runner" : null; - const prefsURI = `${baseURI}defaults/preferences/prefs.js`; - - // Init the 'sdk/webextension' module from the bootstrap addon parameter. - require("sdk/webextension").initFromBootstrapAddonParam(addon); - - const { startup } = require("sdk/addon/runner"); - startup(reason, {loader, main, prefsURI}); - }.bind(this)).catch(error => { - console.error(`Failed to start ${id} addon`, error); - throw error; - }); - }, - shutdown(addon, code) { - this.unmount(); - return this.unload(REASON[code]); - }, - unload(reason) { - return new Promise(resolve => { - const { loader } = this; - if (loader) { - this.loader = null; - unload(loader, reason); - - setTimeout(() => { - for (let uri of Object.keys(loader.sandboxes)) { - let sandbox = loader.sandboxes[uri]; - if (Cu.getClassName(sandbox, true) == "Sandbox") - Cu.nukeSandbox(sandbox); - delete loader.sandboxes[uri]; - delete loader.modules[uri]; - } - - try { - Cu.nukeSandbox(loader.sharedGlobalSandbox); - } catch (e) { - Cu.reportError(e); - } - - resolve(); - }, 1000); - } - else { - resolve(); - } - }); - } -}; -exports.Bootstrap = Bootstrap; diff --git a/addon-sdk/source/lib/sdk/addon/events.js b/addon-sdk/source/lib/sdk/addon/events.js deleted file mode 100644 index 45bada6e1..000000000 --- a/addon-sdk/source/lib/sdk/addon/events.js +++ /dev/null @@ -1,56 +0,0 @@ -/* 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': 'experimental' -}; - -var { request: hostReq, response: hostRes } = require('./host'); -var { defer: async } = require('../lang/functional'); -var { defer } = require('../core/promise'); -var { emit: emitSync, on, off } = require('../event/core'); -var { uuid } = require('../util/uuid'); -var emit = async(emitSync); - -// Map of IDs to deferreds -var requests = new Map(); - -// May not be necessary to wrap this in `async` -// once promises are async via bug 881047 -var receive = async(function ({data, id, error}) { - let request = requests.get(id); - if (request) { - if (error) request.reject(error); - else request.resolve(clone(data)); - requests.delete(id); - } -}); -on(hostRes, 'data', receive); - -/* - * Send is a helper to be used in client APIs to send - * a request to host - */ -function send (eventName, data) { - let id = uuid(); - let deferred = defer(); - requests.set(id, deferred); - emit(hostReq, 'data', { - id: id, - data: clone(data), - event: eventName - }); - return deferred.promise; -} -exports.send = send; - -/* - * Implement internal structured cloning algorithm in the future? - * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#internal-structured-cloning-algorithm - */ -function clone (obj) { - return JSON.parse(JSON.stringify(obj || {})); -} diff --git a/addon-sdk/source/lib/sdk/addon/host.js b/addon-sdk/source/lib/sdk/addon/host.js deleted file mode 100644 index 91aa0e869..000000000 --- a/addon-sdk/source/lib/sdk/addon/host.js +++ /dev/null @@ -1,12 +0,0 @@ -/* 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": "experimental" -}; - -exports.request = {}; -exports.response = {}; diff --git a/addon-sdk/source/lib/sdk/addon/installer.js b/addon-sdk/source/lib/sdk/addon/installer.js deleted file mode 100644 index bb8cf8d16..000000000 --- a/addon-sdk/source/lib/sdk/addon/installer.js +++ /dev/null @@ -1,121 +0,0 @@ -/* 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 { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm"); -const { defer } = require("../core/promise"); -const { setTimeout } = require("../timers"); - -/** - * `install` method error codes: - * - * https://developer.mozilla.org/en/Addons/Add-on_Manager/AddonManager#AddonInstall_errors - */ -exports.ERROR_NETWORK_FAILURE = AddonManager.ERROR_NETWORK_FAILURE; -exports.ERROR_INCORRECT_HASH = AddonManager.ERROR_INCORRECT_HASH; -exports.ERROR_CORRUPT_FILE = AddonManager.ERROR_CORRUPT_FILE; -exports.ERROR_FILE_ACCESS = AddonManager.ERROR_FILE_ACCESS; - -/** - * Immediatly install an addon. - * - * @param {String} xpiPath - * file path to an xpi file to install - * @return {Promise} - * A promise resolved when the addon is finally installed. - * Resolved with addon id as value or rejected with an error code. - */ -exports.install = function install(xpiPath) { - let { promise, resolve, reject } = defer(); - - // Create nsIFile for the xpi file - let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile); - try { - file.initWithPath(xpiPath); - } - catch(e) { - reject(exports.ERROR_FILE_ACCESS); - return promise; - } - - // Listen for installation end - let listener = { - onInstallEnded: function(aInstall, aAddon) { - aInstall.removeListener(listener); - // Bug 749745: on FF14+, onInstallEnded is called just before `startup()` - // is called, but we expect to resolve the promise only after it. - // As startup is called synchronously just after onInstallEnded, - // a simple setTimeout(0) is enough - setTimeout(resolve, 0, aAddon.id); - }, - onInstallFailed: function (aInstall) { - aInstall.removeListener(listener); - reject(aInstall.error); - }, - onDownloadFailed: function(aInstall) { - this.onInstallFailed(aInstall); - } - }; - - // Order AddonManager to install the addon - AddonManager.getInstallForFile(file, function(install) { - if (install.error == 0) { - install.addListener(listener); - install.install(); - } else { - reject(install.error); - } - }); - - return promise; -}; - -exports.uninstall = function uninstall(addonId) { - let { promise, resolve, reject } = defer(); - - // Listen for uninstallation end - let listener = { - onUninstalled: function onUninstalled(aAddon) { - if (aAddon.id != addonId) - return; - AddonManager.removeAddonListener(listener); - resolve(); - } - }; - AddonManager.addAddonListener(listener); - - // Order Addonmanager to uninstall the addon - getAddon(addonId).then(addon => addon.uninstall(), reject); - - return promise; -}; - -exports.disable = function disable(addonId) { - return getAddon(addonId).then(addon => { - addon.userDisabled = true; - return addonId; - }); -}; - -exports.enable = function enabled(addonId) { - return getAddon(addonId).then(addon => { - addon.userDisabled = false; - return addonId; - }); -}; - -exports.isActive = function isActive(addonId) { - return getAddon(addonId).then(addon => addon.isActive && !addon.appDisabled); -}; - -const getAddon = function getAddon (id) { - let { promise, resolve, reject } = defer(); - AddonManager.getAddonByID(id, addon => addon ? resolve(addon) : reject()); - return promise; -} -exports.getAddon = getAddon; diff --git a/addon-sdk/source/lib/sdk/addon/manager.js b/addon-sdk/source/lib/sdk/addon/manager.js deleted file mode 100644 index 7ac0a7d6e..000000000 --- a/addon-sdk/source/lib/sdk/addon/manager.js +++ /dev/null @@ -1,18 +0,0 @@ -/* 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": "experimental" -}; - -const { AddonManager } = require("resource://gre/modules/AddonManager.jsm"); -const { defer } = require("../core/promise"); - -function getAddonByID(id) { - let { promise, resolve } = defer(); - AddonManager.getAddonByID(id, resolve); - return promise; -} -exports.getAddonByID = getAddonByID; diff --git a/addon-sdk/source/lib/sdk/addon/runner.js b/addon-sdk/source/lib/sdk/addon/runner.js deleted file mode 100644 index 3977a04e4..000000000 --- a/addon-sdk/source/lib/sdk/addon/runner.js +++ /dev/null @@ -1,180 +0,0 @@ -/* 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); - }); -} diff --git a/addon-sdk/source/lib/sdk/addon/window.js b/addon-sdk/source/lib/sdk/addon/window.js deleted file mode 100644 index 93ed1d8dc..000000000 --- a/addon-sdk/source/lib/sdk/addon/window.js +++ /dev/null @@ -1,66 +0,0 @@ -/* 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": "experimental" -}; - -const { Ci, Cc } = require("chrome"); -const { make: makeWindow, getHiddenWindow } = require("../window/utils"); -const { create: makeFrame, getDocShell } = require("../frame/utils"); -const { defer } = require("../core/promise"); -const { when: unload } = require("../system/unload"); -const cfxArgs = require("../test/options"); - -var addonPrincipal = Cc["@mozilla.org/systemprincipal;1"]. - createInstance(Ci.nsIPrincipal); - -var hiddenWindow = getHiddenWindow(); - -if (cfxArgs.parseable) { - console.info("hiddenWindow document.documentURI:" + - hiddenWindow.document.documentURI); - console.info("hiddenWindow document.readyState:" + - hiddenWindow.document.readyState); -} - -// Once Bug 565388 is fixed and shipped we'll be able to make invisible, -// permanent docShells. Meanwhile we create hidden top level window and -// use it's docShell. -var frame = makeFrame(hiddenWindow.document, { - nodeName: "iframe", - namespaceURI: "http://www.w3.org/1999/xhtml", - allowJavascript: true, - allowPlugins: true -}) -var docShell = getDocShell(frame); -var eventTarget = docShell.chromeEventHandler; - -// We need to grant docShell system principals in order to load XUL document -// from data URI into it. -docShell.createAboutBlankContentViewer(addonPrincipal); - -// Get a reference to the DOM window of the given docShell and load -// such document into that would allow us to create XUL iframes, that -// are necessary for hidden frames etc.. -var window = docShell.contentViewer.DOMDocument.defaultView; -window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>"; - -// Create a promise that is delivered once add-on window is interactive, -// used by add-on runner to defer add-on loading until window is ready. -var { promise, resolve } = defer(); -eventTarget.addEventListener("DOMContentLoaded", function handler(event) { - eventTarget.removeEventListener("DOMContentLoaded", handler, false); - resolve(); -}, false); - -exports.ready = promise; -exports.window = window; - -// Still close window on unload to claim memory back early. -unload(function() { - window.close() - frame.parentNode.removeChild(frame); -}); |