Bug 1330349 - Part 2 - install and present theme type WebExtensions as themes in the Addon Manager. r=mossop
authorMike de Boer <mdeboer@mozilla.com>
Thu, 02 Mar 2017 14:22:17 +0100
changeset 394543 5e294c7848fc702e38e0b00d560aa298cee24ba1
parent 394542 3d4b1e6c6197f84a79bd7bfc74d0cf57b72a40ca
child 394544 db77e56b25d541f2d330179e8c6f1609500f911f
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmossop
bugs1330349
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1330349 - Part 2 - install and present theme type WebExtensions as themes in the Addon Manager. r=mossop MozReview-Commit-ID: 5J9BDekC7dx
toolkit/mozapps/extensions/internal/E10SAddonsRollout.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
--- a/toolkit/mozapps/extensions/internal/E10SAddonsRollout.jsm
+++ b/toolkit/mozapps/extensions/internal/E10SAddonsRollout.jsm
@@ -946,17 +946,17 @@ Object.defineProperty(this, "isAddonPart
     if (aAddon.mpcOptedOut == true) {
       return false;
     }
 
     if (policy.alladdons) {
       return true;
     }
 
-    if (policy.webextensions && aAddon.type == "webextension") {
+    if (policy.webextensions && (aAddon.type == "webextension" || aAddon.type == "webextension-theme")) {
       return true;
     }
 
     if (policy.mpc && aAddon.multiprocessCompatible) {
       return true;
     }
 
     if (policy.addonsv2) {
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -237,39 +237,42 @@ const TYPES = {
 };
 
 if (!AppConstants.RELEASE_OR_BETA)
   TYPES.apiextension = 256;
 
 // Some add-on types that we track internally are presented as other types
 // externally
 const TYPE_ALIASES = {
+  "apiextension": "extension",
   "webextension": "extension",
-  "apiextension": "extension",
+  "webextension-theme": "theme",
 };
 
 const CHROME_TYPES = new Set([
   "extension",
   "locale",
   "experiment",
 ]);
 
 const RESTARTLESS_TYPES = new Set([
-  "webextension",
+  "apiextension",
   "dictionary",
   "experiment",
   "locale",
-  "apiextension",
+  "webextension",
+  "webextension-theme",
 ]);
 
 const SIGNED_TYPES = new Set([
-  "webextension",
+  "apiextension",
   "extension",
   "experiment",
-  "apiextension",
+  "webextension",
+  "webextension-theme",
 ]);
 
 // This is a random number array that can be used as "salt" when generating
 // an automatic ID based on the directory path of an add-on. It will prevent
 // someone from creating an ID for a permanent add-on that could be replaced
 // by a temporary add-on (because that would be confusing, I guess).
 const TEMP_INSTALL_ID_GEN_SESSION =
   new Uint8Array(Float64Array.of(Math.random()).buffer);
@@ -396,16 +399,27 @@ function findMatchingStaticBlocklistItem
 /**
  * Converts an iterable of addon objects into a map with the add-on's ID as key.
  */
 function addonMap(addons) {
   return new Map(addons.map(a => [a.id, a]));
 }
 
 /**
+ * Helper function that determines whether an addon of a certain type is a
+ * WebExtension.
+ *
+ * @param  {String} type
+ * @return {Boolean}
+ */
+function isWebExtension(type) {
+  return type == "webextension" || type == "webextension-theme";
+}
+
+/**
  * Sets permissions on a file
  *
  * @param  aFile
  *         The file or directory to operate on.
  * @param  aPermissions
  *         The permisions to set
  */
 function setFilePermissions(aFile, aPermissions) {
@@ -928,16 +942,17 @@ function getRDFProperty(aDs, aResource, 
 var loadManifestFromWebManifest = Task.async(function*(aUri) {
   // We're passed the URI for the manifest file. Get the URI for its
   // parent directory.
   let uri = NetUtil.newURI("./", null, aUri);
 
   let extension = new ExtensionData(uri);
 
   let manifest = yield extension.readManifest();
+  let theme = !!manifest.theme;
 
   // Read the list of available locales, and pre-load messages for
   // all locales.
   let locales = yield extension.initAllLocales();
 
   // If there were any errors loading the extension, bail out now.
   if (extension.errors.length)
     throw new Error("Extension is invalid");
@@ -951,17 +966,17 @@ var loadManifestFromWebManifest = Task.a
   // A * is illegal in strict_min_version
   if (bss.strict_min_version && bss.strict_min_version.split(".").some(part => part == "*")) {
     throw new Error("The use of '*' in strict_min_version is invalid");
   }
 
   let addon = new AddonInternal();
   addon.id = bss.id;
   addon.version = manifest.version;
-  addon.type = "webextension";
+  addon.type = "webextension" + (theme ? "-theme" : "");
   addon.unpack = false;
   addon.strictCompatibility = true;
   addon.bootstrap = true;
   addon.hasBinaryComponents = false;
   addon.multiprocessCompatible = true;
   addon.internalName = null;
   addon.updateURL = bss.update_url;
   addon.updateKey = null;
@@ -4435,18 +4450,19 @@ this.XPIProvider = {
    * Determine if an add-on should be blocking e10s if enabled.
    *
    * @param  aAddon
    *         The add-on to test
    * @return true if enabling the add-on should block e10s
    */
   isBlockingE10s(aAddon) {
     if (aAddon.type != "extension" &&
+        aAddon.type != "theme" &&
         aAddon.type != "webextension" &&
-        aAddon.type != "theme")
+        aAddon.type != "webextension-theme")
       return false;
 
     // The hotfix is exempt
     let hotfixID = Preferences.get(PREF_EM_HOTFIX_ID, undefined);
     if (hotfixID && hotfixID == aAddon.id)
       return false;
 
     // The default theme is exempt
@@ -4723,17 +4739,17 @@ this.XPIProvider = {
                                     metadata: { addonID: aId } });
       logger.error("Attempted to load bootstrap scope from missing directory " + aFile.path);
       return;
     }
 
     let uri = getURIForResourceInFile(aFile, "bootstrap.js").spec;
     if (aType == "dictionary")
       uri = "resource://gre/modules/addons/SpellCheckDictionaryBootstrap.js"
-    else if (aType == "webextension")
+    else if (isWebExtension(aType))
       uri = "resource://gre/modules/addons/WebExtensionBootstrap.js"
     else if (aType == "apiextension")
       uri = "resource://gre/modules/addons/APIExtensionBootstrap.js"
 
     activeAddon.bootstrapScope =
       new Cu.Sandbox(principal, { sandboxName: uri,
                                   wantGlobalProperties: ["indexedDB"],
                                   addonId: aId,
@@ -5523,17 +5539,17 @@ class AddonInstall {
       if (this.existingAddon) {
         // Check various conditions related to upgrades
         if (this.addon.id != this.existingAddon.id) {
           zipreader.close();
           return Promise.reject([AddonManager.ERROR_INCORRECT_ID,
                                  `Refusing to upgrade addon ${this.existingAddon.id} to different ID ${this.addon.id}`]);
         }
 
-        if (this.existingAddon.type == "webextension" && this.addon.type != "webextension") {
+        if (isWebExtension(this.existingAddon.type) && !isWebExtension(this.addon.type)) {
           zipreader.close();
           return Promise.reject([AddonManager.ERROR_UNEXPECTED_ADDON_TYPE,
                                  "WebExtensions may not be upated to other extension types"]);
         }
       }
 
       if (mustSign(this.addon.type)) {
         if (this.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
@@ -7206,17 +7222,17 @@ AddonWrapper.prototype = {
     XPIDatabase.saveChanges();
   },
 
   get type() {
     return getExternalType(addonFor(this).type);
   },
 
   get isWebExtension() {
-    return addonFor(this).type == "webextension";
+    return isWebExtension(addonFor(this).type);
   },
 
   get temporarilyInstalled() {
     return addonFor(this)._installLocation == TemporaryInstallLocation;
   },
 
   get aboutURL() {
     return this.isActive ? addonFor(this)["aboutURL"] : null;