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
3 # found in the LICENSE file.
5 """Updates EnterprisePolicies enum in histograms.xml file with policy
6 definitions read from policy_templates.json.
8 If the file was pretty-printed, the updated version is pretty-printed too.
14 from ast
import literal_eval
15 from optparse
import OptionParser
16 from xml
.dom
import minidom
18 from diffutil
import PromptUserToAcceptDiff
19 from pretty_print
import PrettyPrintNode
21 HISTOGRAMS_PATH
= 'histograms.xml'
22 POLICY_TEMPLATES_PATH
= '../../../chrome/app/policy/policy_templates.json'
23 ENUM_NAME
= 'EnterprisePolicies'
25 class UserError(Exception):
26 def __init__(self
, message
):
27 Exception.__init
__(self
, message
)
34 def FlattenPolicies(policy_definitions
, policy_list
):
35 """Appends a list of policies defined in |policy_definitions| to
36 |policy_list|, flattening subgroups.
39 policy_definitions: A list of policy definitions and groups, as in
40 policy_templates.json file.
41 policy_list: A list that has policy definitions appended to it.
43 for policy
in policy_definitions
:
44 if policy
['type'] == 'group':
45 FlattenPolicies(policy
['policies'], policy_list
)
47 policy_list
.append(policy
)
50 def ParsePlaceholders(text
):
51 """Parse placeholders in |text|, making it more human-readable. The format of
52 |text| is exactly the same as in captions in policy_templates.json: it can
53 contain XML tags (ph, ex) and $1-like substitutions. Note that this function
54 does only a very simple parsing that is not fully correct, but should be
55 enough for all practical situations.
58 text: A string containing placeholders.
61 |text| with placeholders removed or replaced by readable text.
63 text
= re
.sub(r
'\$\d+', '', text
) # Remove $1-like substitutions.
64 text
= re
.sub(r
'<[^>]+>', '', text
) # Remove XML tags.
68 def UpdateHistogramDefinitions(policy_templates
, doc
):
69 """Sets the children of <enum name="EnterprisePolicies" ...> node in |doc| to
70 values generated from policy ids contained in |policy_templates|.
73 policy_templates: A list of dictionaries, defining policies or policy
74 groups. The format is exactly the same as in
75 policy_templates.json file.
76 doc: A minidom.Document object representing parsed histogram definitions
79 # Find EnterprisePolicies enum.
80 for enum_node
in doc
.getElementsByTagName('enum'):
81 if enum_node
.attributes
['name'].value
== ENUM_NAME
:
82 policy_enum_node
= enum_node
85 raise UserError('No policy enum node found')
87 # Remove existing values.
88 while policy_enum_node
.hasChildNodes():
89 policy_enum_node
.removeChild(policy_enum_node
.lastChild
)
91 # Add a "Generated from (...)" comment
92 comment
= ' Generated from {0} '.format(POLICY_TEMPLATES_PATH
)
93 policy_enum_node
.appendChild(doc
.createComment(comment
))
95 # Add values generated from policy templates.
97 FlattenPolicies(policy_templates
['policy_definitions'], ordered_policies
)
98 ordered_policies
.sort(key
=lambda policy
: policy
['id'])
99 for policy
in ordered_policies
:
100 node
= doc
.createElement('int')
101 node
.attributes
['value'] = str(policy
['id'])
102 node
.attributes
['label'] = ParsePlaceholders(policy
['caption'])
103 policy_enum_node
.appendChild(node
)
107 if len(sys
.argv
) > 1:
108 print >>sys
.stderr
, 'No arguments expected!'
109 sys
.stderr
.write(__doc__
)
112 with
open(POLICY_TEMPLATES_PATH
, 'rb') as f
:
113 policy_templates
= literal_eval(f
.read())
114 with
open(HISTOGRAMS_PATH
, 'rb') as f
:
115 histograms_doc
= minidom
.parse(f
)
119 UpdateHistogramDefinitions(policy_templates
, histograms_doc
)
121 new_xml
= PrettyPrintNode(histograms_doc
)
122 if PromptUserToAcceptDiff(xml
, new_xml
, 'Is the updated version acceptable?'):
123 with
open(HISTOGRAMS_PATH
, 'wb') as f
:
127 if __name__
== '__main__':
130 except UserError
as e
:
131 print >>sys
.stderr
, e
.message