# 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/. """ This script implements the `mach devtools-css-db` command. It runs an xpcshell script that uses InspectorUtils to query the CSS properties used by the browser. This information is used to generate the properties-db.js file. """ import json import logging import os import runpy import sys import string import subprocess from mozbuild import shellutil from mozbuild.base import ( MozbuildObject, BinaryNotFoundException, ) from mach.decorators import ( Command, ) def resolve_path(start, relativePath): """Helper to resolve a path from a start, and a relative path""" return os.path.normpath(os.path.join(start, relativePath)) def stringify(obj): """Helper to stringify to JSON""" return json.dumps(obj, sort_keys=True, indent=2, separators=(",", ": ")) @Command( "devtools-css-db", category="post-build", description="Rebuild the devtool's static css properties database.", ) def generate_css_db(command_context): """Generate the static css properties database for devtools and write it to file.""" print("Re-generating the css properties database...") db = get_properties_db_from_xpcshell(command_context) if not db: return 1 output_template( command_context, { "cssProperties": stringify(db["cssProperties"]), "pseudoElements": stringify(db["pseudoElements"]), }, ) def get_properties_db_from_xpcshell(command_context): """Generate the static css properties db for devtools from an xpcshell script.""" build = MozbuildObject.from_environment() # Get the paths script_path = resolve_path( command_context.topsrcdir, "devtools/shared/css/generated/generate-properties-db.js", ) gre_path = resolve_path(command_context.topobjdir, "dist/bin") browser_path = resolve_path(command_context.topobjdir, "dist/bin/browser") try: xpcshell_path = build.get_binary_path(what="xpcshell") except BinaryNotFoundException as e: command_context.log( logging.ERROR, "devtools-css-db", {"error": str(e)}, "ERROR: {error}" ) command_context.log( logging.INFO, "devtools-css-db", {"help": e.help()}, "{help}" ) return None print(browser_path) sub_env = dict(os.environ) if sys.platform.startswith("linux"): sub_env["LD_LIBRARY_PATH"] = gre_path # Run the xcpshell script, and set the appdir flag to the browser path so that # we have the proper dependencies for requiring the loader. contents = subprocess.check_output( [xpcshell_path, "-g", gre_path, "-a", browser_path, script_path], env=sub_env, ) # Extract just the output between the delimiters as the xpcshell output can # have extra output that we don't want. contents = contents.decode().split("DEVTOOLS_CSS_DB_DELIMITER")[1] return json.loads(contents) def output_template(command_context, substitutions): """Output a the properties-db.js from a template.""" js_template_path = resolve_path( command_context.topsrcdir, "devtools/shared/css/generated/properties-db.js.in", ) destination_path = resolve_path( command_context.topsrcdir, "devtools/shared/css/generated/properties-db.js" ) with open(js_template_path, "rb") as handle: js_template = handle.read().decode() preamble = "/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n" contents = string.Template(js_template).substitute(substitutions) with open(destination_path, "wb") as destination: destination.write(preamble.encode() + contents.encode()) print("The database was successfully generated at " + destination_path)