diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /toolkit/crashreporter/generate_crash_reporter_sources.py | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/crashreporter/generate_crash_reporter_sources.py')
-rw-r--r-- | toolkit/crashreporter/generate_crash_reporter_sources.py | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/toolkit/crashreporter/generate_crash_reporter_sources.py b/toolkit/crashreporter/generate_crash_reporter_sources.py new file mode 100644 index 0000000000..b8c3333557 --- /dev/null +++ b/toolkit/crashreporter/generate_crash_reporter_sources.py @@ -0,0 +1,259 @@ +# 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 string +import sys +import textwrap + +import yaml + +############################################################################### +# Language-agnostic functionality # +############################################################################### + +template_header = ( + "/* This file was autogenerated by " + "toolkit/crashreporter/generate_crash_reporter_sources.py. DO NOT EDIT */\n\n" +) + + +def validate_annotations(annotations): + """Ensure that the annotations have all the required fields""" + + for name, data in sorted(annotations.items()): + if "description" not in data: + print("Annotation " + name + " does not have a description\n") + sys.exit(1) + if "type" not in data: + print("Annotation " + name + " does not have a type\n") + sys.exit(1) + else: + annotation_type = data.get("type") + valid_types = ["string", "boolean", "u32", "u64", "usize"] + if not any(annotation_type == t for t in valid_types): + print( + "Annotation " + + name + + " has an unknown type: " + + annotation_type + + "\n" + ) + sys.exit(1) + + +def read_annotations(annotations_filename): + """Read the annotations from a YAML file. + If an error is encountered quit the program.""" + + try: + with open(annotations_filename, "r") as annotations_file: + annotations = yaml.safe_load(annotations_file) + except (IOError, ValueError) as e: + print("Error parsing " + annotations_filename + ":\n" + str(e) + "\n") + sys.exit(1) + + validate_annotations(annotations) + + return annotations + + +def read_template(template_filename): + """Read the contents of the template. + If an error is encountered quit the program.""" + + try: + with open(template_filename, "r") as template_file: + template = template_file.read() + except IOError as ex: + print("Error when reading " + template_filename + ":\n" + str(ex) + "\n") + sys.exit(1) + + return template + + +def extract_crash_ping_allowedlist(annotations): + """Extract an array holding the names of the annotations allowed for + inclusion in the crash ping.""" + + return [ + name for (name, data) in sorted(annotations.items()) if data.get("ping", False) + ] + + +def extract_skiplist(annotations): + """Extract an array holding the names of the annotations that should be + skipped and the values which will cause them to be skipped.""" + + return [ + (name, data.get("skip_if")) + for (name, data) in sorted(annotations.items()) + if len(data.get("skip_if", "")) > 0 + ] + + +def type_to_enum(annotation_type): + """Emit the enum value corresponding to each annotation type.""" + + if annotation_type == "string": + return "String" + elif annotation_type == "boolean": + return "Boolean" + elif annotation_type == "u32": + return "U32" + elif annotation_type == "u64": + return "U64" + elif annotation_type == "usize": + return "USize" + + +def extract_types(annotations): + """Extract an array holding the type of each annotation.""" + + return [type_to_enum(data.get("type")) for (_, data) in sorted(annotations.items())] + + +############################################################################### +# C++ code generation # +############################################################################### + + +def generate_strings(annotations): + """Generate strings corresponding to every annotation.""" + + names = [ + ' "' + data.get("altname", name) + '"' + for (name, data) in sorted(annotations.items()) + ] + + return ",\n".join(names) + + +def generate_enum(annotations): + """Generate the C++ typed enum holding all the annotations and return it + as a string.""" + + enum = "" + + for i, (name, _) in enumerate(sorted(annotations.items())): + enum += " " + name + " = " + str(i) + ",\n" + + enum += " Count = " + str(len(annotations)) + + return enum + + +def generate_annotations_array_initializer(contents): + """Generates the initializer for a C++ array of annotations.""" + + initializer = [" Annotation::" + name for name in contents] + + return ",\n".join(initializer) + + +def generate_skiplist_initializer(contents): + """Generates the initializer for a C++ array of AnnotationSkipValue structs.""" + + initializer = [ + " { Annotation::" + name + ', "' + value + '" }' for (name, value) in contents + ] + + return ",\n".join(initializer) + + +def generate_types_initializer(contents): + """Generates the initializer for a C++ array of AnnotationType values.""" + + initializer = [" AnnotationType::" + typename for typename in contents] + + return ",\n".join(initializer) + + +def generate_header(template, annotations): + """Generate a header by filling the template with the the list of + annotations and return it as a string.""" + + allowedlist = extract_crash_ping_allowedlist(annotations) + skiplist = extract_skiplist(annotations) + typelist = extract_types(annotations) + + return template_header + string.Template(template).substitute( + { + "enum": generate_enum(annotations), + "strings": generate_strings(annotations), + "allowedlist": generate_annotations_array_initializer(allowedlist), + "skiplist": generate_skiplist_initializer(skiplist), + "types": generate_types_initializer(typelist), + } + ) + + +def emit_header(output, template_filename, annotations_filename): + """Generate the C++ header from the template and write it out.""" + + annotations = read_annotations(annotations_filename) + template = read_template(template_filename) + generated_header = generate_header(template, annotations) + + try: + output.write(generated_header) + except IOError as ex: + print("Error while writing out the generated file:\n" + str(ex) + "\n") + sys.exit(1) + + +############################################################################### +# Java code generation # +############################################################################### + + +def generate_java_array_initializer(contents): + """Generates the initializer for an array of strings. + Effectively turns `["a", "b"]` into ' \"a\",\n \"b\"\n'.""" + + initializer = "" + + for name in contents: + initializer += ' "' + name + '",\n' + + return initializer.strip(",\n") + + +def generate_class(template, annotations): + """Fill the class template from the list of annotations.""" + + allowedlist = extract_crash_ping_allowedlist(annotations) + + return template_header + string.Template(template).substitute( + { + "allowedlist": generate_java_array_initializer(allowedlist), + } + ) + + +def emit_class(output, annotations_filename): + """Generate the CrashReporterConstants.java file.""" + + template = textwrap.dedent( + """\ + package org.mozilla.gecko; + + /** + * Constants used by the crash reporter. These are generated so that they + * are kept in sync with the other C++ and JS users. + */ + public class CrashReporterConstants { + public static final String[] ANNOTATION_ALLOWEDLIST = { + ${allowedlist} + }; + }""" + ) + + annotations = read_annotations(annotations_filename) + generated_class = generate_class(template, annotations) + + try: + output.write(generated_class) + except IOError as ex: + print("Error while writing out the generated file:\n" + str(ex) + "\n") + sys.exit(1) |