diff options
Diffstat (limited to 'python/mozbuild/mozbuild/codecoverage/chrome_map.py')
-rw-r--r-- | python/mozbuild/mozbuild/codecoverage/chrome_map.py | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/codecoverage/chrome_map.py b/python/mozbuild/mozbuild/codecoverage/chrome_map.py new file mode 100644 index 0000000000..79cedd2faf --- /dev/null +++ b/python/mozbuild/mozbuild/codecoverage/chrome_map.py @@ -0,0 +1,175 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import json +import os +import re + +import mozpack.path as mozpath +import six +from mach.config import ConfigSettings +from mach.logging import LoggingManager +from mozpack.copier import FileRegistry +from mozpack.files import PreprocessedFile +from mozpack.manifests import InstallManifest + +from mozbuild.backend.common import CommonBackend +from mozbuild.base import MozbuildObject +from mozbuild.frontend.data import ( + ChromeManifestEntry, + FinalTargetFiles, + FinalTargetPreprocessedFiles, + JARManifest, +) + +from .manifest_handler import ChromeManifestHandler + +_line_comment_re = re.compile('^//@line (\d+) "(.+)"$') + + +def generate_pp_info(path, topsrcdir): + with open(path, encoding="utf-8") as fh: + # (start, end) -> (included_source, start) + section_info = dict() + + this_section = None + + def finish_section(pp_end): + pp_start, inc_source, inc_start = this_section + section_info[str(pp_start) + "," + str(pp_end)] = inc_source, inc_start + + for count, line in enumerate(fh): + # Regex are quite slow, so bail out early. + if not line.startswith("//@line"): + continue + m = re.match(_line_comment_re, line) + if m: + if this_section: + finish_section(count + 1) + inc_start, inc_source = m.groups() + + # Special case to handle $SRCDIR prefixes + src_dir_prefix = "$SRCDIR" + parts = mozpath.split(inc_source) + if parts[0] == src_dir_prefix: + inc_source = mozpath.join(*parts[1:]) + else: + inc_source = mozpath.relpath(inc_source, topsrcdir) + + pp_start = count + 2 + this_section = pp_start, inc_source, int(inc_start) + + if this_section: + finish_section(count + 2) + + return section_info + + +# This build backend is assuming the build to have happened already, as it is parsing +# built preprocessed files to generate data to map them to the original sources. + + +class ChromeMapBackend(CommonBackend): + def _init(self): + CommonBackend._init(self) + + log_manager = LoggingManager() + self._cmd = MozbuildObject( + self.environment.topsrcdir, + ConfigSettings(), + log_manager, + self.environment.topobjdir, + ) + self._install_mapping = {} + self.manifest_handler = ChromeManifestHandler() + + def consume_object(self, obj): + if isinstance(obj, JARManifest): + self._consume_jar_manifest(obj) + if isinstance(obj, ChromeManifestEntry): + self.manifest_handler.handle_manifest_entry(obj.entry) + if isinstance(obj, (FinalTargetFiles, FinalTargetPreprocessedFiles)): + self._handle_final_target_files(obj) + return True + + def _handle_final_target_files(self, obj): + for path, files in obj.files.walk(): + for f in files: + dest = mozpath.join(obj.install_target, path, f.target_basename) + obj_path = mozpath.join(self.environment.topobjdir, dest) + if obj_path.endswith(".in"): + obj_path = obj_path[:-3] + if isinstance(obj, FinalTargetPreprocessedFiles): + assert os.path.exists(obj_path), "%s should exist" % obj_path + pp_info = generate_pp_info(obj_path, obj.topsrcdir) + else: + pp_info = None + + base = ( + obj.topobjdir + if f.full_path.startswith(obj.topobjdir) + else obj.topsrcdir + ) + self._install_mapping[dest] = ( + mozpath.relpath(f.full_path, base), + pp_info, + ) + + def consume_finished(self): + mp = os.path.join( + self.environment.topobjdir, "_build_manifests", "install", "_tests" + ) + install_manifest = InstallManifest(mp) + reg = FileRegistry() + install_manifest.populate_registry(reg) + + for dest, src in reg: + if not hasattr(src, "path"): + continue + + if not os.path.isabs(dest): + dest = "_tests/" + dest + + obj_path = mozpath.join(self.environment.topobjdir, dest) + if isinstance(src, PreprocessedFile): + assert os.path.exists(obj_path), "%s should exist" % obj_path + pp_info = generate_pp_info(obj_path, self.environment.topsrcdir) + else: + pp_info = None + + rel_src = mozpath.relpath(src.path, self.environment.topsrcdir) + self._install_mapping[dest] = rel_src, pp_info + + # Our result has four parts: + # A map from url prefixes to objdir directories: + # { "chrome://mozapps/content/": [ "dist/bin/chrome/toolkit/content/mozapps" ], ... } + # A map of overrides. + # A map from objdir paths to sourcedir paths, and an object storing mapping + # information for preprocessed files: + # { "dist/bin/browser/chrome/browser/content/browser/aboutSessionRestore.js": + # [ "$topsrcdir/browser/components/sessionstore/content/aboutSessionRestore.js", {} ], + # ... } + # An object containing build configuration information. + outputfile = os.path.join(self.environment.topobjdir, "chrome-map.json") + with self._write_file(outputfile) as fh: + chrome_mapping = self.manifest_handler.chrome_mapping + overrides = self.manifest_handler.overrides + json.dump( + [ + {k: list(v) for k, v in six.iteritems(chrome_mapping)}, + overrides, + self._install_mapping, + { + "topobjdir": mozpath.normpath(self.environment.topobjdir), + "MOZ_APP_NAME": self.environment.substs.get("MOZ_APP_NAME"), + "OMNIJAR_NAME": self.environment.substs.get("OMNIJAR_NAME"), + "MOZ_MACBUNDLE_NAME": self.environment.substs.get( + "MOZ_MACBUNDLE_NAME" + ), + }, + ], + fh, + sort_keys=True, + indent=2, + ) |