diff options
Diffstat (limited to 'tools/addon-sdk-1.3/python-lib/cuddlefish/app-extension/components')
-rw-r--r-- | tools/addon-sdk-1.3/python-lib/cuddlefish/app-extension/components/harness.js | 660 |
1 files changed, 0 insertions, 660 deletions
diff --git a/tools/addon-sdk-1.3/python-lib/cuddlefish/app-extension/components/harness.js b/tools/addon-sdk-1.3/python-lib/cuddlefish/app-extension/components/harness.js deleted file mode 100644 index 23030e9..0000000 --- a/tools/addon-sdk-1.3/python-lib/cuddlefish/app-extension/components/harness.js +++ /dev/null @@ -1,660 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Weave. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dan Mills <thunder@mozilla.com> - * Atul Varma <atul@mozilla.com> - * Drew Willcoxon <adw@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// This file contains an XPCOM component which "bootstraps" a Jetpack -// program. -// -// The main entry point, `NSGetModule()`, is data-driven, and obtains -// a lot of its configuration information from a JSON file -// called `harness-options.json` in the root directory of the extension -// or application it's a part of. -// -// `NSGetModule()` then uses this configuration information to -// dynamically create an XPCOM component called a "Harness Service", -// which is responsible for setting up and shutting down the Jetpack -// program's CommonJS environment. It's also the main mechanism through -// which other parts of the application can communicate with the Jetpack -// program. -// -// If we're on Gecko 1.9.3, which supports rebootless extensions, the -// bootstrap.js file actually evaluates this file and calls parts of -// it automatically. -// -// It should be noted that a lot of what's done by the Harness Service is -// very similar to what's normally done by a `chrome.manifest` file: the -// difference here is that everything the Harness Service does is -// undoable during the lifetime of the application. This is the -// foundation of what makes it possible for Jetpack-based extensions -// to be installed and uninstalled without needing to reboot the -// application being extended. - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -const obSvc = Cc["@mozilla.org/observer-service;1"] - .getService(Ci.nsIObserverService); - -const ioSvc = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService); - -const FIREFOX_ID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"; -const THUNDERBIRD_ID = "{3550f703-e582-4d05-9a08-453d09bdfdc6}"; -const FENNEC_ID = "{a23983c0-fd0e-11dc-95ff-0800200c9a66}"; - -// This function builds and returns a Harness Service XPCOM component. -// -// Parameters: -// -// rootFileSpec - nsILocalFile corresponding to root of extension -// (required). -// -// dump - function to output string to console (required). -// -// logError - function to log an exception (required). -// -// onQuit - function called when the app quits (required). -// -// options - JSON configuration information passed in from the -// environment (required). - -function buildHarnessService(rootFileSpec, dump, logError, - onQuit, options) { - if (arguments.length == 1) { - ({dump, logError, onQuit, options}) = getDefaults(rootFileSpec); - } - - // The loader for securable modules, typically a Cuddlefish loader. - var loader; - - // Singleton Harness Service. - var harnessService; - - // Whether we've initialized or not yet. - var isStarted; - - // Whether we've been asked to quit or not yet. - var isQuitting; - - // The Jetpack program's main module. - var program; - - var ioService = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService); - var resProt = ioService.getProtocolHandler("resource") - .QueryInterface(Ci.nsIResProtocolHandler); - - function quit(status) { - if (status === undefined) - status = "OK"; - if (status != "OK" && status != "FAIL") { - dump("Warning: quit() expected 'OK' or 'FAIL' as an " + - "argument, but got '" + status + "' instead."); - status = "FAIL"; - } - - if (isQuitting) - return; - - isQuitting = true; - - if (harnessService) - harnessService.unload(); - - onQuit(status); - } - - function logErrorAndBail(e) { - logError(e); - quit("FAIL"); - } - - function ensureIsDir(dir) { - if (!(dir.exists() && dir.isDirectory)) - throw new Error("directory not found: " + dir.path); - } - - function getDir(path) { - var dir = Cc['@mozilla.org/file/local;1'] - .createInstance(Ci.nsILocalFile); - dir.initWithPath(path); - ensureIsDir(dir); - return dir; - } - - function buildLoader() { - // TODO: This variable doesn't seem to be used, we should - // be able to remove it. - var compMgr = Components.manager; - compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar); - - for (let name in options.resources) { - var path = options.resources[name]; - var dir; - if (typeof(path) == "string") - dir = getDir(path); - else { - dir = rootFileSpec.clone(); - path.forEach(function(part) { dir.append(part); }); - ensureIsDir(dir); - } - var dirUri = ioService.newFileURI(dir); - resProt.setSubstitution(name, dirUri); - } - - var jsm = {}; - Cu.import(options.loader, jsm); - var packaging = new Packaging(); - var loader = new jsm.Loader({rootPaths: options.rootPaths.slice(), - print: dump, - packaging: packaging, - metadata: options.metadata, - uriPrefix: options.uriPrefix, - name: options.name, - globals: { packaging: packaging } - }); - packaging.__setLoader(loader); - return loader; - } - - // This will be exposed as the 'packaging' global to all - // modules loaded within our loader. - - function Packaging() { - this.__packages = options.manifest; - } - - Packaging.prototype = { - __setLoader: function setLoader(loader) { - this.__loader = loader; - }, - - get root() { - return rootFileSpec.clone(); - }, - - get harnessService() { - return harnessService; - }, - - get buildHarnessService() { - return buildHarnessService; - }, - - get options() { - return options; - }, - - enableE10s: options.enable_e10s, - - jetpackID: options.jetpackID, - uriPrefix: options.uriPrefix, - - bundleID: options.bundleID, - - getModuleInfo: function getModuleInfo(path) { - return this.__packages[path]; - }, - - createLoader: function createLoader() { - return buildLoader(); - } - }; - - // Singleton XPCOM component that is responsible for instantiating - // a Cuddlefish loader and running the main program, if any. - - function HarnessService() { - this.wrappedJSObject = this; - } - - HarnessService.prototype = { - get classDescription() { - // This needs to be unique, lest we regress bug 554489. - return "Harness Service for " + options.bootstrap.contractID; - }, - - get contractID() { return options.bootstrap.contractID; }, - - get classID() { return Components.ID(options.bootstrap.classID); }, - - _xpcom_categories: [{ category: "profile-after-change" }], - - _xpcom_factory: { - get singleton() { - return harnessService; - }, - - createInstance: function(outer, iid) { - if (outer) - throw Cr.NS_ERROR_NO_AGGREGATION; - if (!harnessService) - harnessService = new HarnessService(); - return harnessService.QueryInterface(iid); - } - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, - Ci.nsISupportsWeakReference]), - - get loader() { - if (!loader) - loader = buildLoader(); - return loader; - }, - - get options() { - return options; - }, - - load: function Harness_load(reason) { - if (isStarted) - return; - - isStarted = true; - obSvc.addObserver(this, "quit-application-granted", true); - if (options.main) { - try { - - if (reason) - options.loadReason = reason; - program = this.loader.require(options.main); - if ('main' in program) - program.main(options, {quit: quit, print: dump}); - - // Send application readiness notification - const APP_READY_TOPIC = options.jetpackID + "_APPLICATION_READY"; - obSvc.notifyObservers(null, APP_READY_TOPIC, null); - - } catch (e) { - this.loader.console.exception(e); - quit("FAIL"); - } - } - }, - - unload: function Harness_unload(reason) { - if (!isStarted) - return; - - isStarted = false; - harnessService = null; - - obSvc.removeObserver(this, "quit-application-granted"); - - lifeCycleObserver192.unload(); - - // Notify the program of unload. - if (program) { - if (typeof(program.onUnload) === "function") { - try { - program.onUnload(reason); - } - catch (err) { - if (loader) - loader.console.exception(err); - } - } - program = null; - } - - // Notify the loader of unload. - if (loader) { - loader.unload(reason); - loader = null; - } - - for (let name in options.resources) - resProt.setSubstitution(name, null); - }, - - observe: function Harness_observe(subject, topic, data) { - try { - switch (topic) { - case "profile-after-change": - var appInfo = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsIXULAppInfo); - switch (appInfo.ID) { - case THUNDERBIRD_ID: - case FENNEC_ID: - obSvc.addObserver(this, "xul-window-visible", true); - break; - case FIREFOX_ID: - obSvc.addObserver(this, "sessionstore-windows-restored", true); - break; - default: - obSvc.addObserver(this, "final-ui-startup", true); - break; - } - lifeCycleObserver192.init(options.bundleID, logError); - break; - case "final-ui-startup": // XULRunner - case "sessionstore-windows-restored": // Firefox - case "xul-window-visible": // Thunderbird, Fennec - obSvc.removeObserver(this, topic); - this.load(lifeCycleObserver192.loadReason || "startup"); - break; - case "quit-application-granted": - this.unload(lifeCycleObserver192.unloadReason || "shutdown"); - quit("OK"); - break; - } - } catch (e) { - logErrorAndBail(e); - } - } - }; - - var factory = HarnessService.prototype._xpcom_factory; - if (!factory.wrappedJSObject) - factory.wrappedJSObject = factory; - - return HarnessService; -} - -// This is an error logger of last resort; if we're here, then -// we weren't able to initialize Cuddlefish and display a nice -// traceback through it. - -function defaultLogError(e, print) { - if (!print) - print = dump; - - var level = "error"; - print(e + " (" + e.fileName + ":" + e.lineNumber + ")\n", level); - if (e.stack) - print("stack:\n" + e.stack + "\n", level); -} - -// Builds an onQuit() function that writes a result file if necessary -// and does some other extra things to enhance developer ergonomics. - -function buildDevQuit(options, dump) { - // Absolute path to a file that we put our result code in. Ordinarily - // we'd just exit the process with a zero or nonzero return code, but - // there doesn't appear to be a way to do this in XULRunner. - var resultFile = options.resultFile; - - // Whether we've written resultFile or not. - var fileWritten = false; - - function attemptQuit() { - var appStartup = Cc['@mozilla.org/toolkit/app-startup;1']. - getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eAttemptQuit); - } - - return function onQuit(result) { - dump(result + "\n"); - - function writeResult() { - if (!fileWritten) - try { - var file = Cc["@mozilla.org/file/local;1"] - .createInstance(Ci.nsILocalFile); - file.initWithPath(resultFile); - - var foStream = Cc["@mozilla.org/network/file-output-stream;1"] - .createInstance(Ci.nsIFileOutputStream); - foStream.init(file, -1, -1, 0); - foStream.write(result, result.length); - foStream.close(); - fileWritten = true; - } catch (e) { - dump(e + "\n"); - } - } - - writeResult(); - attemptQuit(); - }; -} - -function buildForsakenConsoleDump(dump) { - var buffer = ""; - var cService = Cc['@mozilla.org/consoleservice;1'].getService() - .QueryInterface(Ci.nsIConsoleService); - - function stringify(arg) { - try { - return String(arg); - } - catch(ex) { - return "<toString() error>"; - } - } - - return function forsakenConsoleDump(msg, level) { - msg = stringify(msg); - if (msg.indexOf('\n') >= 0) { - var str = buffer + msg; - if (level === "error") { - var err = Cc["@mozilla.org/scripterror;1"] - .createInstance(Ci.nsIScriptError); - str = str.replace(/^error: /, ""); - err.init(str, null, null, 0, 0, 0, "Add-on SDK"); - cService.logMessage(err); - } - else - cService.logStringMessage(str); - buffer = ""; - } else { - buffer += msg; - } - }; -} - -function getDefaults(rootFileSpec) { - // Default options to pass back. - var options; - - try { - var environ = Cc["@mozilla.org/process/environment;1"] - .getService(Ci.nsIEnvironment); - - var jsonData; - var optionsFile = rootFileSpec.clone(); - optionsFile.append('harness-options.json'); - if (optionsFile.exists()) { - var fiStream = Cc['@mozilla.org/network/file-input-stream;1'] - .createInstance(Ci.nsIFileInputStream); - var siStream = Cc['@mozilla.org/scriptableinputstream;1'] - .createInstance(Ci.nsIScriptableInputStream); - fiStream.init(optionsFile, 1, 0, false); - siStream.init(fiStream); - var data = new String(); - data += siStream.read(-1); - siStream.close(); - fiStream.close(); - jsonData = data; - } - else { - throw new Error("harness-options.json file must exist."); - } - - options = JSON.parse(jsonData); - } catch (e) { - defaultLogError(e); - throw e; - } - - var onQuit = function() {}; - var doDump = buildForsakenConsoleDump(dump); - - if ('resultFile' in options) - onQuit = buildDevQuit(options, print); - - var logFile; - var logStream; - - if ('logFile' in options) { - logFile = Cc["@mozilla.org/file/local;1"] - .createInstance(Ci.nsILocalFile); - logFile.initWithPath(options.logFile); - - logStream = Cc["@mozilla.org/network/file-output-stream;1"] - .createInstance(Ci.nsIFileOutputStream); - logStream.init(logFile, 26 /* PR_WRONLY | PR_APPEND | PR_CREATE_FILE */, - -1 , 0); - } - - function print(msg, level) { - doDump(msg, level); - if (logStream && typeof(msg) == "string") { - logStream.write(msg, msg.length); - logStream.flush(); - } - } - - function logError(e) { - defaultLogError(e, print); - } - - return {options: options, onQuit: onQuit, dump: print, - logError: logError}; -} - -// Gecko 2, entry point for non-bootstrapped extensions (which register this -// component via chrome.manifest.) -// FIXME: no install/uninstall notifications on 2.0 for non-bootstrapped addons -function NSGetFactory(cid) { - try { - if (!NSGetFactory.fn) { - var rootFileSpec = __LOCATION__.parent.parent; - var HarnessService = buildHarnessService(rootFileSpec); - NSGetFactory.fn = XPCOMUtils.generateNSGetFactory([HarnessService]); - } - } catch(e) { - Components.utils.reportError(e); - dump(e); - throw e; - } - return NSGetFactory.fn(cid); -} - -// Everything below is only used on Gecko 1.9.2 or below. - -function NSGetModule(compMgr, fileSpec) { - var rootFileSpec = fileSpec.parent.parent; - var HarnessService = buildHarnessService(rootFileSpec); - return XPCOMUtils.generateModule([HarnessService]); -} - -// Program life-cycle events originate in bootstrap.js on 1.9.3. But 1.9.2 -// doesn't use bootstrap.js, so we need to do a little extra work there to -// determine the reasons for app startup and shutdown. That's what this -// singleton is for. On 1.9.3 all methods are no-ops. -var lifeCycleObserver192 = { - get loadReason() { - if (this._inited) { - // If you change these names, change them in bootstrap.js too. - if (this._addonIsNew) - return "install"; - return "startup"; - } - return undefined; - }, - - get unloadReason() { - if (this._inited) { - // If you change these names, change them in bootstrap.js too. - switch (this._emState) { - case "item-uninstalled": - return "uninstall"; - case "item-disabled": - return "disable"; - } - return "shutdown"; - } - return undefined; - }, - - // This must be called first to initialize the singleton. It must be called - // on profile-after-change. - init: function lifeCycleObserver192_init(bundleID, logError) { - // This component is present in 1.9.2 but not 2.0. - if ("@mozilla.org/extensions/manager;1" in Cc && !this._inited) { - obSvc.addObserver(this, "em-action-requested", true); - this._bundleID = bundleID; - this._logError = logError; - this._inited = true; - - try { - // This throws if the pref doesn't exist, which is the case when no - // new add-ons were installed. - var addonIdStr = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch). - getCharPref("extensions.newAddons"); - } - catch (err) {} - if (addonIdStr) { - var addonIds = addonIdStr.split(","); - this._addonIsNew = addonIds.indexOf(this._bundleID) >= 0; - } - } - }, - - unload: function lifeCycleObserver192_unload() { - if (this._inited && !this._unloaded) { - obSvc.removeObserver(this, "em-action-requested"); - delete this._logError; - this._unloaded = true; - } - }, - - observe: function lifeCycleObserver192_observe(subj, topic, data) { - try { - if (topic === "em-action-requested") { - if (subj instanceof Ci.nsIUpdateItem && subj.id === this._bundleID) - this._emState = data; - } - } - catch (err) { - this._logError(err); - } - }, - - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsIObserver, - Ci.nsISupportsWeakReference, - ]) -}; |