Created
September 7, 2016 19:58
-
-
Save rhelmer/78cfa5866f28cea30dab956afaa07600 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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