Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Split ABH main module in multiple modules:

 - addon-install which implements simple addon file install,
 - file-utils that handle some FS-related action, mainly due to packed XPIs.
+ Removed `directory-service` that is useless thanks to require(system).pathFor.
+ Fix unregistered listeners in `AddonInstall`.
+ Added new license header.
  • Loading branch information...
commit 8c9f280facae4c98ab8410f719cb1ba266fba7dd 1 parent 37b1082
@ochameau ochameau authored
View
80 lib/addon-install.js
@@ -0,0 +1,80 @@
+/* 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/. */
+
+const { Cc, Ci, Cu } = require('chrome');
+const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
+
+const { Base } = require("api-utils/base");
+const { ns } = require("api-utils/namespace");
+
+
+/**
+ * Class to manage an addon: install and uninstall it.
+ */
+const AddonNS = ns({addon: null});
+exports.AddonInstall = Base.extend({
+ /**
+ * Immediatly install an addon. Note that the given xpi file will be
+ * automatically removed when `callback` is being called.
+ *
+ * @param {String} xpiPath
+ * file path to an xpi to install
+ * @param {Function} callback
+ * function called when addon install finished. First argument being a
+ * boolean to say if the installation was successfull
+ */
+ initialize: function (xpiPath, callback) {
+
+ let self = this;
+ let installListener = {
+ onInstallEnded: function(aInstall, aAddon) {
+ AddonNS(self).addon = aAddon;
+ onInstalled(aInstall, true);
+ },
+ onInstallFailed: function (aInstall) {
+ onInstalled(aInstall, false);
+ }
+ };
+ function onInstalled(aInstall, success) {
+ aInstall.removeListener(installListener);
+ file.remove(xpiPath);
+ callback(success);
+ }
+
+ // Create nsIFile for the xpi file
+ let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
+ file.initWithPath(xpiPath);
+
+ // Order AddonManager to install it!
+ AddonManager.getInstallForFile(file, function(aInstall) {
+ aInstall.addListener(installListener);
+ aInstall.install();
+ });
+
+ },
+
+ get id() {
+ let addon = AddonNS(this).addon;
+ return addon ? addon.id : null;
+ },
+
+ get isInstalled() !!AddonNS(this).addon,
+
+ unload: function (callback) {
+ // Order Addonmanager to uninstall our addon
+ let addon = AddonNS(this).addon;
+ let self = this;
+ let uninstallListener = {
+ onUninstalled: function onUninstalled(aAddon) {
+ if (aAddon.id != addon.id)
+ return;
+ AddonManager.removeAddonListener(uninstallListener);
+ delete AddonNS(self).addon;
+ callback();
+ }
+ };
+ AddonManager.addAddonListener(uninstallListener);
+ addon.uninstall();
+ }
+});
View
95 lib/addons-builder-helper.js
@@ -1,90 +1,19 @@
-const file = require("file");
+/* 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/. */
+
const { Cc, Ci, Cu } = require('chrome');
const windowManager = Cc['@mozilla.org/appshell/window-mediator;1'].
getService(Ci.nsIWindowMediator);
-const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
+
const { PageMod } = require("addon-kit/page-mod");
-const { Base } = require("api-utils/base");
-const { ns } = require("api-utils/namespace");
+
+const { AddonInstall } = require("addon-install");
+const { createTemporaryFileFromData } = require("file-utils");
const CONFIG_FILENAME = "addon-config.json";
const CONFIG_PREF = "extensions.addonBuilderHelper.trustedOrigins";
-/**
- * Class to manage an addon: install and uninstall it.
- */
-const AddonNS = ns({addon: null});
-const AddonInstall = Base.extend({
- /**
- * Immediatly install an addon
- * @param {String} xpiPath
- * file path to an xpi to install
- * @param {Function} callback
- * function called when addon install finished. First argument being a
- * boolean to say if the installation was successfull
- */
- initialize: function (xpiPath, callback) {
-
- function onInstalled(success) {
- file.remove(xpiPath);
- callback(success);
- }
-
- // Create nsIFile for the xpi file
- let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
- file.initWithPath(xpiPath);
-
- // Order AddonManager to install it!
- let self = this;
- AddonManager.getInstallForFile(file, function(aInstall) {
- aInstall.addListener({
- onInstallEnded: function(aInstall, aAddon) {
- AddonNS(self).addon = aAddon;
- onInstalled(true);
- },
- onInstallFailed: function (aInstall) {
- onInstalled(false);
- }
- });
- aInstall.install();
- });
-
- },
-
- get id() {
- let addon = AddonNS(this).addon;
- return addon ? addon.id : null;
- },
-
- get isInstalled() !!AddonNS(this).addon,
-
- unload: function (callback) {
- // Order Addonmanager to uninstall our addon
- let addon = AddonNS(this).addon;
- AddonManager.addAddonListener({
- onUninstalled: function onUninstalled(aAddon) {
- if (aAddon.id != addon.id)
- return;
- callback();
- }
- });
- addon.uninstall();
- }
-});
-
-
-// Create a temporary xpi file for a given string data
-function createXpiFileFromData(xpiData) {
- var profileDir = require("directory-service").getPath("ProfD");
- var tempXPI = file.join(profileDir, "temp-addon-builder.xpi");
-
- var xpi = file.open(tempXPI, "wb");
- xpi.write(xpiData);
- xpi.close();
-
- return tempXPI;
-}
-
/**
* Utility method to toggle the XUL JS Console.
@@ -217,7 +146,7 @@ function SingleAddonManager() {
});
}
else
- currExtension = AddonInstall.new(createXpiFileFromData(xpiData), callback);
+ currExtension = AddonInstall.new(createTemporaryFileFromData(xpiData), callback);
},
uninstall: function uninstall(callback) {
@@ -248,9 +177,11 @@ function safeGetConfig() {
}
exports.main = function main() {
+ // Read config file from data folder
var config = safeGetConfig();
- var pref = require("preferences-service").get(CONFIG_PREF, null);
+ // Read trusted-origins from preference
+ var pref = require("preferences-service").get(CONFIG_PREF, null);
if (typeof(pref) == "string") {
try {
config.trustedOrigins = config.trustedOrigins.concat(pref.split(","));
@@ -263,7 +194,7 @@ exports.main = function main() {
PageMod({
include: config.trustedOrigins,
contentScriptWhen: "start",
- contentScript: "new " + function () {
+ contentScript: "new " + function ContentScriptScope() {
// Utility class to build a promise pattern
function Promise(self) {
View
12 lib/directory-service.js
@@ -1,12 +0,0 @@
-const {Cc, Ci, Cr} = require("chrome");
-
-var dirSvc = Cc["@mozilla.org/file/directory_service;1"]
- .getService(Ci.nsIProperties);
-
-exports.getPath = function getPath(name) {
- try {
- return dirSvc.get(name, Ci.nsIFile).path;
- } catch (e if e.result == Cr.NS_ERROR_FAILURE) {
- throw new Error("Directory service entry not found: " + name);
- }
-};
View
37 lib/file-utils.js
@@ -0,0 +1,37 @@
+/* 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/. */
+
+// Create a temporary file for a given string data
+const file = require("api-utils/file");
+exports.createTemporaryFileFromData = function (data, tmpName) {
+ var profileDir = require("system").pathFor("ProfD");
+ var path = file.join(profileDir, tmpName ? tmpName : "tmp-file");
+
+ var tmpFile = file.open(path, "wb");
+ tmpFile.write(data);
+ tmpFile.close();
+
+ return path;
+}
+
+exports.createTemporaryFileFromURL = function (url, tmpName) {
+ let data = exports.readBinaryURI(url);
+ return exports.createTemporaryFileFromData(data, tmpName);
+}
+
+// Utility function that synchronously reads local resource from the given
+// `uri` and returns content string. Read in binary mode.
+const {ByteReader} = require("api-utils/byte-streams");
+const {Cc, Ci} = require("chrome");
+exports.readBinaryURI = function readBinaryURI(uri) {
+ let ioservice = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ let channel = ioservice.newChannel(uri, "UTF-8", null);
+ let stream = channel.open();
+
+ let reader = new ByteReader(stream);
+ let data = reader.read();
+ stream.close();
+
+ return data;
+}
View
46 tests/test-addon-install.js
@@ -0,0 +1,46 @@
+/* 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/. */
+
+const { Cc, Ci, Cu } = require("chrome");
+const { AddonInstall } = require("addon-install");
+const { Services } = Components.utils.import("resource://gre/modules/Services.jsm");
+
+const SELF = require("self");
+const ADDON_URL = SELF.data.url("abh-unit-test@mozilla.com.xpi");
+const ADDON_PATH = require("file-utils").createTemporaryFileFromURL(ADDON_URL);
+
+exports.testInstall = function (test) {
+ test.waitUntilDone();
+
+ // Save all events distpatched by bootstrap.js of the installed addon
+ let events = [];
+ let eventsObserver = {
+ observe: function (subject, topic, data) {
+ events.push(data);
+ }
+ };
+ Services.obs.addObserver(eventsObserver, "abh-unit-test", false);
+
+ // Install the test addon
+ let install = AddonInstall.new(ADDON_PATH, function onInstalled(success) {
+ test.assert(success, "Installed successfully");
+ test.assertEqual(install.id, "abh-unit-test@mozilla.com", "`install.id` is valid");
+ test.assert(install.isInstalled, "`install.isInstalled` is true on 'onInstalled' call");
+
+ // Now uninstall it
+ install.unload(function () {
+ test.assert(!install.isInstalled, "`install.isInstalled` is false when unload callback is called");
+ test.assert(!install.id, "`install.id` is empty after uninstall");
+
+ // Ensure that bootstrap.js methods of the addon have been called
+ // successfully and in the right order
+ Services.obs.removeObserver(eventsObserver, "abh-unit-test");
+ test.assertEqual(JSON.stringify(events),
+ JSON.stringify(["install", "startup", "shutdown", "uninstall"]),
+ "addon's bootstrap.js functions have been called");
+
+ test.done();
+ });
+ });
+}
View
31 tests/test-addons-builder-helper.js
@@ -1,7 +1,15 @@
+/* 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/. */
+
const { Cc, Ci, Cu } = require("chrome");
const tabs = require("addon-kit/tabs");
const { Services } = Components.utils.import("resource://gre/modules/Services.jsm");
+const { readBinaryURI } = require("file-utils");
+
+const TEST_ADDON_URL = require("self").data.url("abh-unit-test@mozilla.com.xpi");
+
// First register "data:*" URLs as being AddonBuilder trusted URLs
require("api-utils/preferences-service").set(
"extensions.addonBuilderHelper.trustedOrigins",
@@ -132,21 +140,6 @@ exports.testIsInstalled = createTest(
function (test, worker, done) {}
);
-// Utility function that synchronously reads local resource from the given
-// `uri` and returns content string. Read in binary mode.
-const {ByteReader} = require("api-utils/byte-streams");
-function readURI(uri) {
- let ioservice = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
- let channel = ioservice.newChannel(uri, "UTF-8", null);
- let stream = channel.open();
-
- let reader = new ByteReader(stream);
- let data = reader.read();
- stream.close();
-
- return data;
-}
-
exports.testInstall = createTest(
"new " + function ContentScriptScope() {
function assertIsInstalled(addonId, msg, next) {
@@ -188,17 +181,19 @@ exports.testInstall = createTest(
// Save all events distpatched by bootstrap.js of the installed addon
let events = [];
- Services.obs.addObserver({
+ let eventsObserver = {
observe: function (subject, topic, data) {
events.push(data);
}
- }, "abh-unit-test", false);
+ };
+ Services.obs.addObserver(eventsObserver, "abh-unit-test", false);
// We can't use self.data.load as it doesn't read in binary mode!
- let xpiData = readURI(require("self").data.url("abh-unit-test@mozilla.com.xpi"));
+ let xpiData = readBinaryURI(TEST_ADDON_URL);
worker.port.emit("xpiData", xpiData);
worker.port.on("uninstalled", function () {
+ Services.obs.removeObserver(eventsObserver, "abh-unit-test");
test.assertEqual(JSON.stringify(events),
JSON.stringify(["install", "startup", "shutdown", "uninstall"]),
"addon's bootstrap.js functions have been called");
View
11 tests/test-directory-service.js
@@ -1,11 +0,0 @@
-var dirSvc = require("directory-service");
-
-exports.testGet = function(test) {
- test.assertEqual(typeof(dirSvc.getPath("ProfD")), "string",
- "Profile directory should exist");
- test.assertRaises(
- function() require("directory-service").getPath("blargy"),
- "Directory service entry not found: blargy",
- "Getting nonexistent entries should raise exceptions"
- );
-};
Please sign in to comment.
Something went wrong with that request. Please try again.