Skip to content
This repository has been archived by the owner on Apr 10, 2024. It is now read-only.

Commit

Permalink
Bug 680802: Installing a new add-on at the same time as installing a …
Browse files Browse the repository at this point in the history
…new version of the app which uses new properties from install.rdf will fail. r=robstrong, a=LegNeato

--HG--
extra : transplant_source : %80%B5ZaZ%C9%A8%E2%22%F8%C4%E9Rp%BA%91B4%91%9B
  • Loading branch information
Mossop committed Sep 28, 2011
1 parent 3526e4c commit 8402740
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 27 deletions.
65 changes: 38 additions & 27 deletions toolkit/mozapps/extensions/XPIProvider.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -1969,46 +1969,47 @@ var XPIProvider = {
aManifests[aLocation.name][id] = null;
let existingAddonID = id;

// Check for a cached AddonInternal for this add-on, it may contain
// updated compatibility information
let jsonfile = stagingDir.clone();
jsonfile.append(id + ".json");

try {
aManifests[aLocation.name][id] = loadManifestFromFile(stageDirEntry);
}
catch (e) {
ERROR("Unable to read add-on manifest from " + stageDirEntry.path, e);
// This add-on can't be installed so just remove it now
seenFiles.push(stageDirEntry.leafName);
seenFiles.push(jsonfile.leafName);
continue;
}

// Check for a cached metadata for this add-on, it may contain updated
// compatibility information
if (jsonfile.exists()) {
LOG("Found updated manifest for " + id + " in " + aLocation.name);
LOG("Found updated metadata for " + id + " in " + aLocation.name);
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
let json = Cc["@mozilla.org/dom/json;1"].
createInstance(Ci.nsIJSON);

try {
fis.init(jsonfile, -1, 0, 0);
let addonObj = json.decodeFromStream(fis, jsonfile.fileSize);
aManifests[aLocation.name][id] = new AddonInternal();
aManifests[aLocation.name][id].fromJSON(addonObj);
existingAddonID = aManifests[aLocation.name][id].existingAddonID || id;
let metadata = json.decodeFromStream(fis, jsonfile.fileSize);
aManifests[aLocation.name][id].importMetadata(metadata);
}
catch (e) {
ERROR("Unable to read add-on manifest from " + jsonfile.path, e);
// If some data can't be recovered from the cached metadata then it
// is unlikely to be a problem big enough to justify throwing away
// the install, just log and error and continue
ERROR("Unable to read metadata from " + jsonfile.path, e);
}
finally {
fis.close();
}
}
seenFiles.push(jsonfile.leafName);

// If there was no cached AddonInternal then load it directly
if (!aManifests[aLocation.name][id]) {
try {
aManifests[aLocation.name][id] = loadManifestFromFile(stageDirEntry);
existingAddonID = aManifests[aLocation.name][id].existingAddonID || id;
}
catch (e) {
ERROR("Unable to read add-on manifest from " + stageDirEntry.path, e);
// This add-on can't be installed so just remove it now
seenFiles.push(stageDirEntry.leafName);
continue;
}
}
existingAddonID = aManifests[aLocation.name][id].existingAddonID || id;

var oldBootstrap = null;
LOG("Processing install of " + id + " in " + aLocation.name);
Expand Down Expand Up @@ -6906,15 +6907,25 @@ AddonInternal.prototype = {
},

/**
* fromJSON should be called to set the properties of this AddonInternal to
* those from the passed in object. It is essentially the inverse of toJSON.
* When an add-on install is pending its metadata will be cached in a file.
* This method reads particular properties of that metadata that may be newer
* than that in the install manifest, like compatibility information.
*
* @param aObj
* A JS object containing properties to be set on this AddonInternal
* A JS object containing the cached metadata
*/
fromJSON: function(aObj) {
for (let prop in aObj)
this[prop] = aObj[prop];
importMetadata: function(aObj) {
["targetApplications", "userDisabled", "softDisabled", "existingAddonID",
"sourceURI", "releaseNotesURI", "installDate", "updateDate",
"applyBackgroundUpdates"].forEach(function(aProp) {
if (!(aProp in aObj))
return;

this[aProp] = aObj[aProp];
}, this);

// Compatibility info may have changed so update appDisabled
this.appDisabled = !isUsableAddon(this);
}
};

Expand Down
56 changes: 56 additions & 0 deletions toolkit/mozapps/extensions/test/xpcshell/test_bug659772.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,34 @@ function run_test_1() {
Services.prefs.setIntPref("extensions.databaseSchema", 1);
db.close();

let jsonfile = gProfD.clone();
jsonfile.append("extensions");
jsonfile.append("staged");
jsonfile.append("addon3@tests.mozilla.org.json");
do_check_true(jsonfile.exists());

// Remove an unnecessary property from the cached manifest
let fis = AM_Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(AM_Ci.nsIFileInputStream);
let json = AM_Cc["@mozilla.org/dom/json;1"].
createInstance(AM_Ci.nsIJSON);
fis.init(jsonfile, -1, 0, 0);
let addonObj = json.decodeFromStream(fis, jsonfile.fileSize);
fis.close();
delete addonObj.optionsType;

let stream = AM_Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(AM_Ci.nsIFileOutputStream);
let converter = AM_Cc["@mozilla.org/intl/converter-output-stream;1"].
createInstance(AM_Ci.nsIConverterOutputStream);
stream.init(jsonfile, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE |
FileUtils.MODE_TRUNCATE, FileUtils.PERMS_FILE,
0);
converter.init(stream, "UTF-8", 0, 0x0000);
converter.writeString(JSON.stringify(addonObj));
converter.close();
stream.close();

startupManager(false);

AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
Expand Down Expand Up @@ -221,6 +249,34 @@ function run_test_2() {
Services.prefs.setIntPref("extensions.databaseSchema", 1);
db.close();

let jsonfile = gProfD.clone();
jsonfile.append("extensions");
jsonfile.append("staged");
jsonfile.append("addon3@tests.mozilla.org.json");
do_check_true(jsonfile.exists());

// Remove an unnecessary property from the cached manifest
let fis = AM_Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(AM_Ci.nsIFileInputStream);
let json = AM_Cc["@mozilla.org/dom/json;1"].
createInstance(AM_Ci.nsIJSON);
fis.init(jsonfile, -1, 0, 0);
let addonObj = json.decodeFromStream(fis, jsonfile.fileSize);
fis.close();
delete addonObj.optionsType;

let stream = AM_Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(AM_Ci.nsIFileOutputStream);
let converter = AM_Cc["@mozilla.org/intl/converter-output-stream;1"].
createInstance(AM_Ci.nsIConverterOutputStream);
stream.init(jsonfile, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE |
FileUtils.MODE_TRUNCATE, FileUtils.PERMS_FILE,
0);
converter.init(stream, "UTF-8", 0, 0x0000);
converter.writeString(JSON.stringify(addonObj));
converter.close();
stream.close();

gAppInfo.version = "2";
startupManager(true);

Expand Down

0 comments on commit 8402740

Please sign in to comment.