From 1f087f9cfca3da180857ad85bc2fb10054a2b794 Mon Sep 17 00:00:00 2001 From: Andrew Swan Date: Wed, 1 Aug 2018 18:22:23 -0700 Subject: [PATCH] Bug 1449055 Make browser_all_files_referenced.js work with formautofill as a webextension r=florian MozReview-Commit-ID: JV3vA8bmDWt --HG-- extra : rebase_source : 2b0410d2c97e80d032d4cc9116dd2a092ead8c66 extra : intermediate-source : fc97f5b5e65d6dfaac3cf618c7b87e11d5186d4d extra : source : 644216b0ad9b5f9e1e9e8f1f930d4db1c6e717a1 --- .../static/browser_all_files_referenced.js | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/browser/base/content/test/static/browser_all_files_referenced.js b/browser/base/content/test/static/browser_all_files_referenced.js index 3912f22d817a..e1cb3b231490 100644 --- a/browser/base/content/test/static/browser_all_files_referenced.js +++ b/browser/base/content/test/static/browser_all_files_referenced.js @@ -244,13 +244,23 @@ function getBaseUriForChromeUri(chromeUri) { return fileUri.resolve("."); } +function trackChromeUri(uri) { + gChromeMap.set(getBaseUriForChromeUri(uri), uri); +} + +// formautofill registers resource://formautofill/ and +// chrome://formautofill/content/ dynamically at runtime. +// Bug 1480276 is about addressing this without this hard-coding. +trackResourcePrefix("formautofill"); +trackChromeUri("chrome://formautofill/content/"); + function parseManifest(manifestUri) { return fetchFile(manifestUri.spec).then(data => { for (let line of data.split("\n")) { let [type, ...argv] = line.split(/\s+/); if (type == "content" || type == "skin" || type == "locale") { let chromeUri = `chrome://${argv[0]}/${type}/`; - gChromeMap.set(getBaseUriForChromeUri(chromeUri), chromeUri); + trackChromeUri(chromeUri); } else if (type == "override" || type == "overlay") { // Overlays aren't really overrides, but behave the same in // that the overlay is only referenced if the original xul @@ -271,6 +281,35 @@ function parseManifest(manifestUri) { }); } +// If the given URI is a webextension manifest, extract the scripts +// for any embedded APIs. Returns the passed in URI if the manifest +// is not a webextension manifest, null otherwise. +async function parseJsonManifest(uri) { + let raw = await fetchFile(uri.spec); + let data; + try { + data = JSON.parse(raw); + } catch (ex) { + return uri; + } + + // Simplistic test for whether this is a webextension manifest: + if (data.manifest_version !== 2) { + return uri; + } + + if (data.experiment_apis) { + for (let api of Object.values(data.experiment_apis)) { + if (api.parent && api.parent.script) { + let script = uri.resolve(api.parent.script); + gReferencesFromCode.set(script, null); + } + } + } + + return null; +} + function addCodeReference(url, fromURI) { let from = convertToCodeURI(fromURI.spec); @@ -546,11 +585,15 @@ add_task(async function checkAllTheFiles() { // NOTE that this must be done before filtering out devtools paths // so that all chrome paths can be recorded. let manifestURIs = []; + let jsonManifests = []; uris = uris.filter(uri => { let path = uri.pathQueryRef; if (path.endsWith(".manifest")) { manifestURIs.push(uri); return false; + } else if (path.endsWith("/manifest.json")) { + jsonManifests.push(uri); + return false; } return true; @@ -559,6 +602,15 @@ add_task(async function checkAllTheFiles() { // Wait for all manifest to be parsed await throttledMapPromises(manifestURIs, parseManifest); + // manifest.json is a common name, it is used for WebExtension manifests + // but also for other things. To tell them apart, we have to actually + // read the contents. This will populate gExtensionRoots with all + // embedded extension APIs, and return any manifest.json files that aren't + // webextensions. + let nonWebextManifests = (await Promise.all(jsonManifests.map(parseJsonManifest))) + .filter(uri => !!uri); + uris.push(...nonWebextManifests); + addActorModules(); // We build a list of promises that get resolved when their respective