Bug 298498 - Allow extension XPIs to ship multiple independent extensions. patch from Robert Strong <rob_strong@exchangecode.com>, r=bsmedberg, a=asa.

This commit is contained in:
mozilla.mano%sent.com 2005-07-15 10:08:17 +00:00
Родитель 67e3835eac
Коммит b63b65693e
3 изменённых файлов: 111 добавлений и 2 удалений

Просмотреть файл

@ -39,6 +39,7 @@ statusFormatMBMB=#1 of #2 MB
disabledObsoleteTitle=Old Extensions
disabledObsoleteMessage=Any old extensions that you have installed have been disabled.
type-32=Multiple Extension Package
type-4=Theme
type-2=Extension
incompatibleTitle=Incompatible %S
@ -62,6 +63,11 @@ malformedTitle=Malformed File
malformedRegistrationTitle=Chrome Registration Failed
malformedRegistrationMessage=%S could not install this item because of a failure in Chrome Registration. Please contact the author about this problem.
invalidFileExtTitle=Invalid File Extension
invalidFileExtMessage="%S" could not be installed because this item has an invalid file extension (%S is not a valid file extension for a %S). Please contact the author about this problem.
missingPackageFilesTitle=Missing Installation Files
missingPackageFilesMessage="%S" could not be installed because it does not contain a valid package (a %S must contain at least one extension or theme). Please contact the author about this problem.
errorInstallTitle=Error
errorInstallMsg=%S could not install the file at \n\n%S\n\nbecause: %S

Просмотреть файл

@ -497,6 +497,7 @@ interface nsIUpdateItem : nsISupports
const unsigned long TYPE_THEME = 0x04;
const unsigned long TYPE_LOCALE = 0x08;
const unsigned long TYPE_PLUGIN = 0x10;
const unsigned long TYPE_MULTI_XPI = 0x20;
const unsigned long TYPE_ADDON = TYPE_EXTENSION + TYPE_THEME + TYPE_LOCALE + TYPE_PLUGIN;
const unsigned long TYPE_ANY = TYPE_APP + TYPE_ADDON;

Просмотреть файл

