OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 import logging | |
7 import sys | |
8 import os | |
9 | |
10 # Import the metrics/common module for pretty print xml. | |
11 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) | |
12 import models | |
13 import presubmit_util | |
14 | |
15 | |
16 # Model definitions for rappor.xml content | |
17 summaryType = models.TextNodeType('summary') | |
18 | |
19 parametersType = models.ObjectNodeType('parameters', | |
Alexei Svitkine (slow)
2015/02/13 14:36:37
Nit: camelCase isn't a thing in Python style...
I
Steven Holte
2015/02/14 01:11:18
Done.
| |
20 int_attributes=[ | |
21 'num-cohorts', | |
22 'bytes', | |
23 'hash-functions', | |
24 ], | |
25 float_attributes=[ | |
26 'fake-prob', | |
27 'fake-one-prob', | |
28 'one-coin-prob', | |
29 'zero-coin-prob', | |
30 ], | |
31 string_attributes=[ | |
32 'reporting-level' | |
33 ]) | |
34 | |
35 rapporParametersType = models.ObjectNodeType('rappor-parameters', | |
36 extra_newlines=(1, 1, 1), | |
37 string_attributes=['name'], | |
38 children=[ | |
39 models.ChildType('summary', summaryType, False), | |
40 models.ChildType('parameters', parametersType, False), | |
41 ]) | |
42 | |
43 rapporParameterTypesType = models.ObjectNodeType('rappor-parameter-types', | |
44 extra_newlines=(1, 1, 1), | |
45 dont_indent=True, | |
46 children=[ | |
47 models.ChildType('types', rapporParametersType, True), | |
48 ]) | |
49 | |
50 ownerType = models.TextNodeType('owner', single_line=True) | |
51 | |
52 rapporMetricType = models.ObjectNodeType('rappor-metric', | |
53 extra_newlines=(1, 1, 1), | |
54 string_attributes=['name', 'type'], | |
55 children=[ | |
56 models.ChildType('owners', ownerType, True), | |
57 models.ChildType('summary', summaryType, False), | |
58 ]) | |
59 | |
60 rapporMetricsType = models.ObjectNodeType('rappor-metrics', | |
61 extra_newlines=(1, 1, 1), | |
62 dont_indent=True, | |
63 children=[ | |
64 models.ChildType('metrics', rapporMetricType, True), | |
65 ]) | |
66 | |
67 rapporConfigurationType = models.ObjectNodeType('rappor-configuration', | |
68 dont_indent=True, | |
69 children=[ | |
70 models.ChildType('parameterTypes', rapporParameterTypesType, False), | |
71 models.ChildType('metrics', rapporMetricsType, False), | |
72 ]) | |
73 | |
74 rapporXmlType = models.DocumentType(rapporConfigurationType) | |
75 | |
76 | |
77 def HasMissingOwners(metrics): | |
Alexei Svitkine (slow)
2015/02/13 14:36:37
Can you add some tests?
Steven Holte
2015/02/14 01:11:18
Done.
| |
78 """Check that all of the metrics have owners. | |
79 | |
80 Args: | |
81 metrics: A list of rappor metric description objects. | |
82 | |
83 Returns: | |
84 True iff some metrics are missing owners. | |
85 """ | |
86 missing_owners = [m for m in metrics if not m['owners']] | |
87 for metric in missing_owners: | |
88 logging.error('Rappor metric "%s" is missing an owner.', metric['name']) | |
89 print metric | |
90 return bool(missing_owners) | |
91 | |
92 | |
93 def HasInvalidTypes(type_names, metrics): | |
94 """Check that all of the metrics have valid types. | |
95 | |
96 Args: | |
97 type_names: The set of valid type names. | |
98 metrics: A list of rappor metric description objects. | |
99 | |
100 Returns: | |
101 True iff some metrics have invalid types. | |
102 """ | |
103 invalid_types = [m for m in metrics if m['type'] not in type_names] | |
104 for metric in invalid_types: | |
105 logging.error('Rappor metric "%s" has invalid type "%s"', | |
106 metric['name'], metric['type']) | |
107 return bool(invalid_types) | |
108 | |
109 | |
110 def HasErrors(obj): | |
111 """Check that rappor.xml passes some basic validation checks. | |
112 | |
113 Args: | |
114 obj: The parsed rappor.xml contents. | |
115 | |
116 Returns: | |
117 True iff there are validation errors. | |
118 """ | |
119 metrics = obj['metrics']['metrics'] | |
120 type_names = set(p['name'] for p in obj['parameterTypes']['types']) | |
121 return (HasMissingOwners(metrics) or | |
122 HasInvalidTypes(type_names, metrics)) | |
123 | |
124 | |
125 def Cleanup(obj): | |
126 """Preform cleanup on description contents, such as sorting metrics. | |
127 | |
128 Args: | |
129 obj: The parsed rappor.xml contents. | |
130 """ | |
131 types = obj['parameterTypes']['types'] | |
132 types.sort(key=lambda x: x['name']) | |
133 metrics = obj['metrics']['metrics'] | |
134 metrics.sort(key=lambda x: x['name']) | |
135 | |
136 | |
137 def UpdateXml(original_xml): | |
138 """Parse the original xml and return a pretty printed version. | |
139 | |
140 Args: | |
141 original_xml: A string containing the original xml file contents. | |
142 | |
143 Returns: | |
144 A Pretty printed xml string. | |
145 """ | |
146 comments, obj = rapporXmlType.Parse(original_xml) | |
147 | |
148 if HasErrors(obj): | |
149 return None | |
150 | |
151 Cleanup(obj) | |
152 | |
153 return rapporXmlType.PrettyPrint(comments, obj) | |
154 | |
155 | |
156 def main(argv): | |
157 presubmit_util.DoPresubmitMain(argv, 'rappor.xml', 'rappor.old.xml', | |
158 'pretty_print.py', UpdateXml) | |
159 | |
160 | |
161 if '__main__' == __name__: | |
162 sys.exit(main(sys.argv)) | |
OLD | NEW |