Bug 760356: #1 Always request all add-ons when loading AddonRepository; r=unfocused

This commit is contained in:
Irving Reid 2014-05-20 13:16:37 -04:00
parent c3d07ebc37
commit 2f534f79b1
5 changed files with 78 additions and 83 deletions

View File

@ -1160,39 +1160,38 @@ var AddonManagerInternal = {
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", scope);
scope.LightweightThemeManager.updateCurrentTheme();
let aAddons = yield new Promise((resolve, reject) => this.getAllAddons(resolve));
// If there is a known hotfix then exclude it from the list of add-ons to update.
var ids = [a.id for each (a in aAddons) if (a.id != hotfixID)];
let allAddons = yield new Promise((resolve, reject) => this.getAllAddons(resolve));
// Repopulate repository cache first, to ensure compatibility overrides
// are up to date before checking for addon updates.
yield new Promise((resolve, reject) => AddonRepository.backgroundUpdateCheck(ids, resolve));
yield AddonRepository.backgroundUpdateCheck();
// Keep track of all the async add-on updates happening in parallel
let updates = [];
for (let aAddon of aAddons) {
if (aAddon.id == hotfixID) {
for (let addon of allAddons) {
if (addon.id == hotfixID) {
continue;
}
// Check all add-ons for updates so that any compatibility updates will
// be applied
updates.push(new Promise((resolve, reject) => {
aAddon.findUpdates({
addon.findUpdates({
onUpdateAvailable: function BUC_onUpdateAvailable(aAddon, aInstall) {
// Start installing updates when the add-on can be updated and
// background updates should be applied.
logger.debug("Found update for add-on ${id}", aAddon);
if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE &&
AddonManager.shouldAutoUpdate(aAddon)) {
// XXX we really should resolve when this install is done,
// not when update-available check completes, no?
logger.debug("Starting install of ${id}", aAddon);
aInstall.install();
}
},
onUpdateFinished: resolve
onUpdateFinished: aAddon => { logger.debug("onUpdateFinished for ${id}", aAddon); resolve(); }
}, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
}));
}

View File

@ -66,14 +66,16 @@ var gChecking = {
showButtons(true, false, false, false);
this._progress = document.getElementById("checking-progress");
let self = this;
AddonManager.getAllAddons(function gChecking_getAllAddons(aAddons) {
AddonManager.getAllAddons(aAddons => {
if (aAddons.length == 0) {
window.close();
return;
}
aAddons = aAddons.filter(function gChecking_filterAddons(aAddon) {
if (aAddon.id == AddonManager.hotfixID) {
return false;
}
if (aAddon.type == "plugin" || aAddon.type == "service")
return false;
@ -89,15 +91,12 @@ var gChecking = {
return true;
});
self._addonCount = aAddons.length;
self._progress.value = 0;
self._progress.max = aAddons.length;
self._progress.mode = "determined";
this._addonCount = aAddons.length;
this._progress.value = 0;
this._progress.max = aAddons.length;
this._progress.mode = "determined";
// Ensure compatibility overrides are up to date before checking for
// individual addon updates.
let ids = [addon.id for each (addon in aAddons)];
AddonRepository.repopulateCache(ids, function gChecking_repopulateCache() {
AddonRepository.repopulateCache().then(() => {
for (let addonItem of aAddons) {
// Ignore disabled themes
if (addonItem.type != "theme" || !addonItem.userDisabled) {
@ -108,7 +107,7 @@ var gChecking = {
}
}
addonItem.findUpdates(self, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
addonItem.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
}
});
});

View File

@ -10,7 +10,6 @@
const PREF_UPDATE_EXTENSIONS_ENABLED = "extensions.update.enabled";
const PREF_XPINSTALL_ENABLED = "xpinstall.enabled";
const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
// timeout (in milliseconds) to wait for response to the metadata ping
const METADATA_TIMEOUT = 30000;
@ -181,19 +180,14 @@ var gVersionInfoPage = {
"nextButtonText", true,
"cancelButtonText", false);
try {
var hotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID);
}
catch (e) { }
// Retrieve all add-ons in order to sync their app compatibility information
AddonManager.getAllAddons(function gVersionInfoPage_getAllAddons(aAddons) {
AddonManager.getAllAddons(aAddons => {
if (gUpdateWizard.shuttingDown) {
logger.debug("getAllAddons completed after dialog closed");
}
gUpdateWizard.addons = [a for (a of aAddons)
if (a.type != "plugin" && a.id != hotfixID)];
if (a.type != "plugin" && a.id != AddonManager.hotfixID)];
gVersionInfoPage._totalCount = gUpdateWizard.addons.length;
@ -206,12 +200,8 @@ var gVersionInfoPage = {
// Ensure compatibility overrides are up to date before checking for
// individual addon updates.
let ids = [addon.id for (addon of gUpdateWizard.addons)];
// Do the metadata ping, listening for any newly enabled/disabled add-ons.
AddonManager.addAddonListener(listener);
AddonRepository.repopulateCache(ids, function gVersionInfoPage_repopulateCache() {
AddonRepository.repopulateCache(METADATA_TIMEOUT).then(() => {
if (gUpdateWizard.shuttingDown) {
logger.debug("repopulateCache completed after dialog closed");
}
@ -220,7 +210,7 @@ var gVersionInfoPage = {
logger.debug("VersionInfo Finding updates for " + addon.id);
addon.findUpdates(gVersionInfoPage, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
}
}, METADATA_TIMEOUT);
});
});
},

View File

@ -595,58 +595,72 @@ this.AddonRepository = {
* corresponding to the specified ids. If caching is disabled,
* the cache is completely removed.
*
* @param aIds
* The array of add-on ids to repopulate the cache with
* @param aCallback
* The optional callback to call once complete
* @param aTimeout
* (Optional) timeout in milliseconds to abandon the XHR request
* if we have not received a response from the server.
* @return Promise{null}
* Resolves when the metadata ping is complete
*/
repopulateCache: function(aIds, aCallback, aTimeout) {
this._repopulateCacheInternal(aIds, aCallback, false, aTimeout);
repopulateCache: function(aTimeout) {
return this._repopulateCacheInternal(false, aTimeout);
},
_repopulateCacheInternal: function (aIds, aCallback, aSendPerformance, aTimeout) {
// Always call AddonManager updateAddonRepositoryData after we refill the cache
function repopulateAddonManager() {
AddonManagerPrivate.updateAddonRepositoryData(aCallback);
}
/*
* Clear and delete the AddonRepository database
* @return Promise{null} resolves when the database is deleted
*/
_clearCache: function () {
this._addons = null;
this._pendingCallbacks = null;
return AddonDatabase.delete().then(() =>
new Promise((resolve, reject) =>
AddonManagerPrivate.updateAddonRepositoryData(resolve))
);
},
_repopulateCacheInternal: Task.async(function* (aSendPerformance, aTimeout) {
let allAddons = yield new Promise((resolve, reject) =>
AddonManager.getAllAddons(resolve));
// Filter the hotfix out of our list of add-ons
let allAddons = [a for (a of allAddons) if (a.id != AddonManager.hotfixID)];
logger.debug("Repopulate add-on cache with " + aIds.toSource());
// Completely remove cache if caching is not enabled
if (!this.cacheEnabled) {
logger.debug("Clearing cache because it is disabled");
this._addons = null;
this._pendingCallbacks = null;
AddonDatabase.delete(repopulateAddonManager);
return;
return this._clearCache();
}
let self = this;
getAddonsToCache(aIds, function repopulateCache_getAddonsToCache(aAddons) {
// Completely remove cache if there are no add-ons to cache
if (aAddons.length == 0) {
logger.debug("Clearing cache because 0 add-ons were requested");
self._addons = null;
self._pendingCallbacks = null;
AddonDatabase.delete(repopulateAddonManager);
return;
}
let ids = [a.id for (a of allAddons)];
logger.debug("Repopulate add-on cache with " + ids.toSource());
self._beginGetAddons(aAddons, {
let self = this;
let addonsToCache = yield new Promise((resolve, reject) =>
getAddonsToCache(ids, resolve));
// Completely remove cache if there are no add-ons to cache
if (addonsToCache.length == 0) {
logger.debug("Clearing cache because 0 add-ons were requested");
return this._clearCache();
}
yield new Promise((resolve, reject) =>
self._beginGetAddons(addonsToCache, {
searchSucceeded: function repopulateCacheInternal_searchSucceeded(aAddons) {
self._addons = {};
aAddons.forEach(function(aAddon) { self._addons[aAddon.id] = aAddon; });
AddonDatabase.repopulate(aAddons, repopulateAddonManager);
AddonDatabase.repopulate(aAddons, resolve);
},
searchFailed: function repopulateCacheInternal_searchFailed() {
logger.warn("Search failed when repopulating cache");
repopulateAddonManager();
resolve();
}
}, aSendPerformance, aTimeout);
});
},
}, aSendPerformance, aTimeout));
// Always call AddonManager updateAddonRepositoryData after we refill the cache
yield new Promise((resolve, reject) =>
AddonManagerPrivate.updateAddonRepositoryData(resolve));
}),
/**
* Asynchronously add add-ons to the cache corresponding to the specified
@ -862,14 +876,10 @@ this.AddonRepository = {
* data. It is meant to be called as part of the daily update ping. It should
* not be used for any other purpose. Use repopulateCache instead.
*
* @param aIDs
* Array of add-on IDs to repopulate the cache with.
* @param aCallback
* Function to call when data is received. Function must be an object
* with the keys searchSucceeded and searchFailed.
* @return Promise{null} Resolves when the metadata update is complete.
*/
backgroundUpdateCheck: function AddonRepo_backgroundUpdateCheck(aIDs, aCallback) {
this._repopulateCacheInternal(aIDs, aCallback, true);
backgroundUpdateCheck: function () {
return this._repopulateCacheInternal(true);
},
/**
@ -1652,6 +1662,7 @@ var AddonDatabase = {
*
* @param aCallback
* An optional callback to call once complete
* @return Promise{null} resolves when the database has been deleted
*/
delete: function AD_delete(aCallback) {
this.DB = BLANK_DB();
@ -1665,6 +1676,7 @@ var AddonDatabase = {
this.jsonFile, error))
.then(() => this._deleting = null)
.then(aCallback);
return this._deleting;
},
toJSON: function AD_toJSON() {

View File

@ -551,8 +551,7 @@ add_task(function* run_test_3() {
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_FAILED);
yield new Promise((resolve, reject) =>
AddonRepository.repopulateCache(ADDON_IDS, resolve));
yield AddonRepository.repopulateCache();
yield check_initialized_cache([false, false, false]);
});
@ -560,8 +559,7 @@ add_task(function* run_test_3() {
add_task(function* run_test_4() {
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_EMPTY);
yield new Promise((resolve, reject) =>
AddonRepository.repopulateCache(ADDON_IDS, resolve));
yield AddonRepository.repopulateCache();
yield check_initialized_cache([false, false, false]);
});
@ -569,8 +567,7 @@ add_task(function* run_test_4() {
add_task(function* run_test_5() {
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_RESULTS);
yield new Promise((resolve, reject) =>
AddonRepository.repopulateCache(ADDON_IDS, resolve));
yield AddonRepository.repopulateCache();
yield check_initialized_cache([true, true, true]);
});
@ -578,8 +575,7 @@ add_task(function* run_test_5() {
add_task(function* run_test_5_1() {
Services.prefs.setBoolPref(PREF_ADDON0_CACHE_ENABLED, false);
yield new Promise((resolve, reject) =>
AddonRepository.repopulateCache(ADDON_IDS, resolve));
yield AddonRepository.repopulateCache();
// Reset pref for next test
Services.prefs.setBoolPref(PREF_ADDON0_CACHE_ENABLED, true);
@ -592,8 +588,7 @@ add_task(function* run_test_6() {
do_check_true(gDBFile.exists());
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
yield new Promise((resolve, reject) =>
AddonRepository.repopulateCache(ADDON_IDS, resolve));
yield AddonRepository.repopulateCache();
// Database should have been deleted
do_check_false(gDBFile.exists());