@ -48,6 +48,7 @@ const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
const nsILocalFile = Components.interfaces.nsILocalFile;
const nsILineInputStream = Components.interfaces.nsILineInputStream;
const nsIInstallLocation = Components.interfaces.nsIInstallLocation;
const nsIURL = Components.interfaces.nsIURL
// XXXrstrong calling hasMoreElements on a nsIDirectoryEnumerator after
// it has been removed will cause a crash on Mac OS X - bug 292823
const nsIDirectoryEnumerator = Components.interfaces.nsIDirectoryEnumerator;
@ -67,6 +68,7 @@ const PREF_DSS_SWITCHPENDING = "extensions.dss.switchPending";
const PREF_DSS_SKIN_TO_SELECT = "extensions.lastSelectedSkin";
const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
const PREF_EM_LOGGING_ENABLED = "extensions.logging.enabled";
const PREF_XPINSTALL_STATUS_DLG_SKIN = "xpinstall.dialog.progress.skin";
const DIR_EXTENSIONS = "extensions";
const DIR_UNINSTALL = "uninstall";
@ -790,7 +792,7 @@ function getInstallManifest(file) {
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newFileURI(file);
var url = uri.QueryInterface(Components.interfaces.nsIURL);
var url = uri.QueryInterface(nsIURL);
showMessage("malformedTitle", [], "malformedMessage",
[BundleManager.appName, url.fileName]);
}
@ -2387,7 +2389,7 @@ ExtensionManager.prototype = {
*/
_getItemForDroppedFile: function(file, location) {
var fileURL = getURIFromFile(file);
if (fileURL instanceof Components.interfaces.nsIURL) {
if (fileURL instanceof nsIURL) {
if (fileIsItemPackage(fileURL)) {
// We know nothing about this item, it is not something we've
// staged in preparation for finalization, so assume it's something
@ -3634,6 +3636,96 @@ ExtensionManager.prototype = {
}
}
/**
* Extracts and then starts the install for extensions / themes contained
* within a xpi.
*/
function installMultiXPI(xpiFile, installData) {
var fileURL = getURIFromFile(xpiFile).QueryInterface(nsIURL);
if (fileURL.fileExtension.toLowerCase() != "xpi") {
LOG("Invalid File Extension: Item: \"" + fileURL.fileName + "\" has an " +
"invalid file extension. Only xpi file extensions are allowed for " +
"multiple item packages.");
var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);
showMessage("invalidFileExtTitle", [],
"invalidFileExtMessage", [installData.name,
fileURL.fileExtension,
bundle.GetStringFromName("type-" + installData.type)]);
return;
}
try {
var zipReader = Components.classes["@mozilla.org/libjar/zip-reader;1"]
.createInstance(Components.interfaces.nsIZipReader);
zipReader.init(xpiFile);
zipReader.open();
}
catch (e) {
zipReader.close();
LOG("installMultiXPI: failed to open xpi file: " + xpiFile.path);
throw e;
}
var searchForEntries = ["*.xpi", "*.jar"];
var files = [];
for (var i = 0; i < searchForEntries.length; ++i) {
var entries = zipReader.findEntries(searchForEntries[i]);
while (entries.hasMoreElements()) {
var entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry);
var target = getFile(KEY_TEMPDIR, [entry.name]);
try {
target.createUnique(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
}
catch (e) {
LOG("installMultiXPI: failed to create target file for extraction " +
" file = " + target.path + ", exception = " + e + "\n");
}
zipReader.extract(entry.name, target);
files.push(target);
}
}
zipReader.close();
if (files.length == 0) {
LOG("Multiple Item Package: Item: \"" + fileURL.fileName + "\" does " +
"not contain a valid package to install.");
var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);
showMessage("missingPackageFilesTitle",
[bundle.GetStringFromName("type-" + installData.type)],
"missingPackageFilesMessage", [installData.name,
bundle.GetStringFromName("type-" + installData.type)]);
return;
}
// When installing themes we need to open the theme manager if it is not
// already opened except when we are installing a xpi dropped into a
// extensions directory.
fileURL = getURIFromFile(files[files.length - 1]).QueryInterface(nsIURL);
if (fileURL.fileExtension.toLowerCase() == "jar") {
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("Extension:Manager-extensions");
if (win) {
win = wm.getMostRecentWindow("Extension:Manager-themes");
if (win) {
win.focus();
}
else {
var themeManagerURL = gPref.getCharPref(PREF_XPINSTALL_STATUS_DLG_SKIN);
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
ww.openWindow(null, themeManagerURL,
"", "chrome,centerscreen,titlebar,dialog=no,resizable", []);
}
}
}
for (i = 0; i < files.length; ++i) {
em.installItemFromFileInternal(files[i], aInstallLocationKey, null);
files[i].remove(false);
}
}
/**
* An observer for the Extension Update System.
* @constructor
@ -3802,6 +3894,12 @@ ExtensionManager.prototype = {
}
break;
case INSTALLERROR_SUCCESS:
// Installation of multiple extensions / themes contained within a single xpi.
if (installData.type == nsIUpdateItem.TYPE_MULTI_XPI) {
installMultiXPI(aXPIFile, installData);
break;
}
// Stage the extension's XPI so it can be extracted at the next restart.
var installLocation = getInstallLocation(installData.id, aInstallLocationKey);
if (!installLocation) {
@ -5990,6 +6088,10 @@ ExtensionsDataSource.prototype = {
* The version of the item
*/
addIncompatibleUpdateItem: function(name, url, type, version) {
// type must be TYPE_EXTENSION for a multi_xpi to display in the manager.
if (type == nsIUpdateItem.TYPE_MULTI_XPI)
type = nsIUpdateItem.TYPE_EXTENSION;
var iconURL = (type == nsIUpdateItem.TYPE_THEME) ? URI_GENERIC_ICON_THEME :
URI_GENERIC_ICON_XPINSTALL;
var extensionsStrings = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);