Bug 1114752 - Uplift Add-on SDK to Firefox a=me
This commit is contained in:
160
addon-sdk/source/lib/sdk/addon/bootstrap.js
vendored
Normal file
160
addon-sdk/source/lib/sdk/addon/bootstrap.js
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
/* 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) {
|
||||
},
|
||||
uninstall(addon, reason) {
|
||||
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`);
|
||||
|
||||
},
|
||||
startup(addon, reasonCode) {
|
||||
const { id, version, resourceURI: {spec: addonURI} } = addon;
|
||||
const rootURI = this.mountURI || addonURI;
|
||||
const reason = REASON[reasonCode];
|
||||
|
||||
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://gre/modules/devtools/",
|
||||
"./": baseURI
|
||||
}, readPaths(id)),
|
||||
manifest: metadata,
|
||||
metadata: metadata,
|
||||
modules: {
|
||||
"@test/options": {}
|
||||
},
|
||||
noQuit: prefs.get(`extensions.${id}.sdk.test.no-quit`, false)
|
||||
});
|
||||
this.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`;
|
||||
|
||||
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) {
|
||||
const { loader, domain } = this;
|
||||
|
||||
this.unmount();
|
||||
this.unload(REASON[code]);
|
||||
},
|
||||
unload(reason) {
|
||||
const {loader} = this;
|
||||
if (loader) {
|
||||
this.loader = null;
|
||||
unload(loader, reason);
|
||||
setTimeout(() => {
|
||||
for (let uri of Object.keys(loader.sandboxes)) {
|
||||
Cu.nukeSandbox(loader.sandboxes[uri]);
|
||||
delete loader.sandboxes[uri];
|
||||
delete loader.modules[uri];
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.Bootstrap = Bootstrap;
|
||||
Reference in New Issue
Block a user