Bug 1452120 - Make icaljs backend loader work with packed extensions. r=MakeMyDay a=philipp
authorPhilipp Kewisch <mozilla@kewis.ch>
Tue, 01 May 2018 14:53:01 +0200
changeset 31455 1521f2ce1de5
parent 31454 6d62aa47036e
child 31456 6510ef9822b3
push id383
push userclokep@gmail.com
push date2018-05-07 21:52 +0000
reviewersMakeMyDay, philipp
bugs1452120
Bug 1452120 - Make icaljs backend loader work with packed extensions. r=MakeMyDay a=philipp MozReview-Commit-ID: 5yWIQUajyLE
calendar/base/backend/calBackendLoader.js
calendar/base/backend/calBackendLoader.manifest
calendar/base/backend/icaljs/calICALJSComponents.js
calendar/base/backend/icaljs/icaljs-manifest
calendar/base/backend/icaljs/moz.build
calendar/base/modules/calUtils.jsm
calendar/base/src/calItemModule.js
calendar/base/src/calTimezoneService.js
calendar/import-export/calImportExportModule.js
calendar/providers/caldav/calDavCalendar.js
calendar/providers/wcap/calWcapCalendarModule.js
calendar/test/unit/head_consts.js
--- a/calendar/base/backend/calBackendLoader.js
+++ b/calendar/base/backend/calBackendLoader.js
@@ -1,21 +1,22 @@
 /* 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/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 
 function calBackendLoader() {
     this.wrappedJSObject = this;
     try {
         this.loadBackend();
     } catch (e) {
-        dump("### Error loading backend: " + e + "\n");
+        dump(`### Error loading backend:${e.filename || e.fileName}:${e.lineNumber}: ${e}\n`);
     }
 }
 
 var calBackendLoaderClassID = Components.ID("{0314c271-7168-40fa-802e-83c8c46a557e}");
 var calBackendLoaderInterfaces = [Components.interfaces.nsIObserver];
 calBackendLoader.prototype = {
     classID: calBackendLoaderClassID,
     QueryInterface: XPCOMUtils.generateQI(calBackendLoaderInterfaces),
@@ -33,47 +34,53 @@ calBackendLoader.prototype = {
         // Nothing to do here, just need the entry so this is instanciated
     },
 
     loadBackend: function() {
         if (this.loaded) {
             return;
         }
 
-        if (Services.prefs.getBoolPref("calendar.icaljs")) {
-            let contracts = [
-                "@mozilla.org/calendar/datetime;1",
-                "@mozilla.org/calendar/duration;1",
-                "@mozilla.org/calendar/ics-service;1",
-                "@mozilla.org/calendar/period;1",
-                "@mozilla.org/calendar/recurrence-rule;1"
-            ];
+        if (Preferences.get("calendar.icaljs", false)) {
+            let contracts = {
+                "@mozilla.org/calendar/datetime;1": "{36783242-ec94-4d8a-9248-d2679edd55b9}",
+                "@mozilla.org/calendar/ics-service;1": "{c61cb903-4408-41b3-bc22-da0b27efdfe1}",
+                "@mozilla.org/calendar/period;1": "{394a281f-7299-45f7-8b1f-cce21258972f}",
+                "@mozilla.org/calendar/recurrence-rule;1": "{df19281a-5389-4146-b941-798cb93a7f0d}",
+                "@mozilla.org/calendar/duration;1": "{7436f480-c6fc-4085-9655-330b1ee22288}",
+            };
 
-            // Unregister libical components
+            // Load ical.js backend
+            let scope = {};
+            Services.scriptloader.loadSubScript("resource://calendar/components/calICALJSComponents.js", scope);
+
+            // Register the icaljs components. We used to unregisterFactory, but this caused all
+            // sorts of problems. Just registering over it seems to work quite fine.
             let registrar = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
-            for (let contractId of contracts) {
-                let classId = registrar.contractIDToCID(contractId);
-                let factory = Components.manager.getClassObject(classId, Components.interfaces.nsIFactory);
-                registrar.unregisterFactory(classId, factory);
+            for (let [contractID, classID] of Object.entries(contracts)) {
+                let newClassID = Components.ID(classID);
+                let newFactory = lazyFactoryFor(scope, newClassID);
+                registrar.registerFactory(newClassID, "", contractID, newFactory);
             }
 
-            // Now load ical.js backend
-            let uri = Services.io.getProtocolHandler("resource")
-                              .QueryInterface(Components.interfaces.nsIResProtocolHandler)
-                              .getSubstitution("calendar");
-
-            let file = Services.io.getProtocolHandler("file")
-                               .QueryInterface(Components.interfaces.nsIFileProtocolHandler)
-                               .getFileFromURLSpec(uri.spec);
-            file.append("components");
-            file.append("icaljs-manifest");
-
-            registrar.autoRegister(file);
-            dump("[calBackendLoader] Using icaljs backend at " + file.path + "\n");
+            dump("[calBackendLoader] Using Lightning's icaljs backend\n");
         } else {
             dump("[calBackendLoader] Using Thunderbird's builtin libical backend\n");
         }
 
         this.loaded = true;
     }
 };
 
+function lazyFactoryFor(backendScope, classID) {
+    return {
+        createInstance: function(aOuter, aIID) {
+            let realFactory = backendScope.NSGetFactory(classID);
+            return realFactory.createInstance(aOuter, aIID);
+        },
+        lockFactory: function(lock) {
+            let realFactory = backendScope.NSGetFactory(classID);
+            return realFactory.lockFactory(aOuter, aIID);
+        }
+    };
+}
+
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([calBackendLoader]);
--- a/calendar/base/backend/calBackendLoader.manifest
+++ b/calendar/base/backend/calBackendLoader.manifest
@@ -1,3 +1,3 @@
 component {0314c271-7168-40fa-802e-83c8c46a557e} calBackendLoader.js
 contract @mozilla.org/calendar/backend-loader;1 {0314c271-7168-40fa-802e-83c8c46a557e}
-category profile-after-change calendar-backend-loader @mozilla.org/calendar/backend-loader;1
+category profile-after-change calendar-backend-loader service,@mozilla.org/calendar/backend-loader;1
--- a/calendar/base/backend/icaljs/calICALJSComponents.js
+++ b/calendar/base/backend/icaljs/calICALJSComponents.js
@@ -1,28 +1,29 @@
 /* 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/. */
 
-ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-var scriptLoadOrder = [
-    "calTimezone.js",
-    "calDateTime.js",
-    "calDuration.js",
-    "calICSService.js",
-    "calPeriod.js",
-    "calRecurrenceRule.js",
-];
+this.NSGetFactory = (cid) => {
+    let scriptLoadOrder = [
+        "resource://calendar/calendar-js/calTimezone.js",
+        "resource://calendar/calendar-js/calDateTime.js",
+        "resource://calendar/calendar-js/calDuration.js",
+        "resource://calendar/calendar-js/calICSService.js",
+        "resource://calendar/calendar-js/calPeriod.js",
+        "resource://calendar/calendar-js/calRecurrenceRule.js",
+    ];
 
-function getComponents() {
-    return [
-        calDateTime,
-        calDuration,
-        calIcalComponent,
-        calIcalProperty,
-        calICSService,
-        calPeriod,
-        calRecurrenceRule,
+    for (let script of scriptLoadOrder) {
+        Services.scriptloader.loadSubScript(script, this);
+    }
+
+    let components = [
+        calDateTime, calDuration, calIcalComponent, calIcalProperty, calICSService, calPeriod,
+        calRecurrenceRule
     ];
-}
 
-this.NSGetFactory = cal.loadingNSGetFactory(scriptLoadOrder, getComponents, this);
+    this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
+    return this.NSGetFactory(cid);
+};
deleted file mode 100644
--- a/calendar/base/backend/icaljs/icaljs-manifest
+++ /dev/null
@@ -1,17 +0,0 @@
-component {36783242-ec94-4d8a-9248-d2679edd55b9} calICALJSComponents.js
-contract @mozilla.org/calendar/datetime;1 {36783242-ec94-4d8a-9248-d2679edd55b9}
-
-component {7436f480-c6fc-4085-9655-330b1ee22288} calICALJSComponents.js
-contract @mozilla.org/calendar/duration;1 {7436f480-c6fc-4085-9655-330b1ee22288}
-
-component {c61cb903-4408-41b3-bc22-da0b27efdfe1} calICALJSComponents.js
-contract @mozilla.org/calendar/ics-service;1 {c61cb903-4408-41b3-bc22-da0b27efdfe1}
-
-component {394a281f-7299-45f7-8b1f-cce21258972f} calICALJSComponents.js
-contract @mozilla.org/calendar/period;1 {394a281f-7299-45f7-8b1f-cce21258972f}
-
-component {df19281a-5389-4146-b941-798cb93a7f0d} calICALJSComponents.js
-contract @mozilla.org/calendar/recurrence-rule;1 {df19281a-5389-4146-b941-798cb93a7f0d}
-
-component {6702eb17-a968-4b43-b562-0d0c5f8e9eb5} calICALJSComponents.js
-contract @mozilla.org/calendar/timezone;1 {6702eb17-a968-4b43-b562-0d0c5f8e9eb5}
--- a/calendar/base/backend/icaljs/moz.build
+++ b/calendar/base/backend/icaljs/moz.build
@@ -2,20 +2,16 @@
 # 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/.
 
 EXTRA_COMPONENTS += [
     'calICALJSComponents.js',
 ]
 
-FINAL_TARGET_FILES.components += [
-    'icaljs-manifest'
-]
-
 FINAL_TARGET_FILES['calendar-js'] += [
     'calDateTime.js',
     'calDuration.js',
     'calICSService-worker.js',
     'calICSService.js',
     'calPeriod.js',
     'calRecurrenceRule.js'
 ]
--- a/calendar/base/modules/calUtils.jsm
+++ b/calendar/base/modules/calUtils.jsm
@@ -164,51 +164,16 @@ var cal = {
      * @param {nsIIDRef} aIID       The IID to query for
      * @param {nsIIDRef[]}          The interfaces that this object implements
      * @return {nsQIResult}         The object queried for aIID
      */
     generateClassQI: function(aGlobal, aIID, aInterfaces) {
         Object.defineProperty(aGlobal, "QueryInterface", { value: XPCOMUtils.generateQI(aInterfaces) });
         return aGlobal.QueryInterface(aIID);
     },
-    /**
-     * Loads an array of calendar scripts into the passed scope.
-     *
-     * @param scriptNames an array of calendar script names
-     * @param scope       scope to load into
-     */
-    loadScripts: function(scriptNames, scope) {
-        let baseUri = "resource://calendar/calendar-js/";
-        for (let script of scriptNames) {
-            if (!script) {
-                // If the array element is null, then just skip this script.
-                continue;
-            }
-            let scriptUrlSpec = baseUri + script;
-            try {
-                Services.scriptloader.loadSubScript(scriptUrlSpec, scope);
-            } catch (exc) {
-                Components.utils.reportError(exc + " (" + scriptUrlSpec + ")");
-            }
-        }
-    },
-
-    loadingNSGetFactory: function(scriptNames, components, scope) {
-        return function(cid) {
-            if (!this.inner) {
-                let global = Components.utils.getGlobalForObject(scope);
-                cal.loadScripts(scriptNames, global);
-                if (typeof components == "function") {
-                    components = components.call(global);
-                }
-                this.inner = XPCOMUtils.generateNSGetFactory(components);
-            }
-            return this.inner(cid);
-        };
-    },
 
     /**
      * Schedules execution of the passed function to the current thread's queue.
      */
     postPone: function(func) {
         if (this.threadingEnabled) {
             Services.tm.currentThread.dispatch({ run: func },
                                                Components.interfaces.nsIEventTarget.DISPATCH_NORMAL);
--- a/calendar/base/src/calItemModule.js
+++ b/calendar/base/src/calItemModule.js
@@ -1,66 +1,51 @@
 /* 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/. */
 
-ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-
-var scriptLoadOrder = [
-    "calItemBase.js",
-    "calCachedCalendar.js",
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-    "calAlarm.js",
-    "calAlarmService.js",
-    "calAlarmMonitor.js",
-    "calAttendee.js",
-    "calAttachment.js",
-    "calCalendarManager.js",
-    "calCalendarSearchService.js",
-    "calDateTimeFormatter.js",
-    "calDeletedItems.js",
-    "calEvent.js",
-    "calFreeBusyService.js",
-    "calIcsParser.js",
-    "calIcsSerializer.js",
-    "calItipItem.js",
-    "calProtocolHandler.js",
-    "calRecurrenceDate.js",
-    "calRecurrenceInfo.js",
-    "calRelation.js",
-    "calStartupService.js",
-    "calTransactionManager.js",
-    "calTodo.js",
-    "calWeekInfoService.js"
-];
+this.NSGetFactory = (cid) => {
+    let scriptLoadOrder = [
+        "resource://calendar/calendar-js/calItemBase.js",
+        "resource://calendar/calendar-js/calCachedCalendar.js",
 
-function getComponents() {
-    Components.classes["@mozilla.org/calendar/backend-loader;1"].getService();
+        "resource://calendar/calendar-js/calAlarm.js",
+        "resource://calendar/calendar-js/calAlarmService.js",
+        "resource://calendar/calendar-js/calAlarmMonitor.js",
+        "resource://calendar/calendar-js/calAttendee.js",
+        "resource://calendar/calendar-js/calAttachment.js",
+        "resource://calendar/calendar-js/calCalendarManager.js",
+        "resource://calendar/calendar-js/calCalendarSearchService.js",
+        "resource://calendar/calendar-js/calDateTimeFormatter.js",
+        "resource://calendar/calendar-js/calDeletedItems.js",
+        "resource://calendar/calendar-js/calEvent.js",
+        "resource://calendar/calendar-js/calFreeBusyService.js",
+        "resource://calendar/calendar-js/calIcsParser.js",
+        "resource://calendar/calendar-js/calIcsSerializer.js",
+        "resource://calendar/calendar-js/calItipItem.js",
+        "resource://calendar/calendar-js/calProtocolHandler.js",
+        "resource://calendar/calendar-js/calRecurrenceDate.js",
+        "resource://calendar/calendar-js/calRecurrenceInfo.js",
+        "resource://calendar/calendar-js/calRelation.js",
+        "resource://calendar/calendar-js/calStartupService.js",
+        "resource://calendar/calendar-js/calTransactionManager.js",
+        "resource://calendar/calendar-js/calTodo.js",
+        "resource://calendar/calendar-js/calWeekInfoService.js"
+    ];
 
-    return [
-        calAlarm,
-        calAlarmService,
-        calAlarmMonitor,
-        calAttendee,
-        calAttachment,
-        calCalendarManager,
-        calCalendarSearchService,
-        calDateTimeFormatter,
-        calDeletedItems,
-        calEvent,
-        calFreeBusyService,
-        calIcsParser,
-        calIcsSerializer,
-        calItipItem,
-        calProtocolHandlerWebcal,
-        calProtocolHandlerWebcals,
-        calRecurrenceDate,
-        calRecurrenceInfo,
-        calRelation,
-        calStartupService,
-        calTransaction,
-        calTransactionManager,
-        calTodo,
-        calWeekInfoService,
+    for (let script of scriptLoadOrder) {
+        Services.scriptloader.loadSubScript(script, this);
+    }
+
+    let components = [
+        calAlarm, calAlarmService, calAlarmMonitor, calAttendee, calAttachment, calCalendarManager,
+        calCalendarSearchService, calDateTimeFormatter, calDeletedItems, calEvent, calFreeBusyService,
+        calIcsParser, calIcsSerializer, calItipItem, calProtocolHandlerWebcal,
+        calProtocolHandlerWebcals, calRecurrenceDate, calRecurrenceInfo, calRelation,
+        calStartupService, calTransaction, calTransactionManager, calTodo, calWeekInfoService,
     ];
-}
 
-this.NSGetFactory = cal.loadingNSGetFactory(scriptLoadOrder, getComponents, this);
+    this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
+    return this.NSGetFactory(cid);
+};
--- a/calendar/base/src/calTimezoneService.js
+++ b/calendar/base/src/calTimezoneService.js
@@ -804,9 +804,13 @@ function guessSystemTimezone() {
     } catch (ex) { // don't abort if error occurs warning user
         Components.utils.reportError(ex);
     }
 
     // return the guessed timezone
     return probableTZId;
 }
 
-this.NSGetFactory = cal.loadingNSGetFactory(["calTimezone.js"], [calTimezoneService], this);
+this.NSGetFactory = (cid) => {
+    Services.scriptloader.loadSubScript("resource://calendar/calendar-js/calTimezone.js", this);
+    this.NSGetFactory = XPCOMUtils.generateNSGetFactory([calTimezoneService]);
+    return this.NSGetFactory(cid);
+};
--- a/calendar/import-export/calImportExportModule.js
+++ b/calendar/import-export/calImportExportModule.js
@@ -1,31 +1,30 @@
 /* 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/. */
 
-ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-var scriptLoadOrder = [
-    "calIcsImportExport.js",
-    "calHtmlExport.js",
-    "calOutlookCSVImportExport.js",
-
-    "calListFormatter.js",
-    "calMonthGridPrinter.js",
-    "calWeekPrinter.js"
-];
+this.NSGetFactory = (cid) => {
+    let scriptLoadOrder = [
+        "resource://calendar/calendar-js/calIcsImportExport.js",
+        "resource://calendar/calendar-js/calHtmlExport.js",
+        "resource://calendar/calendar-js/calOutlookCSVImportExport.js",
 
-function getComponents() {
-    return [
-        calIcsImporter,
-        calIcsExporter,
-        calHtmlExporter,
-        calOutlookCSVImporter,
-        calOutlookCSVExporter,
+        "resource://calendar/calendar-js/calListFormatter.js",
+        "resource://calendar/calendar-js/calMonthGridPrinter.js",
+        "resource://calendar/calendar-js/calWeekPrinter.js"
+    ];
+
+    for (let script of scriptLoadOrder) {
+        Services.scriptloader.loadSubScript(script, this);
+    }
 
-        calListFormatter,
-        calMonthPrinter,
-        calWeekPrinter
+    let components = [
+        calIcsImporter, calIcsExporter, calHtmlExporter, calOutlookCSVImporter,
+        calOutlookCSVExporter, calListFormatter, calMonthPrinter, calWeekPrinter
     ];
-}
 
-this.NSGetFactory = cal.loadingNSGetFactory(scriptLoadOrder, getComponents, this);
+    this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
+    return this.NSGetFactory(cid);
+};
--- a/calendar/providers/caldav/calDavCalendar.js
+++ b/calendar/providers/caldav/calDavCalendar.js
@@ -3016,13 +3016,13 @@ calDavObserver.prototype = {
 
     onError: function(aCalendar, aErrNo, aMessage) {
         this.mCalendar.readOnly = true;
         this.mCalendar.notifyError(aErrNo, aMessage);
     }
 };
 
 /** Module Registration */
-var scriptLoadOrder = [
-    "calDavRequestHandlers.js"
-];
-
-this.NSGetFactory = cal.loadingNSGetFactory(scriptLoadOrder, [calDavCalendar], this);
+this.NSGetFactory = (cid) => {
+    Services.scriptloader.loadSubScript("resource://calendar/calendar-js/calDavRequestHandlers.js", this);
+    this.NSGetFactory = XPCOMUtils.generateNSGetFactory([calDavCalendar]);
+    return this.NSGetFactory(cid);
+};
--- a/calendar/providers/wcap/calWcapCalendarModule.js
+++ b/calendar/providers/wcap/calWcapCalendarModule.js
@@ -62,28 +62,28 @@ function initWcapProvider() {
         CACHE_LAST_RESULTS = Preferences.get("calendar.wcap.cache_last_results", 4);
         CACHE_LAST_RESULTS_INVALIDATE = Preferences.get("calendar.wcap.cache_last_results_invalidate", 120);
     } catch (exc) {
         logError(exc, "error in init sequence");
     }
 }
 
 /** Module Registration */
-var scriptLoadOrder = [
-    "calWcapUtils.js",
-    "calWcapErrors.js",
-    "calWcapRequest.js",
-    "calWcapSession.js",
-    "calWcapCalendar.js",
-    "calWcapCalendarItems.js"
-];
+this.NSGetFactory = (cid) => {
+    let scriptLoadOrder = [
+        "resource://calendar/calendar-js/calWcapUtils.js",
+        "resource://calendar/calendar-js/calWcapErrors.js",
+        "resource://calendar/calendar-js/calWcapRequest.js",
+        "resource://calendar/calendar-js/calWcapSession.js",
+        "resource://calendar/calendar-js/calWcapCalendar.js",
+        "resource://calendar/calendar-js/calWcapCalendarItems.js"
+    ];
 
-function getComponents() {
+    for (let script of scriptLoadOrder) {
+        Services.scriptloader.loadSubScript(script, this);
+    }
+
     initWcapProvider();
 
-    return [
-        calWcapCalendar,
-        calWcapNetworkRequest,
-        calWcapSession
-    ];
-}
-
-this.NSGetFactory = cal.loadingNSGetFactory(scriptLoadOrder, getComponents, this);
+    let components = [calWcapCalendar, calWcapNetworkRequest, calWcapSession];
+    this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
+    return this.NSGetFactory(cid);
+};
--- a/calendar/test/unit/head_consts.js
+++ b/calendar/test/unit/head_consts.js
@@ -20,16 +20,20 @@ updateAppInfo();
 
 (function() {
     let bindir = Services.dirsvc.get("CurProcD", Components.interfaces.nsIFile);
     bindir.append("extensions");
     bindir.append("{e2fda1a4-762b-4020-b5ad-a41df1933103}");
     bindir.append("chrome.manifest");
     dump("Loading" + bindir.path + "\n");
     Components.manager.autoRegister(bindir);
+
+    // Make sure to load the backend loader as early as possible, as xpcshell doesn't have the
+    // normal app flow with profile-after-change et al.
+    Components.classes["@mozilla.org/calendar/backend-loader;1"].getService();
 })();
 
 ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 
 function createDate(aYear, aMonth, aDay, aHasTime, aHour, aMinute, aSecond, aTimezone) {
     let date = Cc["@mozilla.org/calendar/datetime;1"]
                .createInstance(Ci.calIDateTime);
     date.resetTo(aYear,