Revert of Remove OneClickSigninHelper since it is no longer used. (patchset #5 id...
[chromium-blink-merge.git] / tools / metrics / histograms / pretty_print.py
blob41cc2b6126cba9876d454dd66a56bbd0cbe107c8
1 #!/usr/bin/env python
2 # Copyright 2013 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.
6 """Pretty-prints the histograms.xml file, alphabetizing tags, wrapping text
7 at 80 chars, enforcing standard attribute ordering, and standardizing
8 indentation.
10 This is quite a bit more complicated than just calling tree.toprettyxml();
11 we need additional customization, like special attribute ordering in tags
12 and wrapping text nodes, so we implement our own full custom XML pretty-printer.
13 """
15 from __future__ import with_statement
17 import logging
18 import os
19 import shutil
20 import sys
21 import xml.dom.minidom
23 import print_style
25 sys.path.insert(1, os.path.join(sys.path[0], '..', '..', 'python'))
26 from google import path_utils
28 # Import the metrics/common module.
29 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common'))
30 import diff_util
31 import presubmit_util
33 # Tags whose children we want to alphabetize. The key is the parent tag name,
34 # and the value is a pair of the tag name of the children we want to sort,
35 # and a key function that maps each child node to the desired sort key.
36 ALPHABETIZATION_RULES = {
37 'histograms': ('histogram', lambda n: n.attributes['name'].value.lower()),
38 'enums': ('enum', lambda n: n.attributes['name'].value.lower()),
39 'enum': ('int', lambda n: int(n.attributes['value'].value)),
40 'histogram_suffixes_list': (
41 'histogram_suffixes', lambda n: n.attributes['name'].value.lower()),
42 'histogram_suffixes': ('affected-histogram',
43 lambda n: n.attributes['name'].value.lower()),
47 class Error(Exception):
48 pass
51 def unsafeAppendChild(parent, child):
52 """Append child to parent's list of children, ignoring the possibility that it
53 is already in another node's childNodes list. Requires that the previous
54 parent of child is discarded (to avoid non-tree DOM graphs).
55 This can provide a significant speedup as O(n^2) operations are removed (in
56 particular, each child insertion avoids the need to traverse the old parent's
57 entire list of children)."""
58 child.parentNode = None
59 parent.appendChild(child)
60 child.parentNode = parent
63 def TransformByAlphabetizing(node):
64 """Transform the given XML by alphabetizing specific node types according to
65 the rules in ALPHABETIZATION_RULES.
67 Args:
68 node: The minidom node to transform.
70 Returns:
71 The minidom node, with children appropriately alphabetized. Note that the
72 transformation is done in-place, i.e. the original minidom tree is modified
73 directly.
74 """
75 if node.nodeType != xml.dom.minidom.Node.ELEMENT_NODE:
76 for c in node.childNodes: TransformByAlphabetizing(c)
77 return node
79 # Element node with a tag name that we alphabetize the children of?
80 if node.tagName in ALPHABETIZATION_RULES:
81 # Put subnodes in a list of node,key pairs to allow for custom sorting.
82 subtag, key_function = ALPHABETIZATION_RULES[node.tagName]
83 subnodes = []
84 sort_key = -1
85 pending_node_indices = []
86 for c in node.childNodes:
87 if (c.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and
88 c.tagName == subtag):
89 sort_key = key_function(c)
90 # Replace sort keys for delayed nodes.
91 for idx in pending_node_indices:
92 subnodes[idx][1] = sort_key
93 pending_node_indices = []
94 else:
95 # Subnodes that we don't want to rearrange use the next node's key,
96 # so they stay in the same relative position.
97 # Therefore we delay setting key until the next node is found.
98 pending_node_indices.append(len(subnodes))
100 subnodes.append( [c, sort_key] )
102 # Use last sort key for trailing unknown nodes.
103 for idx in pending_node_indices:
104 subnodes[idx][1] = sort_key
106 # Sort the subnode list.
107 subnodes.sort(key=lambda pair: pair[1])
109 # Re-add the subnodes, transforming each recursively.
110 while node.firstChild:
111 node.removeChild(node.firstChild)
112 for (c, _) in subnodes:
113 unsafeAppendChild(node, TransformByAlphabetizing(c))
114 return node
116 # Recursively handle other element nodes and other node types.
117 for c in node.childNodes: TransformByAlphabetizing(c)
118 return node
121 def PrettyPrint(raw_xml):
122 """Pretty-print the given XML.
124 Args:
125 raw_xml: The contents of the histograms XML file, as a string.
127 Returns:
128 The pretty-printed version.
130 tree = xml.dom.minidom.parseString(raw_xml)
131 tree = TransformByAlphabetizing(tree)
132 return print_style.GetPrintStyle().PrettyPrintNode(tree)
134 def main():
135 presubmit_util.DoPresubmitMain(sys.argv, 'histograms.xml',
136 'histograms.before.pretty-print.xml',
137 'pretty_print.py', PrettyPrint)
139 if __name__ == '__main__':
140 main()