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. 4 5 """Updates MappedEditingCommands enum in histograms.xml file with values read 6 from EditorCommand.cpp. 7 8 If the file was pretty-printed, the updated version is pretty-printed too. 9 """ 10 11 import logging 12 import os 13 import re 14 import sys 15 16 from xml.dom import minidom 17 18 from diffutil import PromptUserToAcceptDiff 19 import print_style 20 21 # Import the metrics/common module. 22 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) 23 from diff_util import PromptUserToAcceptDiff 24 25 HISTOGRAMS_PATH = 'histograms.xml' 26 ENUM_NAME = 'MappedEditingCommands' 27 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 = "^ };" 32 33 34 class UserError(Exception): 35 def __init__(self, message): 36 Exception.__init__(self, message) 37 38 @property 39 def message(self): 40 return self.args[0] 41 42 43 def ReadHistogramValues(filename): 44 """Returns a list of pairs (label, value) corresponding to HistogramValue. 45 46 Reads the EditorCommand.cpp file, locates the 47 HistogramValue enum definition and returns a pair for each entry. 48 """ 49 50 # Read the file as a list of lines 51 with open(filename) as f: 52 content = f.readlines() 53 54 # Locate the enum definition and collect all entries in it 55 inside_enum = False # We haven't found the enum definition yet 56 result = [] 57 for line in content: 58 if inside_enum: 59 # Exit condition: we reached last enum value 60 if re.match(ENUM_END_MARKER, line): 61 inside_enum = False 62 else: 63 # Inside enum: generate new xml entry 64 m = re.match("^{ \"([\w]+)\", \{([\w]+)", line.strip()) 65 if m: 66 result.append((m.group(1), int(m.group(2)))) 67 else: 68 if re.match(ENUM_START_MARKER, line): 69 inside_enum = True 70 enum_value = 0 # Start at 'UNKNOWN' 71 return sorted(result, key=lambda pair: pair[1]) 72 73 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 77 |policy_templates|. 78 79 Args: 80 histogram_values: A list of pairs (label, value) defining each extension 81 function 82 document: A minidom.Document object representing parsed histogram 83 definitions XML file. 84 85 """ 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 90 break 91 else: 92 raise UserError('No policy enum node found') 93 94 # Remove existing values. 95 while extension_functions_enum_node.hasChildNodes(): 96 extension_functions_enum_node.removeChild( 97 extension_functions_enum_node.lastChild) 98 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)) 103 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) 110 111 def Log(message): 112 logging.info(message) 113 114 def main(): 115 if len(sys.argv) > 1: 116 print >>sys.stderr, 'No arguments expected!' 117 sys.stderr.write(__doc__) 118 sys.exit(1) 119 120 Log('Reading histogram enum definition from "%s".' 121 % (EXTENSION_FUNCTIONS_HISTOGRAM_VALUE_PATH)) 122 histogram_values = ReadHistogramValues( 123 EXTENSION_FUNCTIONS_HISTOGRAM_VALUE_PATH) 124 125 Log('Reading existing histograms from "%s".' % (HISTOGRAMS_PATH)) 126 with open(HISTOGRAMS_PATH, 'rb') as f: 127 histograms_doc = minidom.parse(f) 128 f.seek(0) 129 xml = f.read() 130 131 Log('Comparing histograms enum with new enum definition.') 132 UpdateHistogramDefinitions(histogram_values, histograms_doc) 133 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: 138 f.write(new_xml) 139 140 Log('Done.') 141 142 143 if __name__ == '__main__': 144 main() 145