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/.
11 ###############################################################################
12 # Language-agnostic functionality #
13 ###############################################################################
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")
28 if "type" not in data
:
29 print("Annotation " + name
+ " does not have a type\n")
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
):
38 + " has an unknown type: "
45 def read_annotations(annotations_filename
):
46 """Read the annotations from a YAML file.
47 If an error is encountered quit the program."""
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")
56 validate_annotations(annotations
)
61 def read_template(template_filename
):
62 """Read the contents of the template.
63 If an error is encountered quit the program."""
66 with
open(template_filename
, "r") as template_file
:
67 template
= template_file
.read()
69 print("Error when reading " + template_filename
+ ":\n" + str(ex
) + "\n")
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."""
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."""
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":
100 elif annotation_type
== "boolean":
102 elif annotation_type
== "u32":
104 elif annotation_type
== "u64":
106 elif annotation_type
== "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."""
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
138 for i
, (name
, _
) in enumerate(sorted(annotations
.items())):
139 enum
+= " " + name
+ " = " + str(i
) + ",\n"
141 enum
+= " Count = " + str(len(annotations
))
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."""
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
)
199 output
.write(generated_header
)
200 except IOError as ex
:
201 print("Error while writing out the generated file:\n" + str(ex
) + "\n")
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'."""
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(
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 = {
252 annotations
= read_annotations(annotations_filename
)
253 generated_class
= generate_class(template
, annotations
)
256 output
.write(generated_class
)
257 except IOError as ex
:
258 print("Error while writing out the generated file:\n" + str(ex
) + "\n")