Bug 1887774 convert from MediaEnginePrefs to AudioProcessing config in AudioInputProc...
[gecko.git] / toolkit / crashreporter / generate_crash_reporter_sources.py
blobb8c33335573746c6e98bcf2bd0f851f69767d899
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
9 import yaml
11 ###############################################################################
12 # Language-agnostic functionality #
13 ###############################################################################
15 template_header = (
16 "/* This file was autogenerated by "
17 "toolkit/crashreporter/generate_crash_reporter_sources.py. DO NOT EDIT */\n\n"
21 def validate_annotations(annotations):
22 """Ensure that the annotations have all the required fields"""
24 for name, data in sorted(annotations.items()):
25 if "description" not in data:
26 print("Annotation " + name + " does not have a description\n")
27 sys.exit(1)
28 if "type" not in data:
29 print("Annotation " + name + " does not have a type\n")
30 sys.exit(1)
31 else:
32 annotation_type = data.get("type")
33 valid_types = ["string", "boolean", "u32", "u64", "usize"]
34 if not any(annotation_type == t for t in valid_types):
35 print(
36 "Annotation "
37 + name
38 + " has an unknown type: "
39 + annotation_type
40 + "\n"
42 sys.exit(1)
45 def read_annotations(annotations_filename):
46 """Read the annotations from a YAML file.
47 If an error is encountered quit the program."""
49 try:
50 with open(annotations_filename, "r") as annotations_file:
51 annotations = yaml.safe_load(annotations_file)
52 except (IOError, ValueError) as e:
53 print("Error parsing " + annotations_filename + ":\n" + str(e) + "\n")
54 sys.exit(1)
56 validate_annotations(annotations)
58 return annotations
61 def read_template(template_filename):
62 """Read the contents of the template.
63 If an error is encountered quit the program."""
65 try:
66 with open(template_filename, "r") as template_file:
67 template = template_file.read()
68 except IOError as ex:
69 print("Error when reading " + template_filename + ":\n" + str(ex) + "\n")
70 sys.exit(1)
72 return template
75 def extract_crash_ping_allowedlist(annotations):
76 """Extract an array holding the names of the annotations allowed for
77 inclusion in the crash ping."""
79 return [
80 name for (name, data) in sorted(annotations.items()) if data.get("ping", False)
84 def extract_skiplist(annotations):
85 """Extract an array holding the names of the annotations that should be
86 skipped and the values which will cause them to be skipped."""
88 return [
89 (name, data.get("skip_if"))
90 for (name, data) in sorted(annotations.items())
91 if len(data.get("skip_if", "")) > 0
95 def type_to_enum(annotation_type):
96 """Emit the enum value corresponding to each annotation type."""
98 if annotation_type == "string":
99 return "String"
100 elif annotation_type == "boolean":
101 return "Boolean"
102 elif annotation_type == "u32":
103 return "U32"
104 elif annotation_type == "u64":
105 return "U64"
106 elif annotation_type == "usize":
107 return "USize"
110 def extract_types(annotations):
111 """Extract an array holding the type of each annotation."""
113 return [type_to_enum(data.get("type")) for (_, data) in sorted(annotations.items())]
116 ###############################################################################
117 # C++ code generation #
118 ###############################################################################
121 def generate_strings(annotations):
122 """Generate strings corresponding to every annotation."""
124 names = [
125 ' "' + data.get("altname", name) + '"'
126 for (name, data) in sorted(annotations.items())
129 return ",\n".join(names)
132 def generate_enum(annotations):
133 """Generate the C++ typed enum holding all the annotations and return it
134 as a string."""
136 enum = ""
138 for i, (name, _) in enumerate(sorted(annotations.items())):
139 enum += " " + name + " = " + str(i) + ",\n"
141 enum += " Count = " + str(len(annotations))
143 return enum
146 def generate_annotations_array_initializer(contents):
147 """Generates the initializer for a C++ array of annotations."""
149 initializer = [" Annotation::" + name for name in contents]
151 return ",\n".join(initializer)
154 def generate_skiplist_initializer(contents):
155 """Generates the initializer for a C++ array of AnnotationSkipValue structs."""
157 initializer = [
158 " { Annotation::" + name + ', "' + value + '" }' for (name, value) in contents
161 return ",\n".join(initializer)
164 def generate_types_initializer(contents):
165 """Generates the initializer for a C++ array of AnnotationType values."""
167 initializer = [" AnnotationType::" + typename for typename in contents]
169 return ",\n".join(initializer)
172 def generate_header(template, annotations):
173 """Generate a header by filling the template with the the list of
174 annotations and return it as a string."""
176 allowedlist = extract_crash_ping_allowedlist(annotations)
177 skiplist = extract_skiplist(annotations)
178 typelist = extract_types(annotations)
180 return template_header + string.Template(template).substitute(
182 "enum": generate_enum(annotations),
183 "strings": generate_strings(annotations),
184 "allowedlist": generate_annotations_array_initializer(allowedlist),
185 "skiplist": generate_skiplist_initializer(skiplist),
186 "types": generate_types_initializer(typelist),
191 def emit_header(output, template_filename, annotations_filename):
192 """Generate the C++ header from the template and write it out."""
194 annotations = read_annotations(annotations_filename)
195 template = read_template(template_filename)
196 generated_header = generate_header(template, annotations)
198 try:
199 output.write(generated_header)
200 except IOError as ex:
201 print("Error while writing out the generated file:\n" + str(ex) + "\n")
202 sys.exit(1)
205 ###############################################################################
206 # Java code generation #
207 ###############################################################################
210 def generate_java_array_initializer(contents):
211 """Generates the initializer for an array of strings.
212 Effectively turns `["a", "b"]` into ' \"a\",\n \"b\"\n'."""
214 initializer = ""
216 for name in contents:
217 initializer += ' "' + name + '",\n'
219 return initializer.strip(",\n")
222 def generate_class(template, annotations):
223 """Fill the class template from the list of annotations."""
225 allowedlist = extract_crash_ping_allowedlist(annotations)
227 return template_header + string.Template(template).substitute(
229 "allowedlist": generate_java_array_initializer(allowedlist),
234 def emit_class(output, annotations_filename):
235 """Generate the CrashReporterConstants.java file."""
237 template = textwrap.dedent(
238 """\
239 package org.mozilla.gecko;
242 * Constants used by the crash reporter. These are generated so that they
243 * are kept in sync with the other C++ and JS users.
245 public class CrashReporterConstants {
246 public static final String[] ANNOTATION_ALLOWEDLIST = {
247 ${allowedlist}
249 }"""
252 annotations = read_annotations(annotations_filename)
253 generated_class = generate_class(template, annotations)
255 try:
256 output.write(generated_class)
257 except IOError as ex:
258 print("Error while writing out the generated file:\n" + str(ex) + "\n")
259 sys.exit(1)