📄 nsextensionmanager.js
字号:
!iid.equals(Components.interfaces.nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; }};//@line 1441 "/c/builds/1813/mozilla/toolkit/mozapps/extensions/src/nsExtensionManager.js.in"/** * An object which handles the installation of an Extension. * @constructor */function Installer(ds, id, installLocation, type) { this._ds = ds; this._id = id; this._type = type; this._installLocation = installLocation;}Installer.prototype = { // Item metadata _id: null, _ds: null, _installLocation: null, _metadataDS: null, /** * Gets the Install Manifest datasource we are installing from. */ get metadataDS() { if (!this._metadataDS) { var metadataFile = this._installLocation .getItemFile(this._id, FILE_INSTALL_MANIFEST); if (!metadataFile.exists()) return null; this._metadataDS = getInstallManifest(metadataFile); if (!this._metadataDS) { LOG("Installer::install: metadata datasource for extension " + this._id + " at " + metadataFile.path + " could not be loaded. " + " Installation will not proceed."); } } return this._metadataDS; }, /** * Installs the Extension * @param file * A XPI/JAR file to install from. If this is null or does not exist, * the item is assumed to be an expanded directory, located at the GUID * key in the supplied Install Location. */ installFromFile: function(file) { // Move files from the staging dir into the extension's final home. if (file && file.exists()) { this._installExtensionFiles(file); } if (!this.metadataDS) return; // Upgrade old-style contents.rdf Chrome Manifests if necessary. if (this._type == nsIUpdateItem.TYPE_THEME) this.upgradeThemeChrome(); else this.upgradeExtensionChrome(); // Add metadata for the extension to the global extension metadata set this._ds.addItemMetadata(this._id, this.metadataDS, this._installLocation); }, /** * Safely extract the Extension's files into the target folder. * @param file * The XPI/JAR file to install from. */ _installExtensionFiles: function(file) { var installer = this; /** * Callback for |safeInstallOperation| that performs file level installation * steps for an Extension. * @param extensionID * The GUID of the Extension being installed. * @param installLocation * The Install Location where the Extension is being installed. * @param xpiFile * The source XPI file that contains the Extension. */ function extractExtensionFiles(extensionID, installLocation, xpiFile) { // Create a logger to log install operations for uninstall. This must be // created in the |safeInstallOperation| callback, since it creates a file // in the target directory. If we do this outside of the callback, we may // be clobbering a file we should not be. var zipReader = getZipReaderForFile(xpiFile); // create directories first var entries = zipReader.findEntries("*/"); while (entries.hasMoreElements()) { var entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry); var target = installLocation.getItemFile(extensionID, entry.name); if (!target.exists()) { try { target.create(nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY); } catch (e) { LOG("extractExtensionsFiles: failed to create target directory for extraction " + " file = " + target.path + ", exception = " + e + "\n"); } } } entries = zipReader.findEntries("*"); while (entries.hasMoreElements()) { entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry); target = installLocation.getItemFile(extensionID, entry.name); if (target.exists()) continue; try { target.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); } catch (e) { LOG("extractExtensionsFiles: failed to create target file for extraction " + " file = " + target.path + ", exception = " + e + "\n"); } zipReader.extract(entry.name, target); } zipReader.close(); } var installer = this; /** * Callback for |safeInstallOperation| that performs file level installation * steps for a Theme. * @param id * The GUID of the Theme being installed. * @param installLocation * The Install Location where the Theme is being installed. * @param jarFile * The source JAR file that contains the Theme. */ function extractThemeFiles(id, installLocation, jarFile) { var themeDirectory = installLocation.getItemLocation(id); var zipReader = getZipReaderForFile(jarFile); // The only critical file is the install.rdf and we would not have // gotten this far without one. var rootFiles = [FILE_INSTALL_MANIFEST, FILE_CHROME_MANIFEST, "preview.png", "icon.png"]; for (var i = 0; i < rootFiles.length; ++i) { try { var entry = zipReader.getEntry(rootFiles[i]); var target = installLocation.getItemFile(id, rootFiles[i]); zipReader.extract(rootFiles[i], target); } catch (e) { } } var manifestFile = installLocation.getItemFile(id, FILE_CHROME_MANIFEST); // new theme structure requires a chrome.manifest file if (manifestFile.exists()) { var entries = zipReader.findEntries(DIR_CHROME + "/*"); while (entries.hasMoreElements()) { entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry); if (entry.name.substr(entry.name.length - 1, 1) == "/") continue; target = installLocation.getItemFile(id, entry.name); try { target.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); } catch (e) { LOG("extractThemeFiles: failed to create target file for extraction " + " file = " + target.path + ", exception = " + e + "\n"); } zipReader.extract(entry.name, target); } zipReader.close(); } else { // old theme structure requires only an install.rdf try { var entry = zipReader.getEntry(FILE_CONTENTS_MANIFEST); var contentsManifestFile = installLocation.getItemFile(id, FILE_CONTENTS_MANIFEST); contentsManifestFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); zipReader.extract(FILE_CONTENTS_MANIFEST, contentsManifestFile); } catch (e) { zipReader.close(); LOG("extractThemeFiles: failed to extract contents.rdf: " + target.path); throw e; // let the safe-op clean up } zipReader.close(); var chromeDir = installLocation.getItemFile(id, DIR_CHROME); try { jarFile.copyTo(chromeDir, jarFile.leafName); } catch (e) { LOG("extractThemeFiles: failed to copy theme JAR file to: " + chromeDir.path); throw e; // let the safe-op clean up } if (!installer.metadataDS && installer._type == nsIUpdateItem.TYPE_THEME) { if (contentsManifestFile && contentsManifestFile.exists()) { var contentsManifest = gRDF.GetDataSourceBlocking(getURLSpecFromFile(contentsManifestFile)); showOldThemeError(contentsManifest); } LOG("Theme JAR file: " + jarFile.leafName + " contains an Old-Style " + "Theme that is not compatible with this version of the software."); throw new Error("Old Theme"); // let the safe-op clean up } } } var callback = extractExtensionFiles; if (this._type == nsIUpdateItem.TYPE_THEME) callback = extractThemeFiles; safeInstallOperation(this._id, this._installLocation, { callback: callback, data: file }); }, /** * Upgrade contents.rdf Chrome Manifests used by this Theme to the new * chrome.manifest format if necessary. */ upgradeThemeChrome: function() { // Use the Chrome Registry API to install the theme there var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"] .getService(Components.interfaces.nsIToolkitChromeRegistry); var manifestFile = this._installLocation.getItemFile(this._id, FILE_CHROME_MANIFEST); if (manifestFile.exists() || this._id == stripPrefix(RDFURI_DEFAULT_THEME, PREFIX_ITEM_URI)) return; try { // creates a chrome manifest for themes var manifestURI = getURIFromFile(manifestFile); var chromeDir = this._installLocation.getItemFile(this._id, DIR_CHROME); // We're relying on the fact that there is only one JAR file // in the "chrome" directory. This is a hack, but it works. var entries = chromeDir.directoryEntries.QueryInterface(nsIDirectoryEnumerator); var jarFile = entries.nextFile; if (jarFile) { var jarFileURI = getURIFromFile(jarFile); var contentsURI = newURI("jar:" + jarFileURI.spec + "!/"); var contentsFile = this._installLocation.getItemFile(this._id, FILE_CONTENTS_MANIFEST); var contentsFileURI = getURIFromFile(contentsFile.parent); cr.processContentsManifest(contentsFileURI, manifestURI, contentsURI, false, true); } entries.close(); contentsFile.remove(false); } catch (e) { // Failed to register chrome, for any number of reasons - non-existent // contents.rdf file at the location specified, malformed contents.rdf, // etc. Set the pending op to be OP_NEEDS_UNINSTALL so that the // extension is uninstalled properly during the subsequent uninstall // pass in |ExtensionManager::_finalizeOperations| LOG("upgradeThemeChrome: failed for theme " + this._id + " - why " + "not convert to the new chrome.manifest format while you're at it? " + "Failure exception: " + e); showMessage("malformedRegistrationTitle", [], "malformedRegistrationMessage", [BundleManager.appName]); var stageFile = this._installLocation.getStageFile(this._id); if (stageFile) this._installLocation.removeFile(stageFile); StartupCache.put(this._installLocation, this._id, OP_NEEDS_UNINSTALL, true); StartupCache.write(); } }, /** * Upgrade contents.rdf Chrome Manifests used by this Extension to the new * chrome.manifest format if necessary. */ upgradeExtensionChrome: function() { // If the extension is aware of the new flat chrome manifests and has // included one, just use it instead of generating one from the // install.rdf/contents.rdf data. var manifestFile = this._installLocation.getItemFile(this._id, FILE_CHROME_MANIFEST); if (manifestFile.exists()) return; try { // Enumerate the metadata datasource files collection and register chrome // for each file, calling _registerChrome for each. var chromeDir = this._installLocation.getItemFile(this._id, DIR_CHROME); if (!manifestFile.parent.exists()) return; // Even if an extension doesn't have any chrome, we generate an empty // manifest file so that we don't try to upgrade from the "old-style" // chrome manifests at every startup. manifestFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); var manifestURI = getURIFromFile(manifestFile); var files = this.metadataDS.GetTargets(gInstallManifestRoot, EM_R("file"), true); while (files.hasMoreElements()) { var file = files.getNext().QueryInterface(Components.interfaces.nsIRDFResource); var chromeFile = chromeDir.clone(); var fileName = file.Value.substr("urn:mozilla:extension:file:".length, file.Value.length); chromeFile.append(fileName); var fileURLSpec = getURLSpecFromFile(chromeFile); if (!chromeFile.isDirectory()) { var zipReader = getZipReaderForFile(chromeFile); fileURLSpec = "jar:" + fileURLSpec + "!/"; var contentsFile = this._installLocation.getItemFile(this._id, FILE_CONTENTS_MANIFEST); contentsFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); } var providers = [EM_R("package"), EM_R("skin"), EM_R("locale")]; for (var i = 0; i < providers.length; ++i) { var items = this.metadataDS.GetTargets(file, providers[i], true); while (items.hasMoreElements()) { var item = items.getNext().QueryInterface(Components.interfaces.nsIRDFLiteral); var fileURI = newURI(fileURLSpec + item.Value); // Extract the contents.rdf files instead of opening them inside of // the jar. This prevents the jar from being cached by the zip // reader which will keep the jar in use and prevent deletion. if (zipReader) { zipReader.extract(item.Value + FILE_CONTENTS_MANIFEST, contentsFile); var contentsFileURI = getURIFromFile(contentsFile.parent); } else contentsFileURI = fileURI; var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"] .getService(Components.interfaces.nsIToolkitChromeRegistry); cr.processContentsManifest(contentsFileURI, manifestURI, fileURI, true, false); } } if (zipReader) { zipReader.close(); zipReader = null; contentsFile.remove(false); } } } catch (e) { // Failed to register chrome, for any number of reasons - non-existent // contents.rdf file at the location specified, malformed contents.rdf, // etc. Set the pending op to be OP_NEEDS_UNINSTALL so that the // extension is uninstalled properly during the subsequent uninstall // pass in |ExtensionManager::_finalizeOperations| LOG("upgradeExtensionChrome: failed for extension " + this._id + " - why " + "not convert to the new chrome.manifest format while you're at it? " + "Failure exception: " + e); showMessage("malformedRegistrationTitle", [], "malformedRegistrationMessage", [BundleManager.appName]); var stageFile = this._installLocation.getStageFile(this._id); if (stageFile) this._installLocation.removeFile(stageFile); StartupCache.put(this._installLocation, this._id, OP_NEEDS_UNINSTALL, true); StartupCache.write(); } } };/** * Safely attempt to perform a caller-defined install operation for a given * item ID. Using aggressive success-safety checks, this function will attempt * to move an existing location for an item aside and then allow installation * into the appropriate folder. If any operation fails the installation will * abort and roll back from the moved-aside old version. * @param itemID * The GUID of the item to perform the operation on. * @param installLocation * The Install Location where the item is in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -