OLD | NEW |
---|---|
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Extract histogram names from the description XML file. | 5 """Extract histogram names from the description XML file. |
6 | 6 |
7 For more information on the format of the XML file, which is self-documenting, | 7 For more information on the format of the XML file, which is self-documenting, |
8 see histograms.xml; however, here is a simple example to get you started. The | 8 see histograms.xml; however, here is a simple example to get you started. The |
9 XML below will generate the following five histograms: | 9 XML below will generate the following five histograms: |
10 | 10 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 | 56 |
57 import copy | 57 import copy |
58 import logging | 58 import logging |
59 import xml.dom.minidom | 59 import xml.dom.minidom |
60 | 60 |
61 OWNER_FIELD_PLACEHOLDER = ( | 61 OWNER_FIELD_PLACEHOLDER = ( |
62 'Please list the metric\'s owners. Add more owner tags as needed.') | 62 'Please list the metric\'s owners. Add more owner tags as needed.') |
63 | 63 |
64 MAX_HISTOGRAM_SUFFIX_DEPENDENCY_DEPTH = 5 | 64 MAX_HISTOGRAM_SUFFIX_DEPENDENCY_DEPTH = 5 |
65 | 65 |
66 DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON = ( | |
67 'Base histogram. Use suffixes of this histogram instead.') | |
68 | |
66 | 69 |
67 class Error(Exception): | 70 class Error(Exception): |
68 pass | 71 pass |
69 | 72 |
70 | 73 |
71 def _JoinChildNodes(tag): | 74 def _JoinChildNodes(tag): |
72 """Join child nodes into a single text. | 75 """Join child nodes into a single text. |
73 | 76 |
74 Applicable to leafs like 'summary' and 'detail'. | 77 Applicable to leafs like 'summary' and 'detail'. |
75 | 78 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
223 def _ExtractOwners(xml_node): | 226 def _ExtractOwners(xml_node): |
224 """Extract all owners into a list from owner tag under |xml_node|.""" | 227 """Extract all owners into a list from owner tag under |xml_node|.""" |
225 owners = [] | 228 owners = [] |
226 for owner_node in xml_node.getElementsByTagName('owner'): | 229 for owner_node in xml_node.getElementsByTagName('owner'): |
227 owner_entry = _NormalizeString(_JoinChildNodes(owner_node)) | 230 owner_entry = _NormalizeString(_JoinChildNodes(owner_node)) |
228 if OWNER_FIELD_PLACEHOLDER not in owner_entry: | 231 if OWNER_FIELD_PLACEHOLDER not in owner_entry: |
229 owners.append(owner_entry) | 232 owners.append(owner_entry) |
230 return owners | 233 return owners |
231 | 234 |
232 | 235 |
236 def _ProcessBaseHistogramAttribute(node, histogram_entry): | |
237 if node.hasAttribute('base'): | |
238 is_base = node.getAttribute('base').lower() == 'true' | |
239 histogram_entry['base'] = is_base | |
240 if is_base and 'obsolete' not in histogram_entry: | |
241 histogram_entry['obsolete'] = DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON | |
242 | |
243 | |
233 def _ExtractHistogramsFromXmlTree(tree, enums): | 244 def _ExtractHistogramsFromXmlTree(tree, enums): |
234 """Extract all <histogram> nodes in the tree into a dictionary.""" | 245 """Extract all <histogram> nodes in the tree into a dictionary.""" |
235 | 246 |
236 # Process the histograms. The descriptions can include HTML tags. | 247 # Process the histograms. The descriptions can include HTML tags. |
237 histograms = {} | 248 histograms = {} |
238 have_errors = False | 249 have_errors = False |
239 last_name = None | 250 last_name = None |
240 for histogram in tree.getElementsByTagName('histogram'): | 251 for histogram in tree.getElementsByTagName('histogram'): |
241 name = histogram.getAttribute('name') | 252 name = histogram.getAttribute('name') |
242 if last_name is not None and name.lower() < last_name.lower(): | 253 if last_name is not None and name.lower() < last_name.lower(): |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
281 | 292 |
282 # Handle enum types. | 293 # Handle enum types. |
283 if histogram.hasAttribute('enum'): | 294 if histogram.hasAttribute('enum'): |
284 enum_name = histogram.getAttribute('enum') | 295 enum_name = histogram.getAttribute('enum') |
285 if enum_name not in enums: | 296 if enum_name not in enums: |
286 logging.error('Unknown enum %s in histogram %s', enum_name, name) | 297 logging.error('Unknown enum %s in histogram %s', enum_name, name) |
287 have_errors = True | 298 have_errors = True |
288 else: | 299 else: |
289 histogram_entry['enum'] = enums[enum_name] | 300 histogram_entry['enum'] = enums[enum_name] |
290 | 301 |
302 _ProcessBaseHistogramAttribute(histogram, histogram_entry) | |
303 | |
291 return histograms, have_errors | 304 return histograms, have_errors |
292 | 305 |
293 | 306 |
294 # Finds an <obsolete> node amongst |node|'s immediate children and returns its | 307 # Finds an <obsolete> node amongst |node|'s immediate children and returns its |
295 # content as a string. Returns None if no such node exists. | 308 # content as a string. Returns None if no such node exists. |
296 def _GetObsoleteReason(node): | 309 def _GetObsoleteReason(node): |
297 for child in node.childNodes: | 310 for child in node.childNodes: |
298 if child.localName == 'obsolete': | 311 if child.localName == 'obsolete': |
299 # There can be at most 1 obsolete element per node. | 312 # There can be at most 1 obsolete element per node. |
300 return _JoinChildNodes(child) | 313 return _JoinChildNodes(child) |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
391 if with_suffixes: | 404 if with_suffixes: |
392 suffixes_to_add = with_suffixes | 405 suffixes_to_add = with_suffixes |
393 else: | 406 else: |
394 suffixes_to_add = suffix_nodes | 407 suffixes_to_add = suffix_nodes |
395 for suffix in suffixes_to_add: | 408 for suffix in suffixes_to_add: |
396 suffix_name = suffix.getAttribute('name') | 409 suffix_name = suffix.getAttribute('name') |
397 try: | 410 try: |
398 new_histogram_name = _ExpandHistogramNameWithSuffixes( | 411 new_histogram_name = _ExpandHistogramNameWithSuffixes( |
399 suffix_name, histogram_name, histogram_suffixes) | 412 suffix_name, histogram_name, histogram_suffixes) |
400 if new_histogram_name != histogram_name: | 413 if new_histogram_name != histogram_name: |
401 histograms[new_histogram_name] = copy.deepcopy( | 414 new_histogram = copy.deepcopy(histograms[histogram_name]) |
402 histograms[histogram_name]) | 415 # Do not copy forward base histogram state to suffixed |
416 # histograms. Any suffixed histograms that wish to remain base | |
417 # histogram must explicitly declare themselves as base histograms. | |
Ilya Sherman
2016/10/18 21:05:58
nit: s/histogram/histograms
Bryan McQuade
2016/10/18 23:15:19
done, thanks!
| |
418 if new_histogram.get('base', False): | |
419 del new_histogram['base'] | |
420 if (new_histogram.get('obsolete', '') == | |
421 DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON): | |
422 del new_histogram['obsolete'] | |
423 histograms[new_histogram_name] = new_histogram | |
403 | 424 |
404 suffix_label = suffix_labels.get(suffix_name, '') | 425 suffix_label = suffix_labels.get(suffix_name, '') |
405 | 426 |
406 # TODO(yiyaoliu): Rename these to be consistent with the new naming. | 427 # TODO(yiyaoliu): Rename these to be consistent with the new naming. |
407 # It is kept unchanged for now to be it's used by dashboards. | 428 # It is kept unchanged for now to be it's used by dashboards. |
408 if 'fieldtrial_groups' not in histograms[new_histogram_name]: | 429 if 'fieldtrial_groups' not in histograms[new_histogram_name]: |
409 histograms[new_histogram_name]['fieldtrial_groups'] = [] | 430 histograms[new_histogram_name]['fieldtrial_groups'] = [] |
410 histograms[new_histogram_name]['fieldtrial_groups'].append( | 431 histograms[new_histogram_name]['fieldtrial_groups'].append( |
411 suffix_name) | 432 suffix_name) |
412 | 433 |
(...skipping 16 matching lines...) Expand all Loading... | |
429 # group itself was obsolete as well. | 450 # group itself was obsolete as well. |
430 obsolete_reason = _GetObsoleteReason(suffix) | 451 obsolete_reason = _GetObsoleteReason(suffix) |
431 if not obsolete_reason: | 452 if not obsolete_reason: |
432 obsolete_reason = group_obsolete_reason | 453 obsolete_reason = group_obsolete_reason |
433 | 454 |
434 # If the suffix has an obsolete tag, all histograms it generates | 455 # If the suffix has an obsolete tag, all histograms it generates |
435 # inherit it. | 456 # inherit it. |
436 if obsolete_reason: | 457 if obsolete_reason: |
437 histograms[new_histogram_name]['obsolete'] = obsolete_reason | 458 histograms[new_histogram_name]['obsolete'] = obsolete_reason |
438 | 459 |
460 _ProcessBaseHistogramAttribute(suffix, histograms[new_histogram_name]) | |
461 | |
439 except Error: | 462 except Error: |
440 have_errors = True | 463 have_errors = True |
441 | 464 |
442 return have_errors | 465 return have_errors |
443 | 466 |
444 | 467 |
445 def ExtractHistogramsFromFile(file_handle): | 468 def ExtractHistogramsFromFile(file_handle): |
446 """Compute the histogram names and descriptions from the XML representation. | 469 """Compute the histogram names and descriptions from the XML representation. |
447 | 470 |
448 Args: | 471 Args: |
(...skipping 29 matching lines...) Expand all Loading... | |
478 with open(filename, 'r') as f: | 501 with open(filename, 'r') as f: |
479 histograms, had_errors = ExtractHistogramsFromFile(f) | 502 histograms, had_errors = ExtractHistogramsFromFile(f) |
480 if had_errors: | 503 if had_errors: |
481 logging.error('Error parsing %s', filename) | 504 logging.error('Error parsing %s', filename) |
482 raise Error() | 505 raise Error() |
483 return histograms | 506 return histograms |
484 | 507 |
485 | 508 |
486 def ExtractNames(histograms): | 509 def ExtractNames(histograms): |
487 return sorted(histograms.keys()) | 510 return sorted(histograms.keys()) |
OLD | NEW |