1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Updates MappedEditingCommands enum in histograms.xml file with values read
6 from EditorCommand.cpp.
8 If the file was pretty-printed, the updated version is pretty-printed too.
16 from xml
.dom
import minidom
18 from diffutil
import PromptUserToAcceptDiff
21 # Import the metrics/common module.
22 sys
.path
.append(os
.path
.join(os
.path
.dirname(__file__
), '..', 'common'))
23 from diff_util
import PromptUserToAcceptDiff
25 HISTOGRAMS_PATH
= 'histograms.xml'
26 ENUM_NAME
= 'MappedEditingCommands'
28 EXTENSION_FUNCTIONS_HISTOGRAM_VALUE_PATH
= \
29 '../../../third_party/WebKit/Source/core/editing/EditorCommand.cpp'
30 ENUM_START_MARKER
= "^ static const CommandEntry commands\[\] = {"
31 ENUM_END_MARKER
= "^ };"
34 class UserError(Exception):
35 def __init__(self
, message
):
36 Exception.__init
__(self
, message
)
43 def ReadHistogramValues(filename
):
44 """Returns a list of pairs (label, value) corresponding to HistogramValue.
46 Reads the EditorCommand.cpp file, locates the
47 HistogramValue enum definition and returns a pair for each entry.
50 # Read the file as a list of lines
51 with
open(filename
) as f
:
52 content
= f
.readlines()
54 # Locate the enum definition and collect all entries in it
55 inside_enum
= False # We haven't found the enum definition yet
59 # Exit condition: we reached last enum value
60 if re
.match(ENUM_END_MARKER
, line
):
63 # Inside enum: generate new xml entry
64 m
= re
.match("^{ \"([\w]+)\", \{([\w]+)", line
.strip())
66 result
.append((m
.group(1), int(m
.group(2))))
68 if re
.match(ENUM_START_MARKER
, line
):
70 enum_value
= 0 # Start at 'UNKNOWN'
71 return sorted(result
, key
=lambda pair
: pair
[1])
74 def UpdateHistogramDefinitions(histogram_values
, document
):
75 """Sets the children of <enum name="ExtensionFunctions" ...> node in
76 |document| to values generated from policy ids contained in
80 histogram_values: A list of pairs (label, value) defining each extension
82 document: A minidom.Document object representing parsed histogram
86 # Find ExtensionFunctions enum.
87 for enum_node
in document
.getElementsByTagName('enum'):
88 if enum_node
.attributes
['name'].value
== ENUM_NAME
:
89 extension_functions_enum_node
= enum_node
92 raise UserError('No policy enum node found')
94 # Remove existing values.
95 while extension_functions_enum_node
.hasChildNodes():
96 extension_functions_enum_node
.removeChild(
97 extension_functions_enum_node
.lastChild
)
99 # Add a "Generated from (...)" comment
100 comment
= ' Generated from {0} '.format(
101 EXTENSION_FUNCTIONS_HISTOGRAM_VALUE_PATH
)
102 extension_functions_enum_node
.appendChild(document
.createComment(comment
))
104 # Add values generated from policy templates.
105 for (label
, value
) in histogram_values
:
106 node
= document
.createElement('int')
107 node
.attributes
['value'] = str(value
)
108 node
.attributes
['label'] = label
109 extension_functions_enum_node
.appendChild(node
)
112 logging
.info(message
)
115 if len(sys
.argv
) > 1:
116 print >>sys
.stderr
, 'No arguments expected!'
117 sys
.stderr
.write(__doc__
)
120 Log('Reading histogram enum definition from "%s".'
121 % (EXTENSION_FUNCTIONS_HISTOGRAM_VALUE_PATH
))
122 histogram_values
= ReadHistogramValues(
123 EXTENSION_FUNCTIONS_HISTOGRAM_VALUE_PATH
)
125 Log('Reading existing histograms from "%s".' % (HISTOGRAMS_PATH
))
126 with
open(HISTOGRAMS_PATH
, 'rb') as f
:
127 histograms_doc
= minidom
.parse(f
)
131 Log('Comparing histograms enum with new enum definition.')
132 UpdateHistogramDefinitions(histogram_values
, histograms_doc
)
134 Log('Writing out new histograms file.')
135 new_xml
= print_style
.GetPrintStyle().PrettyPrintNode(histograms_doc
)
136 if PromptUserToAcceptDiff(xml
, new_xml
, 'Is the updated version acceptable?'):
137 with
open(HISTOGRAMS_PATH
, 'wb') as f
:
143 if __name__
== '__main__':