Bug 1735252 [wpt PR 31197] - Regenerate WPT certificates, a=testonly
[gecko.git] / toolkit / crashreporter / generate_crash_reporter_sources.py
blobc0699bd9e37027bf059883e4765da4c825c8b689
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 # You can obtain one at http://mozilla.org/MPL/2.0/.
5 import string
6 import sys
7 import textwrap
8 import yaml
10 ###############################################################################
11 # Language-agnostic functionality #
12 ###############################################################################
14 template_header = (
15 "/* This file was autogenerated by "
16 "toolkit/crashreporter/generate_crash_reporter_sources.py. DO NOT EDIT */\n\n"
20 def validate_annotations(annotations):
21 """ Ensure that the annotations have all the required fields """
23 for (name, data) in sorted(annotations.items()):
24 if "description" not in data:
25 print("Annotation " + name + " does not have a description\n")
26 sys.exit(1)
27 if "type" not in data:
28 print("Annotation " + name + " does not have a type\n")
29 sys.exit(1)
30 else:
31 annotation_type = data.get("type")
32 valid_types = ["boolean", "integer", "string"]
33 if not any(annotation_type == t for t in valid_types):
34 print(
35 "Annotation "
36 + name
37 + " has an unknown type: "
38 + annotation_type
39 + "\n"
41 sys.exit(1)
44 def read_annotations(annotations_filename):
45 """Read the annotations from a YAML file.
46 If an error is encountered quit the program."""
48 try:
49 with open(annotations_filename, "r") as annotations_file:
50 annotations = yaml.safe_load(annotations_file)
51 except (IOError, ValueError) as e:
52 print("Error parsing " + annotations_filename + ":\n" + str(e) + "\n")
53 sys.exit(1)
55 validate_annotations(annotations)
57 return annotations
60 def read_template(template_filename):
61 """Read the contents of the template.
62 If an error is encountered quit the program."""
64 try:
65 with open(template_filename, "r") as template_file:
66 template = template_file.read()
67 except IOError as ex:
68 print("Error when reading " + template_filename + ":\n" + str(ex) + "\n")
69 sys.exit(1)
71 return template
74 def extract_crash_ping_whitelist(annotations):
75 """Extract an array holding the names of the annotations whitelisted for
76 inclusion in the crash ping."""
78 return [
79 name for (name, data) in sorted(annotations.items()) if data.get("ping", False)
83 ###############################################################################
84 # C++ code generation #
85 ###############################################################################
88 def generate_strings(annotations):
89 """Generate strings corresponding to every annotation."""
91 names = [
92 ' "' + data.get("altname", name) + '"'
93 for (name, data) in sorted(annotations.items())
96 return ",\n".join(names)
99 def generate_enum(annotations):
100 """Generate the C++ typed enum holding all the annotations and return it
101 as a string."""
103 enum = ""
105 for i, (name, _) in enumerate(sorted(annotations.items())):
106 enum += " " + name + " = " + str(i) + ",\n"
108 enum += " Count = " + str(len(annotations))
110 return enum
113 def generate_array_initializer(contents):
114 """Generates the initializer for a C++ array of annotations."""
116 initializer = [" Annotation::" + name for name in contents]
118 return ",\n".join(initializer)
121 def generate_header(template, annotations):
122 """Generate a header by filling the template with the the list of
123 annotations and return it as a string."""
125 whitelist = extract_crash_ping_whitelist(annotations)
127 return template_header + string.Template(template).substitute(
129 "enum": generate_enum(annotations),
130 "strings": generate_strings(annotations),
131 "whitelist": generate_array_initializer(whitelist),
136 def emit_header(output, template_filename, annotations_filename):
137 """Generate the C++ header from the template and write it out."""
139 annotations = read_annotations(annotations_filename)
140 template = read_template(template_filename)
141 generated_header = generate_header(template, annotations)
143 try:
144 output.write(generated_header)
145 except IOError as ex:
146 print("Error while writing out the generated file:\n" + str(ex) + "\n")
147 sys.exit(1)
150 ###############################################################################
151 # Java code generation #
152 ###############################################################################
155 def generate_java_array_initializer(contents):
156 """Generates the initializer for an array of strings.
157 Effectively turns `["a", "b"]` into ' \"a\",\n \"b\"\n'."""
159 initializer = ""
161 for name in contents:
162 initializer += ' "' + name + '",\n'
164 return initializer.strip(",\n")
167 def generate_class(template, annotations):
168 """Fill the class template from the list of annotations."""
170 whitelist = extract_crash_ping_whitelist(annotations)
172 return template_header + string.Template(template).substitute(
174 "whitelist": generate_java_array_initializer(whitelist),
179 def emit_class(output, annotations_filename):
180 """Generate the CrashReporterConstants.java file."""
182 template = textwrap.dedent(
183 """\
184 package org.mozilla.gecko;
187 * Constants used by the crash reporter. These are generated so that they
188 * are kept in sync with the other C++ and JS users.
190 public class CrashReporterConstants {
191 public static final String[] ANNOTATION_WHITELIST = {
192 ${whitelist}
194 }"""
197 annotations = read_annotations(annotations_filename)
198 generated_class = generate_class(template, annotations)
200 try:
201 output.write(generated_class)
202 except IOError as ex:
203 print("Error while writing out the generated file:\n" + str(ex) + "\n")
204 sys.exit(1)