Skip to content

Instantly share code, notes, and snippets.

@rhelmer
Created September 7, 2016 19:58
Show Gist options
  • Select an option

  • Save rhelmer/78cfa5866f28cea30dab956afaa07600 to your computer and use it in GitHub Desktop.

Select an option

Save rhelmer/78cfa5866f28cea30dab956afaa07600 to your computer and use it in GitHub Desktop.
diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -6591,17 +6591,19 @@ AddonInstall.createSystemAddonInstall =
let location = XPIProvider.installLocationsByName[KEY_APP_SYSTEM_ADDONS];
let file = location.getFileForAddonID(aAddonID);
let url = Services.io.newFileURI(file);
try {
let manifest = syncLoadManifestFromFile(file, location);
let install = new AddonInstall(location, url);
- install.initStagedInstall(manifest);
+
+ install.state = AddonManager.STATE_DOWNLOADED;
+ install.addon = manifest;
install.file = file;
makeSafe(aCallback)(install);
}
catch (e) {
logger.error("Error creating install", e);
makeSafe(aCallback)(null);
}
@@ -8487,22 +8489,60 @@ function SystemAddonInstallLocation(aNam
this._directory.append(this._addonSet.directory);
logger.info("SystemAddonInstallLocation scanning directory " + this._directory.path);
}
else {
logger.info("SystemAddonInstallLocation directory is missing");
}
DirectoryInstallLocation.call(this, aName, this._directory, aScope);
- this.locked = true;
+ this.locked = false;
}
SystemAddonInstallLocation.prototype = Object.create(DirectoryInstallLocation.prototype);
Object.assign(SystemAddonInstallLocation.prototype, {
/**
+ * Gets the staging directory to put add-ons that are pending install and
+ * uninstall into.
+ *
+ * @return an nsIFile
+ */
+ getStagingDir: function() {
+ let dir = this._baseDir.clone();
+ dir.append(DIR_STAGE);
+ return dir;
+ },
+
+ requestStagingDir: function() {
+ this._stagingDirLock++;
+
+ if (this._stagingDirPromise)
+ return this._stagingDirPromise;
+
+ OS.File.makeDir(this._baseDir.path);
+ let stagepath = OS.Path.join(this._baseDir.path, DIR_STAGE);
+ return this._stagingDirPromise = OS.File.makeDir(stagepath).then(null, (e) => {
+ if (e instanceof OS.File.Error && e.becauseExists)
+ return;
+ logger.error("Failed to create system add-on staging directory", e);
+ throw e;
+ });
+ },
+
+ releaseStagingDir: function() {
+ this._stagingDirLock--;
+
+ if (this._stagingDirLock == 0) {
+ this._stagingDirPromise = null;
+ this.cleanStagingDir();
+ }
+
+ return Promise.resolve();
+ },
+ /**
* Reads the current set of system add-ons
*/
_loadAddonSet: function() {
try {
let setStr = Preferences.get(PREF_SYSTEM_ADDON_SET, null);
if (setStr) {
let addonSet = JSON.parse(setStr);
if ((typeof addonSet == "object") && addonSet.schema == 1)
@@ -8587,16 +8627,21 @@ Object.assign(SystemAddonInstallLocation
return true;
},
/**
* Resets the add-on set so on the next startup the default set will be used.
*/
resetAddonSet: function() {
+ logger.info("Removing all system add-on upgrades.");
+ for (let id of Object.keys(this._addonSet.addons)) {
+ let addon = yield new Promise(resolve => AddonManager.getAddonByID(addonID, resolve));
+ addon.uninstall();
+ }
this._saveAddonSet({ schema: 1, addons: {} });
},
/**
* Removes any directories not currently in use or pending use after a
* restart. Any errors that happen here don't really matter as we'll attempt
* to cleanup again next time.
*/
@@ -8656,31 +8701,45 @@ Object.assign(SystemAddonInstallLocation
/**
* Installs a new set of system add-ons into the location and updates the
* add-on set in prefs. We wait to switch state until a restart.
*/
installAddonSet: Task.async(function*(aAddons) {
// Make sure the base dir exists
yield OS.File.makeDir(this._baseDir.path, { ignoreExisting: true });
+ let addonSet = this._loadAddonSet();
+
+ // Remove any add-ons that are no longer part of the set.
+ let oldAddons = new Set(Object.keys(addonSet.addons));
+ let newAddons = new Set(aAddons);
+ var difference = new Set([...oldAddons].filter(x => !newAddons.has(x)));
+
+ if (difference.size > 0) {
+ for (let addonID of difference.values()) {
+ let addon = yield new Promise(resolve => AddonManager.getAddonByID(addonID, resolve));
+ addon.uninstall();
+ }
+ }
+
let newDir = this._baseDir.clone();
let uuidGen = Cc["@mozilla.org/uuid-generator;1"].
getService(Ci.nsIUUIDGenerator);
newDir.append("blank");
while (true) {
newDir.leafName = uuidGen.generateUUID().toString();
try {
yield OS.File.makeDir(newDir.path, { ignoreExisting: false });
break;
}
catch (e) {
- // Directory already exists, pick another
+ logger.debug("Could not create new system add-on updates dir, retrying", e);
}
}
let copyAddon = Task.async(function*(addon) {
let target = OS.Path.join(newDir.path, addon.id + ".xpi");
logger.info(`Copying ${addon.id} from ${addon._sourceBundle.path} to ${target}.`);
try {
yield OS.File.copy(addon._sourceBundle.path, target);
@@ -8712,22 +8771,18 @@ Object.assign(SystemAddonInstallLocation
version: addon.version
}
}
this._saveAddonSet(state);
this._nextDir = newDir;
let installAddon = Task.async(function*(addon) {
- AddonManager.getInstallForSystemAddon(addon.id, install => {
- // TODO support upgrade too not just install
- let reason = BOOTSTRAP_REASONS.ADDON_INSTALL;
- XPIProvider.callBootstrapMethod(addon, install.file,
- "startup", reason, {});
- });
+ let install = yield new Promise(resolve => AddonManager.getInstallForSystemAddon(addon.id, resolve));
+ install.install();
});
try {
yield waitForAllPromises(aAddons.map(installAddon));
}
catch (e) {
// TODO roll back to previous state
try {
@@ -8736,16 +8791,46 @@ Object.assign(SystemAddonInstallLocation
catch (e) {
logger.warn(`Failed to remove new system add-on directory ${newDir.path}.`, e);
}
throw e;
}
}),
/**
+ * Installs an add-on into the install location.
+ *
+ * @param aId
+ * The ID of the add-on to install
+ * @param aSource
+ * The source nsIFile to install from
+ * @param aExistingAddonID
+ * The ID of an existing add-on to uninstall at the same time
+ * @param aCopy
+ * If false the source files will be moved to the new location,
+ * otherwise they will only be copied
+ * @return an nsIFile indicating where the add-on was installed to
+ */
+ installAddon: function(aId, aSource, aExistingAddonID, aCopy) {
+ let addonSet = this._loadAddonSet();
+ let directory = this._baseDir.clone();
+ if (addonSet.directory) {
+ directory.append(addonSet.directory);
+ directory.append(`${aId}.xpi`);
+
+ return directory;
+ } else {
+ logger.error("Could not install system add-on: no directory is configured.");
+ }
+ },
+
+ // FIXME implement
+ uninstallAddon: (aAddon) => {},
+
+ /**
* Returns a file pointer to a XPI already present in this location.
*
* @param {string} aAddonID - the Addon ID.
* @returns {nsIFile} File pointer to the XPI.
*/
getFileForAddonID: function(aAddonID) {
let xpi = this._nextDir.clone();
xpi.append(`${aAddonID}.xpi`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment