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 _SUMMARY_TYPE = models.TextNodeType('summary') |
| 18 |
| 19 _PARAMETERS_TYPE = models.ObjectNodeType('parameters', |
| 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 _RAPPOR_PARAMETERS_TYPE = models.ObjectNodeType('rappor-parameters', |
| 36 extra_newlines=(1, 1, 1), |
| 37 string_attributes=['name'], |
| 38 children=[ |
| 39 models.ChildType('summary', _SUMMARY_TYPE, False), |
| 40 models.ChildType('parameters', _PARAMETERS_TYPE, False), |
| 41 ]) |
| 42 |
| 43 _RAPPOR_PARAMETERS_TYPES_TYPE = models.ObjectNodeType('rappor-parameter-types', |
| 44 extra_newlines=(1, 1, 1), |
| 45 dont_indent=True, |
| 46 children=[ |
| 47 models.ChildType('types', _RAPPOR_PARAMETERS_TYPE, True), |
| 48 ]) |
| 49 |
| 50 _OWNER_TYPE = models.TextNodeType('owner', single_line=True) |
| 51 |
| 52 _RAPPOR_METRIC_TYPE = models.ObjectNodeType('rappor-metric', |
| 53 extra_newlines=(1, 1, 1), |
| 54 string_attributes=['name', 'type'], |
| 55 children=[ |
| 56 models.ChildType('owners', _OWNER_TYPE, True), |
| 57 models.ChildType('summary', _SUMMARY_TYPE, False), |
| 58 ]) |
| 59 |
| 60 _RAPPOR_METRICS_TYPE = models.ObjectNodeType('rappor-metrics', |
| 61 extra_newlines=(1, 1, 1), |
| 62 dont_indent=True, |
| 63 children=[ |
| 64 models.ChildType('metrics', _RAPPOR_METRIC_TYPE, True), |
| 65 ]) |
| 66 |
| 67 _RAPPOR_CONFIGURATION_TYPE = models.ObjectNodeType('rappor-configuration', |
| 68 extra_newlines=(1, 1, 1), |
| 69 dont_indent=True, |
| 70 children=[ |
| 71 models.ChildType('parameterTypes', _RAPPOR_PARAMETERS_TYPES_TYPE, False), |
| 72 models.ChildType('metrics', _RAPPOR_METRICS_TYPE, False), |
| 73 ]) |
| 74 |
| 75 RAPPOR_XML_TYPE = models.DocumentType(_RAPPOR_CONFIGURATION_TYPE) |
| 76 |
| 77 |
| 78 def GetTypeNames(config): |
| 79 return set(p['name'] for p in config['parameterTypes']['types']) |
| 80 |
| 81 |
| 82 def HasMissingOwners(metrics): |
| 83 """Check that all of the metrics have owners. |
| 84 |
| 85 Args: |
| 86 metrics: A list of rappor metric description objects. |
| 87 |
| 88 Returns: |
| 89 True iff some metrics are missing owners. |
| 90 """ |
| 91 missing_owners = [m for m in metrics if not m['owners']] |
| 92 for metric in missing_owners: |
| 93 logging.error('Rappor metric "%s" is missing an owner.', metric['name']) |
| 94 print metric |
| 95 return bool(missing_owners) |
| 96 |
| 97 |
| 98 def HasInvalidTypes(type_names, metrics): |
| 99 """Check that all of the metrics have valid types. |
| 100 |
| 101 Args: |
| 102 type_names: The set of valid type names. |
| 103 metrics: A list of rappor metric description objects. |
| 104 |
| 105 Returns: |
| 106 True iff some metrics have invalid types. |
| 107 """ |
| 108 invalid_types = [m for m in metrics if m['type'] not in type_names] |
| 109 for metric in invalid_types: |
| 110 logging.error('Rappor metric "%s" has invalid type "%s"', |
| 111 metric['name'], metric['type']) |
| 112 return bool(invalid_types) |
| 113 |
| 114 |
| 115 def HasErrors(config): |
| 116 """Check that rappor.xml passes some basic validation checks. |
| 117 |
| 118 Args: |
| 119 config: The parsed rappor.xml contents. |
| 120 |
| 121 Returns: |
| 122 True iff there are validation errors. |
| 123 """ |
| 124 metrics = config['metrics']['metrics'] |
| 125 type_names = GetTypeNames(config) |
| 126 return (HasMissingOwners(metrics) or |
| 127 HasInvalidTypes(type_names, metrics)) |
| 128 |
| 129 |
| 130 def Cleanup(config): |
| 131 """Preform cleanup on description contents, such as sorting metrics. |
| 132 |
| 133 Args: |
| 134 config: The parsed rappor.xml contents. |
| 135 """ |
| 136 types = config['parameterTypes']['types'] |
| 137 types.sort(key=lambda x: x['name']) |
| 138 metrics = config['metrics']['metrics'] |
| 139 metrics.sort(key=lambda x: x['name']) |
| 140 |
| 141 |
| 142 def UpdateXML(original_xml): |
| 143 """Parse the original xml and return a pretty printed version. |
| 144 |
| 145 Args: |
| 146 original_xml: A string containing the original xml file contents. |
| 147 |
| 148 Returns: |
| 149 A Pretty printed xml string. |
| 150 """ |
| 151 comments, config = RAPPOR_XML_TYPE.Parse(original_xml) |
| 152 |
| 153 if HasErrors(config): |
| 154 return None |
| 155 |
| 156 Cleanup(config) |
| 157 |
| 158 return RAPPOR_XML_TYPE.PrettyPrint(comments, config) |
| 159 |
| 160 |
| 161 def main(argv): |
| 162 presubmit_util.DoPresubmitMain(argv, 'rappor.xml', 'rappor.old.xml', |
| 163 'pretty_print.py', UpdateXML) |
| 164 |
| 165 |
| 166 if '__main__' == __name__: |
| 167 sys.exit(main(sys.argv)) |
OLD | NEW |