summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/internal/AddonRepository.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/internal/AddonRepository.jsm')
-rw-r--r--toolkit/mozapps/extensions/internal/AddonRepository.jsm301
1 files changed, 172 insertions, 129 deletions
diff --git a/toolkit/mozapps/extensions/internal/AddonRepository.jsm b/toolkit/mozapps/extensions/internal/AddonRepository.jsm
index 7f88d44ad..adcecbee7 100644
--- a/toolkit/mozapps/extensions/internal/AddonRepository.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonRepository.jsm
@@ -11,7 +11,6 @@ const Cr = Components.results;
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AddonManager.jsm");
-/* globals AddonManagerPrivate*/
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
@@ -24,8 +23,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository_SQLiteMigrator",
"resource://gre/modules/addons/AddonRepository_SQLiteMigrator.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest",
- "resource://gre/modules/ServiceRequest.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
@@ -67,13 +64,15 @@ const BLANK_DB = function() {
}
const TOOLKIT_ID = "toolkit@mozilla.org";
-
+#ifdef MOZ_PHOENIX_EXTENSIONS
+const FIREFOX_ID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
+#endif
Cu.import("resource://gre/modules/Log.jsm");
const LOGGER_ID = "addons.repository";
// Create a new logger for use by the Addons Repository
// (Requires AddonManager.jsm)
-var logger = Log.repository.getLogger(LOGGER_ID);
+let logger = Log.repository.getLogger(LOGGER_ID);
// A map between XML keys to AddonSearchResult keys for string values
// that require no extra parsing from XML
@@ -101,6 +100,10 @@ const INTEGER_KEY_MAP = {
daily_users: "dailyUsers"
};
+// Wrap the XHR factory so that tests can override with a mock
+let XHRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1",
+ "nsIXMLHttpRequest");
+
function convertHTMLToPlainText(html) {
if (!html)
return html;
@@ -130,14 +133,14 @@ function getAddonsToCache(aIds, aCallback) {
types = types.split(",");
- AddonManager.getAddonsByIDs(aIds, function(aAddons) {
+ AddonManager.getAddonsByIDs(aIds, function getAddonsToCache_getAddonsByIDs(aAddons) {
let enabledIds = [];
for (var i = 0; i < aIds.length; i++) {
var preference = PREF_GETADDONS_CACHE_ID_ENABLED.replace("%ID%", aIds[i]);
try {
if (!Services.prefs.getBoolPref(preference))
continue;
- } catch (e) {
+ } catch(e) {
// If the preference doesn't exist caching is enabled by default
}
@@ -398,7 +401,7 @@ AddonSearchResult.prototype = {
* A platform version to test against
* @return Boolean representing if the add-on is compatible
*/
- isCompatibleWith: function(aAppVersion, aPlatformVersion) {
+ isCompatibleWith: function ASR_isCompatibleWith(aAppVerison, aPlatformVersion) {
return true;
},
@@ -415,7 +418,7 @@ AddonSearchResult.prototype = {
* @param aPlatformVersion
* A platform version to check for updates for
*/
- findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) {
+ findUpdates: function ASR_findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) {
if ("onNoCompatibilityUpdateAvailable" in aListener)
aListener.onNoCompatibilityUpdateAvailable(this);
if ("onNoUpdateAvailable" in aListener)
@@ -427,8 +430,7 @@ AddonSearchResult.prototype = {
toJSON: function() {
let json = {};
- for (let property of Object.keys(this)) {
- let value = this[property];
+ for (let [property, value] of Iterator(this)) {
if (property.startsWith("_") ||
typeof(value) === "function")
continue;
@@ -451,8 +453,7 @@ AddonSearchResult.prototype = {
}
}
- for (let property of Object.keys(this._unsupportedProperties)) {
- let value = this._unsupportedProperties[property];
+ for (let [property, value] of Iterator(this._unsupportedProperties)) {
if (!property.startsWith("_"))
json[property] = value;
}
@@ -477,11 +478,18 @@ this.AddonRepository = {
* Whether caching is currently enabled
*/
get cacheEnabled() {
+ // Act as though caching is disabled if there was an unrecoverable error
+ // openning the database.
+ if (!AddonDatabase.databaseOk) {
+ logger.warn("Cache is disabled because database is not OK");
+ return false;
+ }
+
let preference = PREF_GETADDONS_CACHE_ENABLED;
let enabled = false;
try {
enabled = Services.prefs.getBoolPref(preference);
- } catch (e) {
+ } catch(e) {
logger.warn("cacheEnabled: Couldn't get pref: " + preference);
}
@@ -524,7 +532,7 @@ this.AddonRepository = {
* return: promise{integer} resolves with the result of flushing
* the AddonRepository database
*/
- shutdown: function() {
+ shutdown: function AddonRepo_shutdown() {
this.cancelSearch();
this._addons = null;
@@ -546,7 +554,7 @@ this.AddonRepository = {
return now - lastUpdate;
},
- isMetadataStale: function() {
+ isMetadataStale: function AddonRepo_isMetadataStale() {
let threshold = DEFAULT_METADATA_UPDATETHRESHOLD_SEC;
try {
threshold = Services.prefs.getIntPref(PREF_METADATA_UPDATETHRESHOLD_SEC);
@@ -564,7 +572,7 @@ this.AddonRepository = {
* @param aCallback
* The callback to pass the result back to
*/
- getCachedAddonByID: Task.async(function*(aId, aCallback) {
+ getCachedAddonByID: Task.async(function* (aId, aCallback) {
if (!aId || !this.cacheEnabled) {
aCallback(null);
return;
@@ -605,7 +613,7 @@ this.AddonRepository = {
* Clear and delete the AddonRepository database
* @return Promise{null} resolves when the database is deleted
*/
- _clearCache: function() {
+ _clearCache: function () {
this._addons = null;
return AddonDatabase.delete().then(() =>
new Promise((resolve, reject) =>
@@ -613,43 +621,44 @@ this.AddonRepository = {
);
},
- _repopulateCacheInternal: Task.async(function*(aSendPerformance, aTimeout) {
+ _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
- allAddons = allAddons.filter(a => a.id != AddonManager.hotfixID);
-
// Completely remove cache if caching is not enabled
if (!this.cacheEnabled) {
logger.debug("Clearing cache because it is disabled");
- yield this._clearCache();
- return;
+ return this._clearCache();
}
- let ids = allAddons.map(a => a.id);
+ // Tycho: let ids = [a.id for (a of allAddons)];
+ let ids = [];
+ for (let a of allAddons) {
+ ids.push(a.id);
+ }
+
logger.debug("Repopulate add-on cache with " + ids.toSource());
+ 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");
- yield this._clearCache();
- return;
+ return this._clearCache();
}
yield new Promise((resolve, reject) =>
- this._beginGetAddons(addonsToCache, {
- searchSucceeded: aAddons => {
- this._addons = new Map();
+ self._beginGetAddons(addonsToCache, {
+ searchSucceeded: function repopulateCacheInternal_searchSucceeded(aAddons) {
+ self._addons = new Map();
for (let addon of aAddons) {
- this._addons.set(addon.id, addon);
+ self._addons.set(addon.id, addon);
}
AddonDatabase.repopulate(aAddons, resolve);
},
- searchFailed: () => {
+ searchFailed: function repopulateCacheInternal_searchFailed() {
logger.warn("Search failed when repopulating cache");
resolve();
}
@@ -670,7 +679,7 @@ this.AddonRepository = {
* @param aCallback
* The optional callback to call once complete
*/
- cacheAddons: function(aIds, aCallback) {
+ cacheAddons: function AddonRepo_cacheAddons(aIds, aCallback) {
logger.debug("cacheAddons: enabled " + this.cacheEnabled + " IDs " + aIds.toSource());
if (!this.cacheEnabled) {
if (aCallback)
@@ -678,7 +687,8 @@ this.AddonRepository = {
return;
}
- getAddonsToCache(aIds, aAddons => {
+ let self = this;
+ getAddonsToCache(aIds, function cacheAddons_getAddonsToCache(aAddons) {
// If there are no add-ons to cache, act as if caching is disabled
if (aAddons.length == 0) {
if (aCallback)
@@ -686,14 +696,14 @@ this.AddonRepository = {
return;
}
- this.getAddonsByIDs(aAddons, {
- searchSucceeded: aAddons => {
+ self.getAddonsByIDs(aAddons, {
+ searchSucceeded: function cacheAddons_searchSucceeded(aAddons) {
for (let addon of aAddons) {
- this._addons.set(addon.id, addon);
+ self._addons.set(addon.id, addon);
}
AddonDatabase.insertAddons(aAddons, aCallback);
},
- searchFailed: () => {
+ searchFailed: function cacheAddons_searchFailed() {
logger.warn("Search failed when adding add-ons to cache");
if (aCallback)
aCallback();
@@ -723,7 +733,7 @@ this.AddonRepository = {
* The url that can be visited to see recommended add-ons in this repository.
* If the corresponding preference is not defined, defaults to about:blank.
*/
- getRecommendedURL: function() {
+ getRecommendedURL: function AddonRepo_getRecommendedURL() {
let url = this._formatURLPref(PREF_GETADDONS_BROWSERECOMMENDED, {});
return (url != null) ? url : "about:blank";
},
@@ -736,7 +746,7 @@ this.AddonRepository = {
* @param aSearchTerms
* Search terms used to search the repository
*/
- getSearchURL: function(aSearchTerms) {
+ getSearchURL: function AddonRepo_getSearchURL(aSearchTerms) {
let url = this._formatURLPref(PREF_GETADDONS_BROWSESEARCHRESULTS, {
TERMS : encodeURIComponent(aSearchTerms)
});
@@ -747,7 +757,7 @@ this.AddonRepository = {
* Cancels the search in progress. If there is no search in progress this
* does nothing.
*/
- cancelSearch: function() {
+ cancelSearch: function AddonRepo_cancelSearch() {
this._searching = false;
if (this._request) {
this._request.abort();
@@ -765,7 +775,7 @@ this.AddonRepository = {
* @param aCallback
* The callback to pass results to
*/
- getAddonsByIDs: function(aIDs, aCallback) {
+ getAddonsByIDs: function AddonRepo_getAddonsByIDs(aIDs, aCallback) {
return this._beginGetAddons(aIDs, aCallback, false);
},
@@ -823,12 +833,13 @@ this.AddonRepository = {
let url = this._formatURLPref(pref, params);
- let handleResults = (aElements, aTotalResults, aCompatData) => {
+ let self = this;
+ function handleResults(aElements, aTotalResults, aCompatData) {
// Don't use this._parseAddons() so that, for example,
// incompatible add-ons are not filtered out
let results = [];
- for (let i = 0; i < aElements.length && results.length < this._maxResults; i++) {
- let result = this._parseAddon(aElements[i], null, aCompatData);
+ for (let i = 0; i < aElements.length && results.length < self._maxResults; i++) {
+ let result = self._parseAddon(aElements[i], null, aCompatData);
if (result == null)
continue;
@@ -849,8 +860,7 @@ this.AddonRepository = {
// Include any compatibility overrides for addons not hosted by the
// remote repository.
- for (let id in aCompatData) {
- let addonCompat = aCompatData[id];
+ for each (let addonCompat in aCompatData) {
if (addonCompat.hosted)
continue;
@@ -867,7 +877,7 @@ this.AddonRepository = {
}
// aTotalResults irrelevant
- this._reportSuccess(results, -1);
+ self._reportSuccess(results, -1);
}
this._beginSearch(url, ids.length, aCallback, handleResults, aTimeout);
@@ -882,7 +892,7 @@ this.AddonRepository = {
*
* @return Promise{null} Resolves when the metadata update is complete.
*/
- backgroundUpdateCheck: function() {
+ backgroundUpdateCheck: function () {
return this._repopulateCacheInternal(true);
},
@@ -895,7 +905,7 @@ this.AddonRepository = {
* @param aCallback
* The callback to pass results to
*/
- retrieveRecommendedAddons: function(aMaxResults, aCallback) {
+ retrieveRecommendedAddons: function AddonRepo_retrieveRecommendedAddons(aMaxResults, aCallback) {
let url = this._formatURLPref(PREF_GETADDONS_GETRECOMMENDED, {
API_VERSION : API_VERSION,
@@ -903,10 +913,11 @@ this.AddonRepository = {
MAX_RESULTS : 2 * aMaxResults
});
- let handleResults = (aElements, aTotalResults) => {
- this._getLocalAddonIds(aLocalAddonIds => {
+ let self = this;
+ function handleResults(aElements, aTotalResults) {
+ self._getLocalAddonIds(function retrieveRecommendedAddons_getLocalAddonIds(aLocalAddonIds) {
// aTotalResults irrelevant
- this._parseAddons(aElements, -1, aLocalAddonIds);
+ self._parseAddons(aElements, -1, aLocalAddonIds);
});
}
@@ -924,7 +935,7 @@ this.AddonRepository = {
* @param aCallback
* The callback to pass results to
*/
- searchAddons: function(aSearchTerms, aMaxResults, aCallback) {
+ searchAddons: function AddonRepo_searchAddons(aSearchTerms, aMaxResults, aCallback) {
let compatMode = "normal";
if (!AddonManager.checkCompatibility)
compatMode = "ignore";
@@ -941,9 +952,10 @@ this.AddonRepository = {
let url = this._formatURLPref(PREF_GETADDONS_GETSEARCHRESULTS, substitutions);
- let handleResults = (aElements, aTotalResults) => {
- this._getLocalAddonIds(aLocalAddonIds => {
- this._parseAddons(aElements, aTotalResults, aLocalAddonIds);
+ let self = this;
+ function handleResults(aElements, aTotalResults) {
+ self._getLocalAddonIds(function searchAddons_getLocalAddonIds(aLocalAddonIds) {
+ self._parseAddons(aElements, aTotalResults, aLocalAddonIds);
});
}
@@ -951,18 +963,23 @@ this.AddonRepository = {
},
// Posts results to the callback
- _reportSuccess: function(aResults, aTotalResults) {
+ _reportSuccess: function AddonRepo_reportSuccess(aResults, aTotalResults) {
this._searching = false;
this._request = null;
// The callback may want to trigger a new search so clear references early
- let addons = aResults.map(result => result.addon);
+ // Tycho: let addons = [result.addon for each(result in aResults)];
+ let addons = [];
+ for each(let result in aResults) {
+ addons.push(result.addon);
+ }
+
let callback = this._callback;
this._callback = null;
callback.searchSucceeded(addons, addons.length, aTotalResults);
},
// Notifies the callback of a failure
- _reportFailure: function() {
+ _reportFailure: function AddonRepo_reportFailure() {
this._searching = false;
this._request = null;
// The callback may want to trigger a new search so clear references early
@@ -972,28 +989,28 @@ this.AddonRepository = {
},
// Get descendant by unique tag name. Returns null if not unique tag name.
- _getUniqueDescendant: function(aElement, aTagName) {
+ _getUniqueDescendant: function AddonRepo_getUniqueDescendant(aElement, aTagName) {
let elementsList = aElement.getElementsByTagName(aTagName);
return (elementsList.length == 1) ? elementsList[0] : null;
},
// Get direct descendant by unique tag name.
// Returns null if not unique tag name.
- _getUniqueDirectDescendant: function(aElement, aTagName) {
+ _getUniqueDirectDescendant: function AddonRepo_getUniqueDirectDescendant(aElement, aTagName) {
let elementsList = Array.filter(aElement.children,
- aChild => aChild.tagName == aTagName);
+ function arrayFiltering(aChild) aChild.tagName == aTagName);
return (elementsList.length == 1) ? elementsList[0] : null;
},
// Parse out trimmed text content. Returns null if text content empty.
- _getTextContent: function(aElement) {
+ _getTextContent: function AddonRepo_getTextContent(aElement) {
let textContent = aElement.textContent.trim();
return (textContent.length > 0) ? textContent : null;
},
// Parse out trimmed text content of a descendant with the specified tag name
// Returns null if the parsing unsuccessful.
- _getDescendantTextContent: function(aElement, aTagName) {
+ _getDescendantTextContent: function AddonRepo_getDescendantTextContent(aElement, aTagName) {
let descendant = this._getUniqueDescendant(aElement, aTagName);
return (descendant != null) ? this._getTextContent(descendant) : null;
},
@@ -1001,7 +1018,7 @@ this.AddonRepository = {
// Parse out trimmed text content of a direct descendant with the specified
// tag name.
// Returns null if the parsing unsuccessful.
- _getDirectDescendantTextContent: function(aElement, aTagName) {
+ _getDirectDescendantTextContent: function AddonRepo_getDirectDescendantTextContent(aElement, aTagName) {
let descendant = this._getUniqueDirectDescendant(aElement, aTagName);
return (descendant != null) ? this._getTextContent(descendant) : null;
},
@@ -1019,7 +1036,7 @@ this.AddonRepository = {
* @return Result object containing the parsed AddonSearchResult, xpiURL and
* xpiHash if the parsing was successful. Otherwise returns null.
*/
- _parseAddon: function(aElement, aSkip, aCompatData) {
+ _parseAddon: function AddonRepo_parseAddon(aElement, aSkip, aCompatData) {
let skipIDs = (aSkip && aSkip.ids) ? aSkip.ids : [];
let skipSourceURIs = (aSkip && aSkip.sourceURIs) ? aSkip.sourceURIs : [];
@@ -1037,6 +1054,7 @@ this.AddonRepository = {
if (aCompatData && guid in aCompatData)
addon.compatibilityOverrides = aCompatData[guid].compatRanges;
+ let self = this;
for (let node = aElement.firstChild; node; node = node.nextSibling) {
if (!(node instanceof Ci.nsIDOMElement))
continue;
@@ -1107,8 +1125,8 @@ this.AddonRepository = {
case "authors":
let authorNodes = node.getElementsByTagName("author");
for (let authorNode of authorNodes) {
- let name = this._getDescendantTextContent(authorNode, "name");
- let link = this._getDescendantTextContent(authorNode, "link");
+ let name = self._getDescendantTextContent(authorNode, "name");
+ let link = self._getDescendantTextContent(authorNode, "link");
if (name == null || link == null)
continue;
@@ -1126,22 +1144,22 @@ this.AddonRepository = {
case "previews":
let previewNodes = node.getElementsByTagName("preview");
for (let previewNode of previewNodes) {
- let full = this._getUniqueDescendant(previewNode, "full");
+ let full = self._getUniqueDescendant(previewNode, "full");
if (full == null)
continue;
- let fullURL = this._getTextContent(full);
+ let fullURL = self._getTextContent(full);
let fullWidth = full.getAttribute("width");
let fullHeight = full.getAttribute("height");
let thumbnailURL, thumbnailWidth, thumbnailHeight;
- let thumbnail = this._getUniqueDescendant(previewNode, "thumbnail");
+ let thumbnail = self._getUniqueDescendant(previewNode, "thumbnail");
if (thumbnail) {
- thumbnailURL = this._getTextContent(thumbnail);
+ thumbnailURL = self._getTextContent(thumbnail);
thumbnailWidth = thumbnail.getAttribute("width");
thumbnailHeight = thumbnail.getAttribute("height");
}
- let caption = this._getDescendantTextContent(previewNode, "caption");
+ let caption = self._getDescendantTextContent(previewNode, "caption");
let screenshot = new AddonManagerPrivate.AddonScreenshot(fullURL, fullWidth, fullHeight,
thumbnailURL, thumbnailWidth,
thumbnailHeight, caption);
@@ -1198,7 +1216,7 @@ this.AddonRepository = {
break;
case "all_compatible_os":
let nodes = node.getElementsByTagName("os");
- addon.isPlatformCompatible = Array.some(nodes, function(aNode) {
+ addon.isPlatformCompatible = Array.some(nodes, function parseAddon_platformCompatFilter(aNode) {
let text = aNode.textContent.toLowerCase().trim();
return text == "all" || text == Services.appinfo.OS.toLowerCase();
});
@@ -1244,10 +1262,21 @@ this.AddonRepository = {
return result;
},
- _parseAddons: function(aElements, aTotalResults, aSkip) {
+ _parseAddons: function AddonRepo_parseAddons(aElements, aTotalResults, aSkip) {
+ let self = this;
let results = [];
- let isSameApplication = aAppNode => this._getTextContent(aAppNode) == Services.appinfo.ID;
+ function isSameApplication(aAppNode) {
+#ifdef MOZ_PHOENIX_EXTENSIONS
+ if (self._getTextContent(aAppNode) == Services.appinfo.ID ||
+ self._getTextContent(aAppNode) == FIREFOX_ID) {
+#else
+ if (self._getTextContent(aAppNode) == Services.appinfo.ID) {
+#endif
+ return true;
+ }
+ return false;
+ }
for (let i = 0; i < aElements.length && results.length < this._maxResults; i++) {
let element = aElements[i];
@@ -1257,13 +1286,13 @@ this.AddonRepository = {
continue;
let applications = tags.getElementsByTagName("appID");
- let compatible = Array.some(applications, aAppNode => {
+ let compatible = Array.some(applications, function parseAddons_applicationsCompatFilter(aAppNode) {
if (!isSameApplication(aAppNode))
return false;
let parent = aAppNode.parentNode;
- let minVersion = this._getDescendantTextContent(parent, "min_version");
- let maxVersion = this._getDescendantTextContent(parent, "max_version");
+ let minVersion = self._getDescendantTextContent(parent, "min_version");
+ let maxVersion = self._getDescendantTextContent(parent, "max_version");
if (minVersion == null || maxVersion == null)
return false;
@@ -1291,7 +1320,7 @@ this.AddonRepository = {
// Ignore add-on missing a required attribute
let requiredAttributes = ["id", "name", "version", "type", "creator"];
- if (requiredAttributes.some(aAttribute => !result.addon[aAttribute]))
+ if (requiredAttributes.some(function parseAddons_attributeFilter(aAttribute) !result.addon[aAttribute]))
continue;
// Ignore add-on with a type AddonManager doesn't understand:
@@ -1322,28 +1351,28 @@ this.AddonRepository = {
}
// Create an AddonInstall for each result
- for (let result of results) {
- let addon = result.addon;
- let callback = aInstall => {
+ results.forEach(function(aResult) {
+ let addon = aResult.addon;
+ let callback = function addonInstallCallback(aInstall) {
addon.install = aInstall;
pendingResults--;
if (pendingResults == 0)
- this._reportSuccess(results, aTotalResults);
+ self._reportSuccess(results, aTotalResults);
}
- if (result.xpiURL) {
- AddonManager.getInstallForURL(result.xpiURL, callback,
- "application/x-xpinstall", result.xpiHash,
+ if (aResult.xpiURL) {
+ AddonManager.getInstallForURL(aResult.xpiURL, callback,
+ "application/x-xpinstall", aResult.xpiHash,
addon.name, addon.icons, addon.version);
}
else {
callback(null);
}
- }
+ });
},
// Parses addon_compatibility nodes, that describe compatibility overrides.
- _parseAddonCompatElement: function(aResultObj, aElement) {
+ _parseAddonCompatElement: function AddonRepo_parseAddonCompatElement(aResultObj, aElement) {
let guid = this._getDescendantTextContent(aElement, "guid");
if (!guid) {
logger.debug("Compatibility override is missing guid.");
@@ -1416,7 +1445,7 @@ this.AddonRepository = {
let rangeNodes = aElement.querySelectorAll("version_ranges > version_range");
compat.compatRanges = Array.map(rangeNodes, parseRangeNode.bind(this))
- .filter(aItem => !!aItem);
+ .filter(function compatRangesFilter(aItem) !!aItem);
if (compat.compatRanges.length == 0)
return;
@@ -1424,7 +1453,7 @@ this.AddonRepository = {
},
// Parses addon_compatibility elements.
- _parseAddonCompatData: function(aElements) {
+ _parseAddonCompatData: function AddonRepo_parseAddonCompatData(aElements) {
let compatData = {};
Array.forEach(aElements, this._parseAddonCompatElement.bind(this, compatData));
return compatData;
@@ -1445,7 +1474,7 @@ this.AddonRepository = {
logger.debug("Requesting " + aURI);
- this._request = new ServiceRequest();
+ this._request = new XHRequest();
this._request.mozBackgroundRequest = true;
this._request.open("GET", aURI, true);
this._request.overrideMimeType("text/xml");
@@ -1484,21 +1513,28 @@ this.AddonRepository = {
// Gets the id's of local add-ons, and the sourceURI's of local installs,
// passing the results to aCallback
- _getLocalAddonIds: function(aCallback) {
+ _getLocalAddonIds: function AddonRepo_getLocalAddonIds(aCallback) {
+ let self = this;
let localAddonIds = {ids: null, sourceURIs: null};
- AddonManager.getAllAddons(function(aAddons) {
- localAddonIds.ids = aAddons.map(a => a.id);
+ AddonManager.getAllAddons(function getLocalAddonIds_getAllAddons(aAddons) {
+ // Tycho: localAddonIds.ids = [a.id for each (a in aAddons)];
+ localAddonIds.ids = [];
+
+ for each(let a in aAddons) {
+ localAddonIds.ids.push(a.id);
+ }
+
if (localAddonIds.sourceURIs)
aCallback(localAddonIds);
});
- AddonManager.getAllInstalls(function(aInstalls) {
+ AddonManager.getAllInstalls(function getLocalAddonIds_getAllInstalls(aInstalls) {
localAddonIds.sourceURIs = [];
- for (let install of aInstalls) {
- if (install.state != AddonManager.STATE_AVAILABLE)
- localAddonIds.sourceURIs.push(install.sourceURI.spec);
- }
+ aInstalls.forEach(function(aInstall) {
+ if (aInstall.state != AddonManager.STATE_AVAILABLE)
+ localAddonIds.sourceURIs.push(aInstall.sourceURI.spec);
+ });
if (localAddonIds.ids)
aCallback(localAddonIds);
@@ -1506,16 +1542,16 @@ this.AddonRepository = {
},
// Create url from preference, returning null if preference does not exist
- _formatURLPref: function(aPreference, aSubstitutions) {
+ _formatURLPref: function AddonRepo_formatURLPref(aPreference, aSubstitutions) {
let url = null;
try {
url = Services.prefs.getCharPref(aPreference);
- } catch (e) {
+ } catch(e) {
logger.warn("_formatURLPref: Couldn't get pref: " + aPreference);
return null;
}
- url = url.replace(/%([A-Z_]+)%/g, function(aMatch, aKey) {
+ url = url.replace(/%([A-Z_]+)%/g, function urlSubstitution(aMatch, aKey) {
return (aKey in aSubstitutions) ? aSubstitutions[aKey] : aMatch;
});
@@ -1524,7 +1560,7 @@ this.AddonRepository = {
// Find a AddonCompatibilityOverride that matches a given aAddonVersion and
// application/platform version.
- findMatchingCompatOverride: function(aAddonVersion,
+ findMatchingCompatOverride: function AddonRepo_findMatchingCompatOverride(aAddonVersion,
aCompatOverrides,
aAppVersion,
aPlatformVersion) {
@@ -1552,6 +1588,9 @@ this.AddonRepository = {
};
var AddonDatabase = {
+ // false if there was an unrecoverable error opening the database
+ databaseOk: true,
+
connectionPromise: null,
// the in-memory database
DB: BLANK_DB(),
@@ -1594,12 +1633,8 @@ var AddonDatabase = {
schema < DB_MIN_JSON_SCHEMA) {
throw new Error("Invalid schema value.");
}
- } catch (e) {
- if (e instanceof OS.File.Error && e.becauseNoSuchFile) {
- logger.debug("No " + FILE_DATABASE + " found.");
- } else {
- logger.error(`Malformed ${FILE_DATABASE}: ${e} - resetting to empty`);
- }
+ } catch (e if e instanceof OS.File.Error && e.becauseNoSuchFile) {
+ logger.debug("No " + FILE_DATABASE + " found.");
// Create a blank addons.json file
this._saveDBToDisk();
@@ -1618,9 +1653,14 @@ var AddonDatabase = {
yield this._insertAddons(results);
}
+ Services.prefs.setIntPref(PREF_GETADDONS_DB_SCHEMA, DB_SCHEMA);
}
- Services.prefs.setIntPref(PREF_GETADDONS_DB_SCHEMA, DB_SCHEMA);
+ return this.DB;
+ } catch (e) {
+ logger.error("Malformed " + FILE_DATABASE + ": " + e);
+ this.databaseOk = false;
+
return this.DB;
}
@@ -1657,7 +1697,9 @@ var AddonDatabase = {
* An optional boolean to skip flushing data to disk. Useful
* when the database is going to be deleted afterwards.
*/
- shutdown: function(aSkipFlush) {
+ shutdown: function AD_shutdown(aSkipFlush) {
+ this.databaseOk = true;
+
if (!this.connectionPromise) {
return Promise.resolve();
}
@@ -1666,8 +1708,9 @@ var AddonDatabase = {
if (aSkipFlush) {
return Promise.resolve();
+ } else {
+ return this.Writer.flush();
}
- return this.Writer.flush();
},
/**
@@ -1678,7 +1721,7 @@ var AddonDatabase = {
* An optional callback to call once complete
* @return Promise{null} resolves when the database has been deleted
*/
- delete: function(aCallback) {
+ delete: function AD_delete(aCallback) {
this.DB = BLANK_DB();
this._deleting = this.Writer.flush()
@@ -1693,7 +1736,7 @@ var AddonDatabase = {
return this._deleting;
},
- toJSON: function() {
+ toJSON: function AD_toJSON() {
let json = {
schema: this.DB.schema,
addons: []
@@ -1738,7 +1781,7 @@ var AddonDatabase = {
* @return: Promise{Map}
* Resolves when the add-ons are retrieved from the database
*/
- retrieveStoredData: function() {
+ retrieveStoredData: function (){
return this.openConnection().then(db => db.addons);
},
@@ -1751,9 +1794,9 @@ var AddonDatabase = {
* @param aCallback
* An optional callback to call once complete
*/
- repopulate: function(aAddons, aCallback) {
+ repopulate: function AD_repopulate(aAddons, aCallback) {
this.DB.addons.clear();
- this.insertAddons(aAddons, function() {
+ this.insertAddons(aAddons, function repopulate_insertAddons() {
let now = Math.round(Date.now() / 1000);
logger.debug("Cache repopulated, setting " + PREF_METADATA_LASTUPDATE + " to " + now);
Services.prefs.setIntPref(PREF_METADATA_LASTUPDATE, now);
@@ -1770,12 +1813,12 @@ var AddonDatabase = {
* @param aCallback
* An optional callback to call once complete
*/
- insertAddons: Task.async(function*(aAddons, aCallback) {
+ insertAddons: Task.async(function* (aAddons, aCallback) {
yield this.openConnection();
yield this._insertAddons(aAddons, aCallback);
}),
- _insertAddons: Task.async(function*(aAddons, aCallback) {
+ _insertAddons: Task.async(function* (aAddons, aCallback) {
for (let addon of aAddons) {
this._insertAddon(addon);
}
@@ -1794,7 +1837,7 @@ var AddonDatabase = {
* @param aCallback
* The callback to call once complete
*/
- _insertAddon: function(aAddon) {
+ _insertAddon: function AD__insertAddon(aAddon) {
let newAddon = this._parseAddon(aAddon);
if (!newAddon ||
!newAddon.id ||
@@ -1812,7 +1855,7 @@ var AddonDatabase = {
* The object to parse
* @return Returns an AddonSearchResult object.
*/
- _parseAddon: function(aObj) {
+ _parseAddon: function (aObj) {
if (aObj instanceof AddonSearchResult)
return aObj;
@@ -1822,7 +1865,7 @@ var AddonDatabase = {
let addon = new AddonSearchResult(id);
- for (let expectedProperty of Object.keys(AddonSearchResult.prototype)) {
+ for (let [expectedProperty,] of Iterator(AddonSearchResult.prototype)) {
if (!(expectedProperty in aObj) ||
typeof(aObj[expectedProperty]) === "function")
continue;
@@ -1870,8 +1913,8 @@ var AddonDatabase = {
case "icons":
if (!addon.icons) addon.icons = {};
- for (let size of Object.keys(aObj.icons)) {
- addon.icons[size] = aObj.icons[size];
+ for (let [size, url] of Iterator(aObj.icons)) {
+ addon.icons[size] = url;
}
break;
@@ -1937,7 +1980,7 @@ var AddonDatabase = {
* The JS object to use
* @return The created developer
*/
- _makeDeveloper: function(aObj) {
+ _makeDeveloper: function (aObj) {
let name = aObj.name;
let url = aObj.url;
return new AddonManagerPrivate.AddonAuthor(name, url);
@@ -1951,7 +1994,7 @@ var AddonDatabase = {
* The JS object to use
* @return The created screenshot
*/
- _makeScreenshot: function(aObj) {
+ _makeScreenshot: function (aObj) {
let url = aObj.url;
let width = aObj.width;
let height = aObj.height;
@@ -1971,7 +2014,7 @@ var AddonDatabase = {
* The JS object to use
* @return The created CompatibilityOverride
*/
- _makeCompatOverride: function(aObj) {
+ _makeCompatOverride: function (aObj) {
let type = aObj.type;
let minVersion = aObj.minVersion;
let maxVersion = aObj.maxVersion;