Bug 1449055 Make browser_all_files_referenced.js work with formautofill as a webextension r=florian
authorAndrew Swan <aswan@mozilla.com>
Wed, 01 Aug 2018 18:22:23 -0700
changeset 487063 39dc85d0cc5a9255768fd0147d6909e69193b4b3
parent 487062 d13360c413ff6bd1fcb05201bb58ca4f61ff85bd
child 487064 908ddb41b8b528351889f53e698c267356f0db5f
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflorian
bugs1449055
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1449055 Make browser_all_files_referenced.js work with formautofill as a webextension r=florian MozReview-Commit-ID: JV3vA8bmDWt
browser/base/content/test/static/browser_all_files_referenced.js
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -239,23 +239,33 @@ trackResourcePrefix("app");
 
 function getBaseUriForChromeUri(chromeUri) {
   let chromeFile = chromeUri + "gobbledygooknonexistentfile.reallynothere";
   let uri = Services.io.newURI(chromeFile);
   let fileUri = gChromeReg.convertChromeURL(uri);
   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
         // file is referenced somewhere.
         let os = "os=" + Services.appinfo.OS;
         if (!argv.some(s => s.startsWith("os=") && s != os)) {
           gOverrideMap.set(Services.io.newURI(argv[1]).specIgnoringRef,
                            Services.io.newURI(argv[0]).specIgnoringRef);
@@ -266,16 +276,45 @@ function parseManifest(manifestUri) {
         trackResourcePrefix(argv[0]);
       } else if (type == "component") {
         gComponentsSet.add(argv[1]);
       }
     }
   });
 }
 
+// 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);
 
   // Ignore self references.
   if (url == from)
     return;
 
   let ref;
@@ -541,29 +580,42 @@ add_task(async function checkAllTheFiles
   // test infrastructure because it runs against jarfiles there, and
   // our zipreader APIs are all sync)
   let uris = await generateURIsFromDirTree(appDir, [".css", ".manifest", ".jpg", ".png", ".gif", ".svg",  ".dtd", ".properties"].concat(kCodeExtensions));
 
   // Parse and remove all manifests from the list.
   // 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;
   });
 
   // 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
   // files have loaded and produced no errors.
   let allPromises = [];
 
   for (let uri of uris) {
     let path = uri.pathQueryRef;