Bug 1192433: Part 3 - Support localized names and descriptions in WebExtension manifests. r=Mossop

--HG--
extra : commitid : 79RHXd1mZtp
extra : rebase_source : 3bbd8ae3184d58ba5d2c1d332e0209fb2d0a19ef
This commit is contained in:
Kris Maglione 2015-11-02 16:50:42 -08:00
Родитель e18450690a
Коммит 4a1b170b2c
5 изменённых файлов: 149 добавлений и 66 удалений

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

@ -22,6 +22,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ChromeManifestParser",
"resource://gre/modules/ChromeManifestParser.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
"resource://gre/modules/LightweightThemeManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Locale",
"resource://gre/modules/Locale.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
@ -828,15 +830,20 @@ function getRDFProperty(aDs, aResource, aProperty) {
/**
* Reads an AddonInternal object from a manifest stream.
*
* @param aStream
* An open stream to read the manifest from
* @param aUri
* A |file:| or |jar:| URL for the manifest
* @return an AddonInternal object
* @throws if the install manifest in the stream is corrupt or could not
* be read
*/
function loadManifestFromWebManifest(aStream) {
let decoder = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
let manifest = decoder.decodeFromStream(aStream, aStream.available());
var loadManifestFromWebManifest = Task.async(function* loadManifestFromWebManifest(aUri) {
// We're passed the URI for the manifest file. Get the URI for its
// parent directory.
let uri = NetUtil.newURI("./", null, aUri);
let extension = new ExtensionData(uri);
let manifest = yield extension.readManifest();
function findProp(obj, current, properties) {
if (properties.length == 0)
@ -903,30 +910,46 @@ function loadManifestFromWebManifest(aStream) {
addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT;
addon.defaultLocale = {
name: getProp("name"),
description: getOptionalProp("description"),
creator: null,
homepageURL: null,
function getLocale(aLocale) {
let result = {
name: extension.localize(getProp("name"), aLocale),
description: extension.localize(getOptionalProp("description"), aLocale),
creator: null,
homepageURL: null,
developers: null,
translators: null,
contributors: null,
developers: null,
translators: null,
contributors: null,
locales: [aLocale],
};
return result;
}
// Read the list of available locales, and pre-load messages for
// all locales.
let locales = yield extension.initAllLocales();
// If there were any errors loading the extension, bail out now.
if (extension.errors.length)
throw new Error("Extension is invalid");
addon.defaultLocale = getLocale(extension.defaultLocale);
addon.locales = Array.from(locales.keys(), getLocale);
delete addon.defaultLocale.locales;
addon.targetApplications = [{
id: TOOLKIT_ID,
minVersion: AddonManagerPrivate.webExtensionsMinPlatformVersion,
maxVersion: "*",
}];
addon.locales = [];
addon.targetPlatforms = [];
addon.userDisabled = false;
addon.softDisabled = addon.blocklistState == Blocklist.STATE_SOFTBLOCKED;
return addon;
}
});
/**
* Reads an AddonInternal object from an RDF stream.
@ -1251,8 +1274,19 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal
return size;
}
function loadFromRDF(aFile, aStream) {
let addon = loadManifestFromRDF(Services.io.newFileURI(aFile), aStream);
function loadFromRDF(aUri) {
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
fis.init(aUri.file, -1, -1, false);
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
createInstance(Ci.nsIBufferedInputStream);
bis.init(fis, 4096);
try {
var addon = loadManifestFromRDF(aUri, bis);
} finally {
bis.close();
fis.close();
}
let iconFile = aDir.clone();
iconFile.append("icon.png");
@ -1283,32 +1317,21 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal
"install manifest");
}
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
fis.init(file, -1, -1, false);
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
createInstance(Ci.nsIBufferedInputStream);
bis.init(fis, 4096);
let uri = Services.io.newFileURI(file).QueryInterface(Ci.nsIFileURL);
try {
let addon = file.leafName == FILE_WEB_MANIFEST ?
loadManifestFromWebManifest(bis) :
loadFromRDF(file, bis);
let addon = file.leafName == FILE_WEB_MANIFEST ?
yield loadManifestFromWebManifest(uri) :
loadFromRDF(uri);
addon._sourceBundle = aDir.clone();
addon._installLocation = aInstallLocation;
addon.size = getFileSize(aDir);
addon.signedState = yield verifyDirSignedState(aDir, addon);
addon.appDisabled = !isUsableAddon(addon);
addon._sourceBundle = aDir.clone();
addon._installLocation = aInstallLocation;
addon.size = getFileSize(aDir);
addon.signedState = yield verifyDirSignedState(aDir, addon);
addon.appDisabled = !isUsableAddon(addon);
defineSyncGUID(addon);
defineSyncGUID(addon);
return addon;
}
finally {
bis.close();
fis.close();
}
return addon;
});
/**
@ -1320,9 +1343,17 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal
* @throws if the XPI file does not contain a valid install manifest
*/
var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(aZipReader, aInstallLocation) {
function loadFromRDF(aStream) {
let uri = buildJarURI(aZipReader.file, FILE_RDF_MANIFEST);
let addon = loadManifestFromRDF(uri, aStream);
function loadFromRDF(aUri) {
let zis = aZipReader.getInputStream(entry);
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
createInstance(Ci.nsIBufferedInputStream);
bis.init(zis, 4096);
try {
var addon = loadManifestFromRDF(aUri, bis);
} finally {
bis.close();
zis.close();
}
if (aZipReader.hasEntry("icon.png")) {
addon.icons[32] = "icon.png";
@ -1335,7 +1366,7 @@ var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
// Binary components can only be loaded from unpacked addons.
if (addon.unpack) {
uri = buildJarURI(aZipReader.file, "chrome.manifest");
let uri = buildJarURI(aZipReader.file, "chrome.manifest");
let chromeManifest = ChromeManifestParser.parseSync(uri);
addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
"binary-component");
@ -1352,35 +1383,26 @@ var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
"install manifest");
}
let zis = aZipReader.getInputStream(entry);
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
createInstance(Ci.nsIBufferedInputStream);
bis.init(zis, 4096);
let uri = buildJarURI(aZipReader.file, entry);
try {
let addon = entry == FILE_WEB_MANIFEST ?
loadManifestFromWebManifest(bis) :
loadFromRDF(bis);
let addon = entry == FILE_WEB_MANIFEST ?
yield loadManifestFromWebManifest(uri) :
loadFromRDF(uri);
addon._sourceBundle = aZipReader.file;
addon._installLocation = aInstallLocation;
addon._sourceBundle = aZipReader.file;
addon._installLocation = aInstallLocation;
addon.size = 0;
let entries = aZipReader.findEntries(null);
while (entries.hasMore())
addon.size += aZipReader.getEntry(entries.getNext()).realSize;
addon.size = 0;
let entries = aZipReader.findEntries(null);
while (entries.hasMore())
addon.size += aZipReader.getEntry(entries.getNext()).realSize;
addon.signedState = yield verifyZipSignedState(aZipReader.file, addon);
addon.appDisabled = !isUsableAddon(addon);
addon.signedState = yield verifyZipSignedState(aZipReader.file, addon);
addon.appDisabled = !isUsableAddon(addon);
defineSyncGUID(addon);
defineSyncGUID(addon);
return addon;
}
finally {
bis.close();
zis.close();
}
return addon;
});
/**

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

@ -0,0 +1,10 @@
{
"name": {
"message": "foo",
"description": "foo"
},
"desc": {
"message": "bar",
"description": "bar"
}
}

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

@ -0,0 +1,10 @@
{
"name": {
"message": "le foo",
"description": "foo"
},
"desc": {
"message": "le bar",
"description": "bar"
}
}

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

@ -0,0 +1,12 @@
{
"name": "Web Extension __MSG_name__",
"description": "Descripton __MSG_desc__ of add-on",
"version": "1.0",
"manifest_version": 2,
"default_locale": "en",
"applications": {
"gecko": {
"id": "webextension3@tests.mozilla.org"
}
}
}

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

@ -4,6 +4,8 @@
const ID = "webextension1@tests.mozilla.org";
const PREF_SELECTED_LOCALE = "general.useragent.locale";
const profileDir = gProfD.clone();
profileDir.append("extensions");
@ -142,6 +144,33 @@ add_task(function*() {
yield promiseRestartManager();
});
add_task(function* test_manifest_localization() {
const ID = "webextension3@tests.mozilla.org";
yield promiseInstallAllFiles([do_get_addon("webextension_3")], true);
let addon = yield promiseAddonByID(ID);
equal(addon.name, "Web Extension foo");
equal(addon.description, "Descripton bar of add-on");
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "fr-FR");
yield promiseRestartManager();
addon = yield promiseAddonByID(ID);
equal(addon.name, "Web Extension le foo");
equal(addon.description, "Descripton le bar of add-on");
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "de");
yield promiseRestartManager();
addon = yield promiseAddonByID(ID);
equal(addon.name, "Web Extension foo");
equal(addon.description, "Descripton bar of add-on");
});
// Missing ID should cause a failure
add_task(function*() {
writeWebManifestForExtension({