Merge tag android-5.1.0_r1 into AOSP_5.1_MERGE
Change-Id: I1f84faa617cf30a8c259dc1790bd96300857f662
diff --git a/grit/format/policy_templates/policy_template_generator.py b/grit/format/policy_templates/policy_template_generator.py
index 11d097e..a1eb123 100644
--- a/grit/format/policy_templates/policy_template_generator.py
+++ b/grit/format/policy_templates/policy_template_generator.py
@@ -118,7 +118,7 @@
if policy['type'] == 'group':
self._ProcessPolicyList(policy['policies'])
- elif policy['type'] in ('string-enum', 'int-enum'):
+ elif policy['type'] in ('string-enum', 'int-enum', 'string-enum-list'):
# Iterate through all the items of an enum-type policy, and add captions.
for item in policy['items']:
item['caption'] = self._ImportMessage(item['caption'])
diff --git a/grit/format/policy_templates/policy_template_generator_unittest.py b/grit/format/policy_templates/policy_template_generator_unittest.py
index f06cc2d..adc4a22 100644
--- a/grit/format/policy_templates/policy_template_generator_unittest.py
+++ b/grit/format/policy_templates/policy_template_generator_unittest.py
@@ -262,6 +262,29 @@
self.tester.assertEquals(policy['items'][2]['caption'], 'string3')
self.do_test(policy_data_mock, LocalMockWriter())
+ def testStringEnumTexts(self):
+ # Test that GUI messages are assigned correctly to string-enums
+ # (aka dropdown menus).
+ policy_data_mock = {
+ 'policy_definitions': [{
+ 'name': 'Policy1',
+ 'type': 'string-enum-list',
+ 'caption': '', 'desc': '',
+ 'supported_on': [],
+ 'items': [
+ {'name': 'item1', 'value': 'one', 'caption': 'string1', 'desc': ''},
+ {'name': 'item2', 'value': 'two', 'caption': 'string2', 'desc': ''},
+ {'name': 'item3', 'value': 'three', 'caption': 'string3', 'desc': ''},
+ ]
+ }]
+ }
+ class LocalMockWriter(mock_writer.MockWriter):
+ def WritePolicy(self, policy):
+ self.tester.assertEquals(policy['items'][0]['caption'], 'string1')
+ self.tester.assertEquals(policy['items'][1]['caption'], 'string2')
+ self.tester.assertEquals(policy['items'][2]['caption'], 'string3')
+ self.do_test(policy_data_mock, LocalMockWriter())
+
def testPolicyFiltering(self):
# Test that policies are filtered correctly based on their annotations.
policy_data_mock = {
diff --git a/grit/format/policy_templates/writer_configuration.py b/grit/format/policy_templates/writer_configuration.py
index 00da0cc..88de6b5 100644
--- a/grit/format/policy_templates/writer_configuration.py
+++ b/grit/format/policy_templates/writer_configuration.py
@@ -33,6 +33,7 @@
'win_recommended_category_path': ['chromium_recommended'],
'admx_namespace': 'Chromium.Policies.Chromium',
'admx_prefix': 'chromium',
+ 'linux_policy_path': '/etc/chromium/policies/',
}
elif '_google_chrome' in defines:
config = {
@@ -47,6 +48,7 @@
'win_recommended_category_path': ['google', 'googlechrome_recommended'],
'admx_namespace': 'Google.Policies.Chrome',
'admx_prefix': 'chrome',
+ 'linux_policy_path': '/etc/opt/chrome/policies/',
}
else:
raise Exception('Unknown build')
diff --git a/grit/format/policy_templates/writers/adm_writer.py b/grit/format/policy_templates/writers/adm_writer.py
index 3103c3e..bffbeb5 100644
--- a/grit/format/policy_templates/writers/adm_writer.py
+++ b/grit/format/policy_templates/writers/adm_writer.py
@@ -71,6 +71,7 @@
'string-enum': 'DROPDOWNLIST',
'int-enum': 'DROPDOWNLIST',
'list': 'LISTBOX',
+ 'string-enum-list': 'LISTBOX',
'dict': 'EDITTEXT'
}
@@ -106,7 +107,7 @@
builder.AddLine()
adm_type = self.TYPE_TO_INPUT[policy['type']]
builder.AddLine('PART !!%s %s' % (policy_part_name, adm_type), 1)
- if policy['type'] == 'list':
+ if policy['type'] in ('list', 'string-enum-list'):
# Note that the following line causes FullArmor ADMX Migrator to create
# corrupt ADMX files. Please use admx_writer to get ADMX files.
builder.AddLine('KEYNAME "%s\\%s"' % (key_name, policy['name']))
@@ -152,9 +153,10 @@
builder.AddLine()
def WritePolicy(self, policy):
- self._WritePolicy(policy,
- self.config['win_reg_mandatory_key_name'],
- self.policies)
+ if self.CanBeMandatory(policy):
+ self._WritePolicy(policy,
+ self.config['win_reg_mandatory_key_name'],
+ self.policies)
def WriteRecommendedPolicy(self, policy):
self._WritePolicy(policy,
diff --git a/grit/format/policy_templates/writers/adm_writer_unittest.py b/grit/format/policy_templates/writers/adm_writer_unittest.py
index 49c31d8..82374bb 100644
--- a/grit/format/policy_templates/writers/adm_writer_unittest.py
+++ b/grit/format/policy_templates/writers/adm_writer_unittest.py
@@ -147,6 +147,70 @@
MainPolicy_Explain="Description of main."''')
self.CompareOutputs(output, expected_output)
+ def testMainPolicyRecommendedOnly(self):
+ # Tests a policy group with a single policy of type 'main'.
+ grd = self.PrepareTest('''
+ {
+ 'policy_definitions': [
+ {
+ 'name': 'MainPolicy',
+ 'type': 'main',
+ 'supported_on': ['chrome.win:8-'],
+ 'features': {
+ 'can_be_recommended': True,
+ 'can_be_mandatory': False
+ },
+ 'caption': 'Caption of main.',
+ 'desc': 'Description of main.',
+ },
+ ],
+ 'placeholders': [],
+ 'messages': {
+ 'win_supported_winxpsp2': {
+ 'text': 'At least Windows 3.12', 'desc': 'blah'
+ },
+ 'doc_recommended': {
+ 'text': 'Recommended', 'desc': 'bleh'
+ }
+ }
+ }''')
+ output = self.GetOutput(grd, 'fr', {'_google_chrome' : '1'}, 'adm', 'en')
+ expected_output = self.ConstructOutput(
+ ['MACHINE', 'USER'], '''
+ CATEGORY !!google
+ CATEGORY !!googlechrome
+ KEYNAME "Software\\Policies\\Google\\Chrome"
+
+ END CATEGORY
+ END CATEGORY
+
+ CATEGORY !!google
+ CATEGORY !!googlechrome_recommended
+ KEYNAME "Software\\Policies\\Google\\Chrome\\Recommended"
+
+ POLICY !!MainPolicy_Policy
+ #if version >= 4
+ SUPPORTED !!SUPPORTED_WINXPSP2
+ #endif
+ EXPLAIN !!MainPolicy_Explain
+ VALUENAME "MainPolicy"
+ VALUEON NUMERIC 1
+ VALUEOFF NUMERIC 0
+ END POLICY
+
+ END CATEGORY
+ END CATEGORY
+
+
+''', '''[Strings]
+SUPPORTED_WINXPSP2="At least Windows 3.12"
+google="Google"
+googlechrome="Google Chrome"
+googlechrome_recommended="Google Chrome - Recommended"
+MainPolicy_Policy="Caption of main."
+MainPolicy_Explain="Description of main."''')
+ self.CompareOutputs(output, expected_output)
+
def testStringPolicy(self):
# Tests a policy group with a single policy of type 'string'.
grd = self.PrepareTest('''
@@ -552,6 +616,86 @@
''')
self.CompareOutputs(output, expected_output)
+ def testStringEnumListPolicy(self):
+ # Tests a policy group with a single policy of type 'string-enum-list'.
+ grd = self.PrepareTest('''
+ {
+ 'policy_definitions': [
+ {
+ 'name': 'ListPolicy',
+ 'type': 'string-enum-list',
+ 'supported_on': ['chrome.win:8-'],
+ 'features': { 'can_be_recommended': True },
+ 'desc': """Description of list policy.
+With a newline.""",
+ 'items': [
+ {'name': 'ProxyServerDisabled', 'value': 'one',
+ 'caption': 'Option1'},
+ {'name': 'ProxyServerAutoDetect', 'value': 'two',
+ 'caption': 'Option2'},
+ ],
+ 'caption': 'Caption of list policy.',
+ 'label': 'Label of list policy.'
+ },
+ ],
+ 'placeholders': [],
+ 'messages': {
+ 'win_supported_winxpsp2': {
+ 'text': 'At least Windows 3.15', 'desc': 'blah'
+ },
+ 'doc_recommended': {
+ 'text': 'Recommended', 'desc': 'bleh'
+ }
+ },
+ }''')
+ output = self.GetOutput(grd, 'fr', {'_chromium' : '1'}, 'adm', 'en')
+ expected_output = self.ConstructOutput(
+ ['MACHINE', 'USER'], '''
+ CATEGORY !!chromium
+ KEYNAME "Software\\Policies\\Chromium"
+
+ POLICY !!ListPolicy_Policy
+ #if version >= 4
+ SUPPORTED !!SUPPORTED_WINXPSP2
+ #endif
+ EXPLAIN !!ListPolicy_Explain
+
+ PART !!ListPolicy_Part LISTBOX
+ KEYNAME "Software\\Policies\\Chromium\\ListPolicy"
+ VALUEPREFIX ""
+ END PART
+ END POLICY
+
+ END CATEGORY
+
+ CATEGORY !!chromium_recommended
+ KEYNAME "Software\\Policies\\Chromium\\Recommended"
+
+ POLICY !!ListPolicy_Policy
+ #if version >= 4
+ SUPPORTED !!SUPPORTED_WINXPSP2
+ #endif
+ EXPLAIN !!ListPolicy_Explain
+
+ PART !!ListPolicy_Part LISTBOX
+ KEYNAME "Software\\Policies\\Chromium\\Recommended\\ListPolicy"
+ VALUEPREFIX ""
+ END PART
+ END POLICY
+
+ END CATEGORY
+
+
+''', '''[Strings]
+SUPPORTED_WINXPSP2="At least Windows 3.15"
+chromium="Chromium"
+chromium_recommended="Chromium - Recommended"
+ListPolicy_Policy="Caption of list policy."
+ListPolicy_Explain="Description of list policy.\\nWith a newline."
+ListPolicy_Part="Label of list policy."
+''')
+ self.CompareOutputs(output, expected_output)
+
def testDictionaryPolicy(self):
# Tests a policy group with a single policy of type 'dict'.
grd = self.PrepareTest('''
diff --git a/grit/format/policy_templates/writers/adml_writer.py b/grit/format/policy_templates/writers/adml_writer.py
index 20b7c0d..c525602 100644
--- a/grit/format/policy_templates/writers/adml_writer.py
+++ b/grit/format/policy_templates/writers/adml_writer.py
@@ -99,7 +99,7 @@
dropdownlist_elem = self.AddElement(presentation_elem, 'dropdownList',
{'refId': policy_name})
dropdownlist_elem.appendChild(self._doc.createTextNode(policy_label))
- elif policy_type == 'list':
+ elif policy_type in ('list', 'string-enum-list'):
self._AddString(self._string_table_elem,
policy_name + 'Desc',
policy_caption)
diff --git a/grit/format/policy_templates/writers/adml_writer_unittest.py b/grit/format/policy_templates/writers/adml_writer_unittest.py
index 3600005..8a8f4f7 100644
--- a/grit/format/policy_templates/writers/adml_writer_unittest.py
+++ b/grit/format/policy_templates/writers/adml_writer_unittest.py
@@ -284,6 +284,44 @@
'</presentation>')
self.AssertXMLEquals(output, expected_output)
+ def testStringEnumListPolicy(self):
+ list_policy = {
+ 'name': 'ListPolicyStub',
+ 'type': 'string-enum-list',
+ 'caption': 'List policy caption',
+ 'label': 'List policy label',
+ 'desc': 'This is a test description.',
+ 'items': [
+ {
+ 'name': 'item 1',
+ 'value': 'value 1',
+ 'caption': 'Caption Item 1',
+ },
+ {
+ 'name': 'item 2',
+ 'value': 'value 2',
+ 'caption': 'Caption Item 2',
+ },
+ ],
+ }
+ self. _InitWriterForAddingPolicies(self.writer, list_policy)
+ self.writer.WritePolicy(list_policy)
+ # Assert generated string elements.
+ output = self.GetXMLOfChildren(self.writer._string_table_elem)
+ expected_output = (
+ '<string id="ListPolicyStub">List policy caption</string>\n'
+ '<string id="ListPolicyStub_Explain">'
+ 'This is a test description.</string>\n'
+ '<string id="ListPolicyStubDesc">List policy caption</string>')
+ self.AssertXMLEquals(output, expected_output)
+ # Assert generated presentation elements.
+ output = self.GetXMLOfChildren(self.writer._presentation_table_elem)
+ expected_output = (
+ '<presentation id="ListPolicyStub">\n'
+ ' <listBox refId="ListPolicyStubDesc">List policy label</listBox>\n'
+ '</presentation>')
+ self.AssertXMLEquals(output, expected_output)
+
def testDictionaryPolicy(self):
dict_policy = {
'name': 'DictionaryPolicyStub',
diff --git a/grit/format/policy_templates/writers/admx_writer.py b/grit/format/policy_templates/writers/admx_writer.py
index 69c797d..0d4394b 100644
--- a/grit/format/policy_templates/writers/admx_writer.py
+++ b/grit/format/policy_templates/writers/admx_writer.py
@@ -286,7 +286,7 @@
elif policy_type in ('int-enum', 'string-enum'):
parent = self._GetElements(policy_elem)
self._AddEnumPolicy(parent, policy)
- elif policy_type == 'list':
+ elif policy_type in ('list', 'string-enum-list'):
parent = self._GetElements(policy_elem)
self._AddListPolicy(parent, key, policy_name)
elif policy_type == 'group':
@@ -295,10 +295,11 @@
raise Exception('Unknown policy type %s.' % policy_type)
def WritePolicy(self, policy):
- self._WritePolicy(policy,
- policy['name'],
- self.config['win_reg_mandatory_key_name'],
- self._active_mandatory_policy_group_name)
+ if self.CanBeMandatory(policy):
+ self._WritePolicy(policy,
+ policy['name'],
+ self.config['win_reg_mandatory_key_name'],
+ self._active_mandatory_policy_group_name)
def WriteRecommendedPolicy(self, policy):
self._WritePolicy(policy,
diff --git a/grit/format/policy_templates/writers/admx_writer_unittest.py b/grit/format/policy_templates/writers/admx_writer_unittest.py
index c99131f..cb3d39e 100644
--- a/grit/format/policy_templates/writers/admx_writer_unittest.py
+++ b/grit/format/policy_templates/writers/admx_writer_unittest.py
@@ -219,6 +219,46 @@
self.AssertXMLEquals(output, expected_output)
+ def testRecommendedOnlyPolicy(self):
+ main_policy = {
+ 'name': 'DummyMainPolicy',
+ 'type': 'main',
+ 'features': {
+ 'can_be_recommended': True,
+ 'can_be_mandatory': False,
+ }
+ }
+
+ policy_group = {
+ 'name': 'PolicyGroup',
+ 'policies': [main_policy],
+ }
+ self.writer.BeginTemplate()
+ self.writer.BeginRecommendedPolicyGroup(policy_group)
+
+ self.writer.WritePolicy(main_policy)
+ self.writer.WriteRecommendedPolicy(main_policy)
+
+ output = self.GetXMLOfChildren(self._GetPoliciesElement(self.writer._doc))
+ expected_output = (
+ '<policy class="TestClass" displayName="$(string.DummyMainPolicy)"'
+ ' explainText="$(string.DummyMainPolicy_Explain)"'
+ ' key="Software\\Policies\\Test\\Recommended"'
+ ' name="DummyMainPolicy_recommended"'
+ ' presentation="$(presentation.DummyMainPolicy)"'
+ ' valueName="DummyMainPolicy">\n'
+ ' <parentCategory ref="PolicyGroup_recommended"/>\n'
+ ' <supportedOn ref="SUPPORTED_TESTOS"/>\n'
+ ' <enabledValue>\n'
+ ' <decimal value="1"/>\n'
+ ' </enabledValue>\n'
+ ' <disabledValue>\n'
+ ' <decimal value="0"/>\n'
+ ' </disabledValue>\n'
+ '</policy>')
+
+ self.AssertXMLEquals(output, expected_output)
+
def testStringPolicy(self):
string_policy = {
'name': 'SampleStringPolicy',
@@ -369,6 +409,33 @@
self.AssertXMLEquals(output, expected_output)
+ def testStringEnumListPolicy(self):
+ list_policy = {
+ 'name': 'SampleListPolicy',
+ 'type': 'string-enum-list',
+ 'items': [
+ {'name': 'item_1', 'value': 'one'},
+ {'name': 'item_2', 'value': 'two'},
+ ]
+ }
+ self._initWriterForPolicy(self.writer, list_policy)
+ self.writer.WritePolicy(list_policy)
+ output = self.GetXMLOfChildren(self._GetPoliciesElement(self.writer._doc))
+ expected_output = (
+ '<policy class="TestClass" displayName="$(string.SampleListPolicy)"'
+ ' explainText="$(string.SampleListPolicy_Explain)"'
+ ' key="Software\\Policies\\Test" name="SampleListPolicy"'
+ ' presentation="$(presentation.SampleListPolicy)">\n'
+ ' <parentCategory ref="PolicyGroup"/>\n'
+ ' <supportedOn ref="SUPPORTED_TESTOS"/>\n'
+ ' <elements>\n'
+ ' <list id="SampleListPolicyDesc"'
+ ' key="Software\Policies\Test\SampleListPolicy" valuePrefix=""/>\n'
+ ' </elements>\n'
+ '</policy>')
+
+ self.AssertXMLEquals(output, expected_output)
+
def testDictionaryPolicy(self):
dict_policy = {
'name': 'SampleDictionaryPolicy',
diff --git a/grit/format/policy_templates/writers/doc_writer.py b/grit/format/policy_templates/writers/doc_writer.py
index 7cca976..d8f108d 100644
--- a/grit/format/policy_templates/writers/doc_writer.py
+++ b/grit/format/policy_templates/writers/doc_writer.py
@@ -4,6 +4,7 @@
# found in the LICENSE file.
+import json
from xml.dom import minidom
from grit import lazy_re
from grit.format.policy_templates.writers import xml_formatted_writer
@@ -116,7 +117,7 @@
# Replace URLs with links in the description.
self._AddTextWithLinks(parent, policy['desc'])
# Add list of enum items.
- if policy['type'] in ('string-enum', 'int-enum'):
+ if policy['type'] in ('string-enum', 'int-enum', 'string-enum-list'):
ul = self.AddElement(parent, 'ul')
for item in policy['items']:
if policy['type'] == 'int-enum':
@@ -179,7 +180,10 @@
win = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre'])
win_text = []
cnt = 1
- key_name = self.config['win_reg_mandatory_key_name']
+ if self.CanBeRecommended(policy) and not self.CanBeMandatory(policy):
+ key_name = self.config['win_reg_recommended_key_name']
+ else:
+ key_name = self.config['win_reg_mandatory_key_name']
for item in example_value:
win_text.append(
'%s\\%s\\%d = "%s"' %
@@ -286,9 +290,12 @@
'''
self.AddElement(parent, 'dt', {}, 'Windows:')
win = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre'])
- key_name = self.config['win_reg_mandatory_key_name']
- example = str(policy['example_value'])
- self.AddText(win, '%s\\%s = "%s"' % (key_name, policy['name'], example))
+ if self.CanBeRecommended(policy) and not self.CanBeMandatory(policy):
+ key_name = self.config['win_reg_recommended_key_name']
+ else:
+ key_name = self.config['win_reg_mandatory_key_name']
+ example = json.dumps(policy['example_value'])
+ self.AddText(win, '%s\\%s = %s' % (key_name, policy['name'], example))
def _AddDictionaryExampleLinux(self, parent, policy):
'''Adds an example value for Linux of a 'dict' policy to a DOM node.
@@ -300,7 +307,7 @@
'''
self.AddElement(parent, 'dt', {}, 'Linux:')
linux = self._AddStyledElement(parent, 'dd', ['.monospace'])
- example = str(policy['example_value'])
+ example = json.dumps(policy['example_value'])
self.AddText(linux, '%s: %s' % (policy['name'], example))
def _AddDictionaryExample(self, parent, policy):
@@ -379,7 +386,7 @@
self.AddText(parent, ', '.join(pieces))
elif policy_type == 'string-enum':
self.AddText(parent, '"%s"' % (example_value))
- elif policy_type == 'list':
+ elif policy_type in ('list', 'string-enum-list'):
self._AddListExample(parent, policy)
elif policy_type == 'dict':
self._AddDictionaryExample(parent, policy)
@@ -458,10 +465,14 @@
if policy['type'] != 'external':
# All types except 'external' can be set through platform policy.
if self.IsPolicySupportedOnPlatform(policy, 'win'):
+ if self.CanBeRecommended(policy) and not self.CanBeMandatory(policy):
+ key_name = self.config['win_reg_recommended_key_name']
+ else:
+ key_name = self.config['win_reg_mandatory_key_name']
self._AddPolicyAttribute(
dl,
'win_reg_loc',
- self.config['win_reg_mandatory_key_name'] + '\\' + policy['name'],
+ key_name + '\\' + policy['name'],
['.monospace'])
if (self.IsPolicySupportedOnPlatform(policy, 'linux') or
self.IsPolicySupportedOnPlatform(policy, 'mac')):
@@ -640,16 +651,19 @@
'int-enum': 'Integer',
'string-enum': 'String',
'list': 'List of strings',
+ 'string-enum-list': 'List of strings',
'dict': 'Dictionary',
'external': 'External data reference',
}
+ reg_dict = 'REG_SZ; %s' % self._GetLocalizedMessage(
+ 'complex_policies_on_windows')
self._REG_TYPE_MAP = {
'string': 'REG_SZ',
'int': 'REG_DWORD',
'main': 'REG_DWORD',
'int-enum': 'REG_DWORD',
'string-enum': 'REG_SZ',
- 'dict': 'REG_SZ, encoded as a JSON string',
+ 'dict': reg_dict,
}
# The CSS style-sheet used for the document. It will be used in Google
# Sites, which strips class attributes from HTML tags. To work around this,
diff --git a/grit/format/policy_templates/writers/doc_writer_unittest.py b/grit/format/policy_templates/writers/doc_writer_unittest.py
index 6c087d5..15d8b85 100644
--- a/grit/format/policy_templates/writers/doc_writer_unittest.py
+++ b/grit/format/policy_templates/writers/doc_writer_unittest.py
@@ -6,6 +6,7 @@
'''Unit tests for grit.format.policy_templates.writers.doc_writer'''
+import json
import os
import sys
if __name__ == '__main__':
@@ -37,9 +38,11 @@
'frame_name': 'Chrome Frame',
'os_name': 'Chrome OS',
'win_reg_mandatory_key_name': 'MockKey',
+ 'win_reg_recommended_key_name': 'MockKeyRec',
})
self.writer.messages = {
'doc_back_to_top': {'text': '_test_back_to_top'},
+ 'doc_complex_policies_on_windows': {'text': '_test_complex_policies_win'},
'doc_data_type': {'text': '_test_data_type'},
'doc_description': {'text': '_test_description'},
'doc_description_column_title': {
@@ -48,6 +51,7 @@
'doc_example_value': {'text': '_test_example_value'},
'doc_feature_dynamic_refresh': {'text': '_test_feature_dynamic_refresh'},
'doc_feature_can_be_recommended': {'text': '_test_feature_recommended'},
+ 'doc_feature_can_be_mandatory': {'text': '_test_feature_mandatory'},
'doc_intro': {'text': '_test_intro'},
'doc_mac_linux_pref_name': {'text': '_test_mac_linux_pref_name'},
'doc_note': {'text': '_test_note'},
@@ -282,7 +286,7 @@
'<root>0x00000010 (Windows), 16 (Linux), 16 (Mac)</root>')
def testStringEnumExample(self):
- # Test representation of 'int-enum' example values.
+ # Test representation of 'string-enum' example values.
policy = {
'name': 'PolicyName',
'type': 'string-enum',
@@ -293,6 +297,40 @@
self.doc_root.toxml(),
'<root>"wacky"</root>')
+ def testListExample(self):
+ # Test representation of 'list' example values.
+ policy = {
+ 'name': 'PolicyName',
+ 'type': 'list',
+ 'example_value': ['one', 'two'],
+ 'supported_on': [ { 'platforms': ['linux'] } ]
+ }
+ self.writer._AddExample(self.doc_root, policy)
+ self.assertEquals(
+ self.doc_root.toxml(),
+ '<root><dl style="style_dd dl;">'
+ '<dt>Linux:</dt>'
+ '<dd style="style_.monospace;">'
+ '["one", "two"]'
+ '</dd></dl></root>')
+
+ def testStringEnumListExample(self):
+ # Test representation of 'string-enum-list' example values.
+ policy = {
+ 'name': 'PolicyName',
+ 'type': 'string-enum-list',
+ 'example_value': ['one', 'two'],
+ 'supported_on': [ { 'platforms': ['linux'] } ]
+ }
+ self.writer._AddExample(self.doc_root, policy)
+ self.assertEquals(
+ self.doc_root.toxml(),
+ '<root><dl style="style_dd dl;">'
+ '<dt>Linux:</dt>'
+ '<dd style="style_.monospace;">'
+ '["one", "two"]'
+ '</dd></dl></root>')
+
def testStringExample(self):
# Test representation of 'string' example values.
policy = {
@@ -380,6 +418,117 @@
'<dd>0x00000000 (Windows), false (Linux), <false /> (Mac)</dd>'
'</dl></root>')
+ def testAddDictPolicyDetails(self):
+ # Test if the definition list (<dl>) of policy details is created correctly
+ # for 'dict' policies.
+ policy = {
+ 'type': 'dict',
+ 'name': 'TestPolicyName',
+ 'caption': 'TestPolicyCaption',
+ 'desc': 'TestPolicyDesc',
+ 'supported_on': [{
+ 'product': 'chrome',
+ 'platforms': ['win', 'mac', 'linux'],
+ 'since_version': '8',
+ 'until_version': '',
+ }],
+ 'features': {'dynamic_refresh': False},
+ 'example_value': { 'foo': 123 }
+ }
+ self.writer.messages['doc_since_version'] = {'text': '...$6...'}
+ self.writer._AddPolicyDetails(self.doc_root, policy)
+ self.assertEquals(
+ self.doc_root.toxml(),
+ '<root><dl>'
+ '<dt style="style_dt;">_test_data_type</dt><dd>Dictionary (REG_SZ; _test_complex_policies_win)</dd>'
+ '<dt style="style_dt;">_test_win_reg_loc</dt>'
+ '<dd style="style_.monospace;">MockKey\TestPolicyName</dd>'
+ '<dt style="style_dt;">_test_mac_linux_pref_name</dt>'
+ '<dd style="style_.monospace;">TestPolicyName</dd>'
+ '<dt style="style_dt;">_test_supported_on</dt>'
+ '<dd>'
+ '<ul style="style_ul;">'
+ '<li>Chrome (Windows, Mac, Linux) ...8...</li>'
+ '</ul>'
+ '</dd>'
+ '<dt style="style_dt;">_test_supported_features</dt>'
+ '<dd>_test_feature_dynamic_refresh: _test_not_supported</dd>'
+ '<dt style="style_dt;">_test_description</dt><dd>TestPolicyDesc</dd>'
+ '<dt style="style_dt;">_test_example_value</dt>'
+ '<dd>'
+ '<dl style="style_dd dl;">'
+ '<dt>Windows:</dt>'
+ '<dd style="style_.monospace;style_.pre;">MockKey\TestPolicyName = {"foo": 123}</dd>'
+ '<dt>Linux:</dt>'
+ '<dd style="style_.monospace;">TestPolicyName: {"foo": 123}</dd>'
+ '<dt>Mac:</dt>'
+ '<dd style="style_.monospace;style_.pre;">'
+ '<key>TestPolicyName</key>\n'
+ '<dict>\n'
+ ' <key>foo</key>\n'
+ ' <integer>123</integer>\n'
+ '</dict>'
+ '</dd>'
+ '</dl>'
+ '</dd>'
+ '</dl></root>')
+
+ def testAddPolicyDetailsRecommendedOnly(self):
+ policy = {
+ 'type': 'main',
+ 'name': 'TestPolicyName',
+ 'caption': 'TestPolicyCaption',
+ 'desc': 'TestPolicyDesc',
+ 'supported_on': [{
+ 'product': 'chrome',
+ 'platforms': ['win', 'mac', 'linux'],
+ 'since_version': '8',
+ 'until_version': '',
+ }, {
+ 'product': 'chrome',
+ 'platforms': ['android'],
+ 'since_version': '30',
+ 'until_version': '',
+ }, {
+ 'product': 'chrome',
+ 'platforms': ['ios'],
+ 'since_version': '34',
+ 'until_version': '',
+ }],
+ 'features': {
+ 'dynamic_refresh': False,
+ 'can_be_mandatory': False,
+ 'can_be_recommended': True
+ },
+ 'example_value': False
+ }
+ self.writer.messages['doc_since_version'] = {'text': '...$6...'}
+ self.writer._AddPolicyDetails(self.doc_root, policy)
+ self.assertEquals(
+ self.doc_root.toxml(),
+ '<root><dl>'
+ '<dt style="style_dt;">_test_data_type</dt><dd>Boolean (REG_DWORD)</dd>'
+ '<dt style="style_dt;">_test_win_reg_loc</dt>'
+ '<dd style="style_.monospace;">MockKeyRec\TestPolicyName</dd>'
+ '<dt style="style_dt;">_test_mac_linux_pref_name</dt>'
+ '<dd style="style_.monospace;">TestPolicyName</dd>'
+ '<dt style="style_dt;">_test_supported_on</dt>'
+ '<dd>'
+ '<ul style="style_ul;">'
+ '<li>Chrome (Windows, Mac, Linux) ...8...</li>'
+ '<li>Chrome (Android) ...30...</li>'
+ '<li>Chrome (iOS) ...34...</li>'
+ '</ul>'
+ '</dd>'
+ '<dt style="style_dt;">_test_supported_features</dt>'
+ '<dd>_test_feature_mandatory: _test_not_supported,'
+ ' _test_feature_recommended: _test_supported,'
+ ' _test_feature_dynamic_refresh: _test_not_supported</dd>'
+ '<dt style="style_dt;">_test_description</dt><dd>TestPolicyDesc</dd>'
+ '<dt style="style_dt;">_test_example_value</dt>'
+ '<dd>0x00000000 (Windows), false (Linux), <false /> (Mac)</dd>'
+ '</dl></root>')
+
def testAddPolicyNote(self):
# TODO(jkummerow): The functionality tested by this test is currently not
# used for anything and will probably soon be removed.
@@ -654,14 +803,14 @@
},
}
self.writer._AddDictionaryExample(self.doc_root, policy)
- value = str(policy['example_value'])
+ value = json.dumps(policy['example_value']).replace('"', '"')
self.assertEquals(
self.doc_root.toxml(),
'<root>'
'<dl style="style_dd dl;">'
'<dt>Windows:</dt>'
'<dd style="style_.monospace;style_.pre;">MockKey\PolicyName = '
- '"' + value + '"'
+ + value +
'</dd>'
'<dt>Linux:</dt>'
'<dd style="style_.monospace;">PolicyName: ' + value + '</dd>'
diff --git a/grit/format/policy_templates/writers/ios_plist_writer_unittest.py b/grit/format/policy_templates/writers/ios_plist_writer_unittest.py
index 14a0cab..4743e4e 100644
--- a/grit/format/policy_templates/writers/ios_plist_writer_unittest.py
+++ b/grit/format/policy_templates/writers/ios_plist_writer_unittest.py
@@ -180,6 +180,21 @@
}
self._VerifyGeneratedOutput(templates, expected)
+ def testStringEnumList(self):
+ templates = self._MakeTemplate('StringEnumListPolicy',
+ 'string-enum-list', '["a", "b"]',
+ '''
+ 'items': [
+ { 'name': 'Foo', 'value': 'a', 'caption': '' },
+ { 'name': 'Bar', 'value': 'b', 'caption': '' },
+ ],
+ ''')
+
+ expected = {
+ 'StringEnumListPolicy': [ "a", "b" ],
+ }
+ self._VerifyGeneratedOutput(templates, expected)
+
def testListOfDictionary(self):
templates = self._MakeTemplate(
'ManagedBookmarks', 'dict',
diff --git a/grit/format/policy_templates/writers/json_writer.py b/grit/format/policy_templates/writers/json_writer.py
index 673bbf7..f5af8c1 100644
--- a/grit/format/policy_templates/writers/json_writer.py
+++ b/grit/format/policy_templates/writers/json_writer.py
@@ -49,6 +49,13 @@
if not self._first_written:
self._out[-2] += ','
+ if not self.CanBeMandatory(policy) and self.CanBeRecommended(policy):
+ line = ' // Note: this policy is supported only in recommended mode.'
+ self._out.append(line)
+ line = ' // The JSON file should be placed in %srecommended.' % \
+ self.config['linux_policy_path']
+ self._out.append(line)
+
line = ' // %s' % policy['caption']
self._out.append(line)
self._out.append(HEADER_DELIMETER)
diff --git a/grit/format/policy_templates/writers/json_writer_unittest.py b/grit/format/policy_templates/writers/json_writer_unittest.py
index 00acde3..b2ed1ef 100644
--- a/grit/format/policy_templates/writers/json_writer_unittest.py
+++ b/grit/format/policy_templates/writers/json_writer_unittest.py
@@ -86,6 +86,40 @@
'}')
self.CompareOutputs(output, expected_output)
+ def testRecommendedOnlyPolicy(self):
+ # Tests a policy group with a single policy of type 'main'.
+ grd = self.PrepareTest(
+ '{'
+ ' "policy_definitions": ['
+ ' {'
+ ' "name": "MainPolicy",'
+ ' "type": "main",'
+ ' "caption": "Example Main Policy",'
+ ' "desc": "Example Main Policy",'
+ ' "features": {'
+ ' "can_be_recommended": True,'
+ ' "can_be_mandatory": False'
+ ' },'
+ ' "supported_on": ["chrome.linux:8-"],'
+ ' "example_value": True'
+ ' },'
+ ' ],'
+ ' "placeholders": [],'
+ ' "messages": {},'
+ '}')
+ output = self.GetOutput(grd, 'fr', {'_google_chrome' : '1'}, 'json', 'en')
+ expected_output = (
+ TEMPLATE_HEADER +
+ ' // Note: this policy is supported only in recommended mode.\n' +
+ ' // The JSON file should be placed in' +
+ ' /etc/opt/chrome/policies/recommended.\n' +
+ ' // Example Main Policy\n' +
+ HEADER_DELIMETER +
+ ' // Example Main Policy\n\n'
+ ' //"MainPolicy": true\n\n'
+ '}')
+ self.CompareOutputs(output, expected_output)
+
def testStringPolicy(self):
# Tests a policy group with a single policy of type 'string'.
grd = self.PrepareTest(
@@ -231,6 +265,39 @@
'}')
self.CompareOutputs(output, expected_output)
+ def testStringEnumListPolicy(self):
+ # Tests a policy group with a single policy of type 'string-enum-list'.
+ grd = self.PrepareTest(
+ '{'
+ ' "policy_definitions": ['
+ ' {'
+ ' "name": "ListPolicy",'
+ ' "type": "string-enum-list",'
+ ' "caption": "Example List",'
+ ' "desc": "Example List",'
+ ' "items": ['
+ ' {"name": "ProxyServerDisabled", "value": "one",'
+ ' "caption": ""},'
+ ' {"name": "ProxyServerAutoDetect", "value": "two",'
+ ' "caption": ""},'
+ ' ],'
+ ' "supported_on": ["chrome.linux:8-"],'
+ ' "example_value": ["one", "two"]'
+ ' },'
+ ' ],'
+ ' "placeholders": [],'
+ ' "messages": {},'
+ '}')
+ output = self.GetOutput(grd, 'fr', {'_chromium' : '1'}, 'json', 'en')
+ expected_output = (
+ TEMPLATE_HEADER +
+ ' // Example List\n' +
+ HEADER_DELIMETER +
+ ' // Example List\n\n'
+ ' //"ListPolicy": ["one", "two"]\n\n'
+ '}')
+ self.CompareOutputs(output, expected_output)
+
def testDictionaryPolicy(self):
# Tests a policy group with a single policy of type 'dict'.
example = {
diff --git a/grit/format/policy_templates/writers/plist_strings_writer.py b/grit/format/policy_templates/writers/plist_strings_writer.py
index 08fcddd..966aaf2 100644
--- a/grit/format/policy_templates/writers/plist_strings_writer.py
+++ b/grit/format/policy_templates/writers/plist_strings_writer.py
@@ -52,7 +52,7 @@
if policy['type'] == 'external':
# This type can only be set through cloud policy.
return
- elif policy['type'] in ('int-enum','string-enum'):
+ elif policy['type'] in ('int-enum','string-enum', 'string-enum-list'):
# Append the captions of enum items to the description string.
item_descs = []
for item in policy['items']:
diff --git a/grit/format/policy_templates/writers/plist_strings_writer_unittest.py b/grit/format/policy_templates/writers/plist_strings_writer_unittest.py
index 613a3cd..17fc85c 100644
--- a/grit/format/policy_templates/writers/plist_strings_writer_unittest.py
+++ b/grit/format/policy_templates/writers/plist_strings_writer_unittest.py
@@ -127,6 +127,111 @@
'"Description of policy.\\nWith a newline.";')
self.assertEquals(output.strip(), expected_output.strip())
+ def testStringListPolicy(self):
+ # Tests a policy group with a single policy of type 'list'.
+ grd = self.PrepareTest('''
+ {
+ 'policy_definitions': [
+ {
+ 'name': 'ListGroup',
+ 'type': 'group',
+ 'caption': '',
+ 'desc': '',
+ 'policies': [{
+ 'name': 'ListPolicy',
+ 'type': 'list',
+ 'caption': 'Caption of policy.',
+ 'desc': """Description of policy.
+With a newline.""",
+ 'schema': {
+ 'type': 'array',
+ 'items': { 'type': 'string' },
+ },
+ 'supported_on': ['chrome.mac:8-'],
+ }],
+ },
+ ],
+ 'placeholders': [],
+ 'messages': {
+ 'mac_chrome_preferences': {
+ 'text': 'Preferences of $1',
+ 'desc': 'blah'
+ }
+ }
+ }''')
+ output = self.GetOutput(
+ grd,
+ 'fr',
+ {'_chromium' : '1', 'mac_bundle_id': 'com.example.Test'},
+ 'plist_strings',
+ 'en')
+ expected_output = (
+ 'Chromium.pfm_title = "Chromium";\n'
+ 'Chromium.pfm_description = "Preferences of Chromium";\n'
+ 'ListPolicy.pfm_title = "Caption of policy.";\n'
+ 'ListPolicy.pfm_description = '
+ '"Description of policy.\\nWith a newline.";')
+ self.assertEquals(output.strip(), expected_output.strip())
+
+ def testStringEnumListPolicy(self):
+ # Tests a policy group with a single policy of type 'string-enum-list'.
+ grd = self.PrepareTest('''
+ {
+ 'policy_definitions': [
+ {
+ 'name': 'EnumGroup',
+ 'type': 'group',
+ 'caption': '',
+ 'desc': '',
+ 'policies': [{
+ 'name': 'EnumPolicy',
+ 'type': 'string-enum-list',
+ 'caption': 'Caption of policy.',
+ 'desc': """Description of policy.
+With a newline.""",
+ 'schema': {
+ 'type': 'array',
+ 'items': { 'type': 'string' },
+ },
+ 'items': [
+ {
+ 'name': 'ProxyServerDisabled',
+ 'value': 'one',
+ 'caption': 'Option1'
+ },
+ {
+ 'name': 'ProxyServerAutoDetect',
+ 'value': 'two',
+ 'caption': 'Option2'
+ },
+ ],
+ 'supported_on': ['chrome.mac:8-'],
+ }],
+ },
+ ],
+ 'placeholders': [],
+ 'messages': {
+ 'mac_chrome_preferences': {
+ 'text': 'Preferences of $1',
+ 'desc': 'blah'
+ }
+ }
+ }''')
+ output = self.GetOutput(
+ grd,
+ 'fr',
+ {'_chromium' : '1', 'mac_bundle_id': 'com.example.Test'},
+ 'plist_strings',
+ 'en')
+ expected_output = (
+ 'Chromium.pfm_title = "Chromium";\n'
+ 'Chromium.pfm_description = "Preferences of Chromium";\n'
+ 'EnumPolicy.pfm_title = "Caption of policy.";\n'
+ 'EnumPolicy.pfm_description = '
+ '"one - Option1\\ntwo - Option2\\n'
+ 'Description of policy.\\nWith a newline.";')
+ self.assertEquals(output.strip(), expected_output.strip())
+
def testIntEnumPolicy(self):
# Tests a policy group with a single policy of type 'int-enum'.
grd = self.PrepareTest('''
diff --git a/grit/format/policy_templates/writers/plist_writer.py b/grit/format/policy_templates/writers/plist_writer.py
index 2297858..6d929d6 100644
--- a/grit/format/policy_templates/writers/plist_writer.py
+++ b/grit/format/policy_templates/writers/plist_writer.py
@@ -32,6 +32,7 @@
'int': 'integer',
'int-enum': 'integer',
'string-enum': 'string',
+ 'string-enum-list': 'array',
'main': 'boolean',
'list': 'array',
'dict': 'dictionary',
@@ -66,7 +67,7 @@
self.AddElement(parent, 'key', {}, key_string)
self.AddElement(parent, 'string', {}, value_string)
- def _AddTargets(self, parent):
+ def _AddTargets(self, parent, policy):
'''Adds the following XML snippet to an XML element:
<key>pfm_targets</key>
<array>
@@ -77,7 +78,10 @@
parent: The parent XML element where the snippet will be added.
'''
array = self._AddKeyValuePair(parent, 'pfm_targets', 'array')
- self.AddElement(array, 'string', {}, 'user-managed')
+ if self.CanBeRecommended(policy):
+ self.AddElement(array, 'string', {}, 'user')
+ if self.CanBeMandatory(policy):
+ self.AddElement(array, 'string', {}, 'user-managed')
def PreprocessPolicies(self, policy_list):
return self.FlattenGroupsAndSortPolicies(policy_list)
@@ -96,7 +100,7 @@
# Those files are generated by plist_strings_writer.
self._AddStringKeyValuePair(dict, 'pfm_description', '')
self._AddStringKeyValuePair(dict, 'pfm_title', '')
- self._AddTargets(dict)
+ self._AddTargets(dict, policy)
self._AddStringKeyValuePair(dict, 'pfm_type',
self.TYPE_TO_INPUT[policy_type])
if policy_type in ('int-enum', 'string-enum'):
@@ -107,7 +111,7 @@
else:
element_type = 'string'
self.AddElement(range_list, element_type, {}, str(item['value']))
- elif policy_type == 'list':
+ elif policy_type in ('list', 'string-enum-list'):
subkeys = self._AddKeyValuePair(dict, 'pfm_subkeys', 'array')
subkeys_dict = self.AddElement(subkeys, 'dict')
subkeys_type = self._AddKeyValuePair(subkeys_dict, 'pfm_type', 'string')
diff --git a/grit/format/policy_templates/writers/plist_writer_unittest.py b/grit/format/policy_templates/writers/plist_writer_unittest.py
index a9d146d..ddbdbfe 100644
--- a/grit/format/policy_templates/writers/plist_writer_unittest.py
+++ b/grit/format/policy_templates/writers/plist_writer_unittest.py
@@ -118,6 +118,108 @@
</array>''')
self.assertEquals(output.strip(), expected_output.strip())
+ def testRecommendedPolicy(self):
+ # Tests a policy group with a single policy of type 'main'.
+ grd = self.PrepareTest('''
+ {
+ 'policy_definitions': [
+ {
+ 'name': 'MainGroup',
+ 'type': 'group',
+ 'policies': [{
+ 'name': 'MainPolicy',
+ 'type': 'main',
+ 'desc': '',
+ 'caption': '',
+ 'features': {
+ 'can_be_recommended' : True
+ },
+ 'supported_on': ['chrome.mac:8-'],
+ }],
+ 'desc': '',
+ 'caption': '',
+ },
+ ],
+ 'placeholders': [],
+ 'messages': {}
+ }''')
+ output = self.GetOutput(
+ grd,
+ 'fr',
+ {'_chromium' : '1', 'mac_bundle_id': 'com.example.Test'},
+ 'plist',
+ 'en')
+ expected_output = self._GetExpectedOutputs(
+ 'Chromium', 'com.example.Test', '''<array>
+ <dict>
+ <key>pfm_name</key>
+ <string>MainPolicy</string>
+ <key>pfm_description</key>
+ <string/>
+ <key>pfm_title</key>
+ <string/>
+ <key>pfm_targets</key>
+ <array>
+ <string>user</string>
+ <string>user-managed</string>
+ </array>
+ <key>pfm_type</key>
+ <string>boolean</string>
+ </dict>
+ </array>''')
+ self.assertEquals(output.strip(), expected_output.strip())
+
+ def testRecommendedOnlyPolicy(self):
+ # Tests a policy group with a single policy of type 'main'.
+ grd = self.PrepareTest('''
+ {
+ 'policy_definitions': [
+ {
+ 'name': 'MainGroup',
+ 'type': 'group',
+ 'policies': [{
+ 'name': 'MainPolicy',
+ 'type': 'main',
+ 'desc': '',
+ 'caption': '',
+ 'features': {
+ 'can_be_recommended' : True,
+ 'can_be_mandatory' : False
+ },
+ 'supported_on': ['chrome.mac:8-'],
+ }],
+ 'desc': '',
+ 'caption': '',
+ },
+ ],
+ 'placeholders': [],
+ 'messages': {}
+ }''')
+ output = self.GetOutput(
+ grd,
+ 'fr',
+ {'_chromium' : '1', 'mac_bundle_id': 'com.example.Test'},
+ 'plist',
+ 'en')
+ expected_output = self._GetExpectedOutputs(
+ 'Chromium', 'com.example.Test', '''<array>
+ <dict>
+ <key>pfm_name</key>
+ <string>MainPolicy</string>
+ <key>pfm_description</key>
+ <string/>
+ <key>pfm_title</key>
+ <string/>
+ <key>pfm_targets</key>
+ <array>
+ <string>user</string>
+ </array>
+ <key>pfm_type</key>
+ <string>boolean</string>
+ </dict>
+ </array>''')
+ self.assertEquals(output.strip(), expected_output.strip())
+
def testStringPolicy(self):
# Tests a policy group with a single policy of type 'string'.
grd = self.PrepareTest('''
@@ -165,6 +267,127 @@
</array>''')
self.assertEquals(output.strip(), expected_output.strip())
+ def testListPolicy(self):
+ # Tests a policy group with a single policy of type 'list'.
+ grd = self.PrepareTest('''
+ {
+ 'policy_definitions': [
+ {
+ 'name': 'ListGroup',
+ 'type': 'group',
+ 'desc': '',
+ 'caption': '',
+ 'policies': [{
+ 'name': 'ListPolicy',
+ 'type': 'list',
+ 'schema': {
+ 'type': 'array',
+ 'items': { 'type': 'string' },
+ },
+ 'supported_on': ['chrome.mac:8-'],
+ 'desc': '',
+ 'caption': '',
+ }],
+ },
+ ],
+ 'placeholders': [],
+ 'messages': {},
+ }''')
+ output = self.GetOutput(
+ grd,
+ 'fr',
+ {'_chromium' : '1', 'mac_bundle_id': 'com.example.Test'},
+ 'plist',
+ 'en')
+ expected_output = self._GetExpectedOutputs(
+ 'Chromium', 'com.example.Test', '''<array>
+ <dict>
+ <key>pfm_name</key>
+ <string>ListPolicy</string>
+ <key>pfm_description</key>
+ <string/>
+ <key>pfm_title</key>
+ <string/>
+ <key>pfm_targets</key>
+ <array>
+ <string>user-managed</string>
+ </array>
+ <key>pfm_type</key>
+ <string>array</string>
+ <key>pfm_subkeys</key>
+ <array>
+ <dict>
+ <key>pfm_type</key>
+ <string>string</string>
+ </dict>
+ </array>
+ </dict>
+ </array>''')
+ self.assertEquals(output.strip(), expected_output.strip())
+
+ def testStringEnumListPolicy(self):
+ # Tests a policy group with a single policy of type 'string-enum-list'.
+ grd = self.PrepareTest('''
+ {
+ 'policy_definitions': [
+ {
+ 'name': 'ListGroup',
+ 'type': 'group',
+ 'desc': '',
+ 'caption': '',
+ 'policies': [{
+ 'name': 'ListPolicy',
+ 'type': 'string-enum-list',
+ 'schema': {
+ 'type': 'array',
+ 'items': { 'type': 'string' },
+ },
+ 'items': [
+ {'name': 'ProxyServerDisabled', 'value': 'one', 'caption': ''},
+ {'name': 'ProxyServerAutoDetect', 'value': 'two', 'caption': ''},
+ ],
+ 'supported_on': ['chrome.mac:8-'],
+ 'supported_on': ['chrome.mac:8-'],
+ 'desc': '',
+ 'caption': '',
+ }],
+ },
+ ],
+ 'placeholders': [],
+ 'messages': {},
+ }''')
+ output = self.GetOutput(
+ grd,
+ 'fr',
+ {'_chromium' : '1', 'mac_bundle_id': 'com.example.Test'},
+ 'plist',
+ 'en')
+ expected_output = self._GetExpectedOutputs(
+ 'Chromium', 'com.example.Test', '''<array>
+ <dict>
+ <key>pfm_name</key>
+ <string>ListPolicy</string>
+ <key>pfm_description</key>
+ <string/>
+ <key>pfm_title</key>
+ <string/>
+ <key>pfm_targets</key>
+ <array>
+ <string>user-managed</string>
+ </array>
+ <key>pfm_type</key>
+ <string>array</string>
+ <key>pfm_subkeys</key>
+ <array>
+ <dict>
+ <key>pfm_type</key>
+ <string>string</string>
+ </dict>
+ </array>
+ </dict>
+ </array>''')
+ self.assertEquals(output.strip(), expected_output.strip())
+
def testIntPolicy(self):
# Tests a policy group with a single policy of type 'int'.
grd = self.PrepareTest('''
diff --git a/grit/format/policy_templates/writers/reg_writer.py b/grit/format/policy_templates/writers/reg_writer.py
index beb1590..ad83046 100644
--- a/grit/format/policy_templates/writers/reg_writer.py
+++ b/grit/format/policy_templates/writers/reg_writer.py
@@ -47,7 +47,7 @@
list.sort() methods to sort policies.
See TemplateWriter.SortPoliciesGroupsFirst for usage.
'''
- is_list = policy['type'] == 'list'
+ is_list = policy['type'] in ('list', 'string-enum-list')
# Lists come after regular policies.
return (is_list, policy['name'])
@@ -57,7 +57,7 @@
if policy['type'] == 'external':
# This type can only be set through cloud policy.
return
- elif policy['type'] == 'list':
+ elif policy['type'] in ('list', 'string-enum-list'):
self._StartBlock(key, policy['name'], list)
i = 1
for item in example_value:
@@ -83,9 +83,10 @@
list.append('"%s"=%s' % (policy['name'], example_value_str))
def WritePolicy(self, policy):
- self._WritePolicy(policy,
- self.config['win_reg_mandatory_key_name'],
- self._mandatory)
+ if self.CanBeMandatory(policy):
+ self._WritePolicy(policy,
+ self.config['win_reg_mandatory_key_name'],
+ self._mandatory)
def WriteRecommendedPolicy(self, policy):
self._WritePolicy(policy,
diff --git a/grit/format/policy_templates/writers/reg_writer_unittest.py b/grit/format/policy_templates/writers/reg_writer_unittest.py
index d559c9f..88fb2e2 100644
--- a/grit/format/policy_templates/writers/reg_writer_unittest.py
+++ b/grit/format/policy_templates/writers/reg_writer_unittest.py
@@ -77,6 +77,35 @@
'"MainPolicy"=dword:00000001'])
self.CompareOutputs(output, expected_output)
+ def testRecommendedMainPolicy(self):
+ # Tests a policy group with a single policy of type 'main'.
+ grd = self.PrepareTest(
+ '{'
+ ' "policy_definitions": ['
+ ' {'
+ ' "name": "MainPolicy",'
+ ' "type": "main",'
+ ' "features": {'
+ ' "can_be_recommended": True,'
+ ' "can_be_mandatory": False '
+ ' },'
+ ' "caption": "",'
+ ' "desc": "",'
+ ' "supported_on": ["chrome.win:8-"],'
+ ' "example_value": True'
+ ' },'
+ ' ],'
+ ' "placeholders": [],'
+ ' "messages": {},'
+ '}')
+ output = self.GetOutput(grd, 'fr', {'_google_chrome' : '1'}, 'reg', 'en')
+ expected_output = self.NEWLINE.join([
+ 'Windows Registry Editor Version 5.00',
+ '',
+ '[HKEY_LOCAL_MACHINE\\Software\\Policies\\Google\\Chrome\\Recommended]',
+ '"MainPolicy"=dword:00000001'])
+ self.CompareOutputs(output, expected_output)
+
def testStringPolicy(self):
# Tests a policy group with a single policy of type 'string'.
grd = self.PrepareTest(
@@ -212,6 +241,37 @@
'"1"="foo"',
'"2"="bar"'])
+ def testStringEnumListPolicy(self):
+ # Tests a policy group with a single policy of type 'string-enum-list'.
+ grd = self.PrepareTest(
+ '{'
+ ' "policy_definitions": ['
+ ' {'
+ ' "name": "ListPolicy",'
+ ' "type": "string-enum-list",'
+ ' "caption": "",'
+ ' "desc": "",'
+ ' "items": ['
+ ' {"name": "ProxyServerDisabled", "value": "foo",'
+ ' "caption": ""},'
+ ' {"name": "ProxyServerAutoDetect", "value": "bar",'
+ ' "caption": ""},'
+ ' ],'
+ ' "supported_on": ["chrome.linux:8-"],'
+ ' "example_value": ["foo", "bar"]'
+ ' },'
+ ' ],'
+ ' "placeholders": [],'
+ ' "messages": {},'
+ '}')
+ output = self.GetOutput(grd, 'fr', {'_chromium' : '1'}, 'reg', 'en')
+ expected_output = self.NEWLINE.join([
+ 'Windows Registry Editor Version 5.00',
+ '',
+ '[HKEY_LOCAL_MACHINE\\Software\\Policies\\Chromium\\ListPolicy]',
+ '"1"="foo"',
+ '"2"="bar"'])
+
def testDictionaryPolicy(self):
# Tests a policy group with a single policy of type 'dict'.
example = {
diff --git a/grit/format/policy_templates/writers/template_writer.py b/grit/format/policy_templates/writers/template_writer.py
index 2a8b548..bd48425 100644
--- a/grit/format/policy_templates/writers/template_writer.py
+++ b/grit/format/policy_templates/writers/template_writer.py
@@ -87,6 +87,10 @@
'''Checks if the given policy can be recommended.'''
return policy.get('features', {}).get('can_be_recommended', False)
+ def CanBeMandatory(self, policy):
+ '''Checks if the given policy can be mandatory.'''
+ return policy.get('features', {}).get('can_be_mandatory', True)
+
def IsPolicySupportedOnPlatform(self, policy, platform):
'''Checks if |policy| is supported on |platform|.
diff --git a/grit/format/resource_map.py b/grit/format/resource_map.py
index b5a7b45..37ac54a 100644
--- a/grit/format/resource_map.py
+++ b/grit/format/resource_map.py
@@ -109,18 +109,18 @@
tids = rc_header.GetIds(root)
seen = set()
active_descendants = [item for item in root.ActiveDescendants()]
+ output_all_resource_defines = root.ShouldOutputAllResourceDefines()
for item in root:
- if isinstance(item, (include.IncludeNode,
- structure.StructureNode,
- message.MessageNode)):
- key = get_key(item)
- tid = item.attrs['name']
- if tid in tids and key not in seen:
- seen.add(key)
- # For messages, only include the active ones
- if not isinstance(item, message.MessageNode) \
- or item in active_descendants:
- yield ' {"%s", %s},\n' % (key, tid)
+ if not item.IsResourceMapSource():
+ continue
+ key = get_key(item)
+ tid = item.attrs['name']
+ if tid not in tids or key in seen:
+ continue
+ seen.add(key)
+ if item.GeneratesResourceMapEntry(output_all_resource_defines,
+ item in active_descendants):
+ yield ' {"%s", %s},\n' % (key, tid)
yield _FormatSourceFooter(root)
diff --git a/grit/format/resource_map_unittest.py b/grit/format/resource_map_unittest.py
index 8f162b5..55de504 100644
--- a/grit/format/resource_map_unittest.py
+++ b/grit/format/resource_map_unittest.py
@@ -94,6 +94,129 @@
};
const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output)
+ def testFormatResourceMapWithOutputAllEqualsFalseForStructures(self):
+ grd = grd_reader.Parse(StringIO.StringIO(
+ '''<?xml version="1.0" encoding="UTF-8"?>
+ <grit latest_public_release="2" source_lang_id="en" current_release="3"
+ base_dir="." output_all_resource_defines="false">
+ <outputs>
+ <output type="rc_header" filename="the_rc_header.h" />
+ <output type="resource_map_header"
+ filename="the_resource_map_header.h" />
+ <output type="resource_map_source"
+ filename="the_resource_map_header.cc" />
+ </outputs>
+ <release seq="3">
+ <structures first_id="300">
+ <structure type="chrome_scaled_image" name="IDR_KLONKMENU"
+ file="foo.png" />
+ <if expr="False">
+ <structure type="chrome_scaled_image" name="IDR_MISSING"
+ file="bar.png" />
+ </if>
+ </structures>
+ </release>
+ </grit>'''), util.PathFromRoot('.'))
+ grd.SetOutputLanguage('en')
+ grd.RunGatherers()
+ output = util.StripBlankLinesAndComments(''.join(
+ resource_map.GetFormatter('resource_map_header')(grd, 'en', '.')))
+ self.assertEqual('''\
+#include <stddef.h>
+#ifndef GRIT_RESOURCE_MAP_STRUCT_
+#define GRIT_RESOURCE_MAP_STRUCT_
+struct GritResourceMap {
+ const char* const name;
+ int value;
+};
+#endif // GRIT_RESOURCE_MAP_STRUCT_
+extern const GritResourceMap kTheRcHeader[];
+extern const size_t kTheRcHeaderSize;''', output)
+ output = util.StripBlankLinesAndComments(''.join(
+ resource_map.GetFormatter('resource_map_source')(grd, 'en', '.')))
+ self.assertEqual('''\
+#include "the_resource_map_header.h"
+#include "base/basictypes.h"
+#include "the_rc_header.h"
+const GritResourceMap kTheRcHeader[] = {
+ {"IDR_KLONKMENU", IDR_KLONKMENU},
+};
+const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output)
+ output = util.StripBlankLinesAndComments(''.join(
+ resource_map.GetFormatter('resource_map_source')(grd, 'en', '.')))
+ self.assertEqual('''\
+#include "the_resource_map_header.h"
+#include "base/basictypes.h"
+#include "the_rc_header.h"
+const GritResourceMap kTheRcHeader[] = {
+ {"IDR_KLONKMENU", IDR_KLONKMENU},
+};
+const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output)
+
+ def testFormatResourceMapWithOutputAllEqualsFalseForIncludes(self):
+ grd = grd_reader.Parse(StringIO.StringIO(
+ '''<?xml version="1.0" encoding="UTF-8"?>
+ <grit latest_public_release="2" source_lang_id="en" current_release="3"
+ base_dir="." output_all_resource_defines="false">
+ <outputs>
+ <output type="rc_header" filename="the_rc_header.h" />
+ <output type="resource_map_header"
+ filename="the_resource_map_header.h" />
+ </outputs>
+ <release seq="3">
+ <structures first_id="300">
+ <structure type="menu" name="IDC_KLONKMENU"
+ file="grit\\testdata\\klonk.rc" encoding="utf-16" />
+ </structures>
+ <includes first_id="10000">
+ <include type="foo" file="abc" name="IDS_FIRSTPRESENT" />
+ <if expr="False">
+ <include type="foo" file="def" name="IDS_MISSING" />
+ </if>
+ <include type="foo" file="mno" name="IDS_THIRDPRESENT" />
+ </includes>
+ </release>
+ </grit>'''), util.PathFromRoot('.'))
+ grd.SetOutputLanguage('en')
+ grd.RunGatherers()
+ output = util.StripBlankLinesAndComments(''.join(
+ resource_map.GetFormatter('resource_map_header')(grd, 'en', '.')))
+ self.assertEqual('''\
+#include <stddef.h>
+#ifndef GRIT_RESOURCE_MAP_STRUCT_
+#define GRIT_RESOURCE_MAP_STRUCT_
+struct GritResourceMap {
+ const char* const name;
+ int value;
+};
+#endif // GRIT_RESOURCE_MAP_STRUCT_
+extern const GritResourceMap kTheRcHeader[];
+extern const size_t kTheRcHeaderSize;''', output)
+ output = util.StripBlankLinesAndComments(''.join(
+ resource_map.GetFormatter('resource_map_source')(grd, 'en', '.')))
+ self.assertEqual('''\
+#include "the_resource_map_header.h"
+#include "base/basictypes.h"
+#include "the_rc_header.h"
+const GritResourceMap kTheRcHeader[] = {
+ {"IDC_KLONKMENU", IDC_KLONKMENU},
+ {"IDS_FIRSTPRESENT", IDS_FIRSTPRESENT},
+ {"IDS_THIRDPRESENT", IDS_THIRDPRESENT},
+};
+const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output)
+ output = util.StripBlankLinesAndComments(''.join(
+ resource_map.GetFormatter('resource_file_map_source')(grd, 'en', '.')))
+ self.assertEqual('''\
+#include "the_resource_map_header.h"
+#include "base/basictypes.h"
+#include "the_rc_header.h"
+const GritResourceMap kTheRcHeader[] = {
+ {"grit/testdata/klonk.rc", IDC_KLONKMENU},
+ {"abc", IDS_FIRSTPRESENT},
+ {"mno", IDS_THIRDPRESENT},
+};
+const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output)
+
def testFormatStringResourceMap(self):
grd = grd_reader.Parse(StringIO.StringIO(
'''<?xml version="1.0" encoding="UTF-8"?>
diff --git a/grit/node/base.py b/grit/node/base.py
index 3de51b6..a40794b 100644
--- a/grit/node/base.py
+++ b/grit/node/base.py
@@ -590,6 +590,21 @@
'''Whether we need to expand variables on a given node.'''
return False
+ def IsResourceMapSource(self):
+ '''Whether this node is a resource map source.'''
+ return False
+
+ def GeneratesResourceMapEntry(self, output_all_resource_defines,
+ is_active_descendant):
+ '''Whether this node should output a resource map entry.
+
+ Args:
+ output_all_resource_defines: The value of output_all_resource_defines for
+ the root node.
+ is_active_descendant: Whether the current node is an active descendant
+ from the root node.'''
+ return False
+
class ContentNode(Node):
'''Convenience baseclass for nodes that can have content.'''
diff --git a/grit/node/include.py b/grit/node/include.py
index 9c3685f..8d32064 100644
--- a/grit/node/include.py
+++ b/grit/node/include.py
@@ -113,6 +113,16 @@
self.ToRealPath(self.GetInputPath()),
allow_external_script=allow_external_script)
+ def IsResourceMapSource(self):
+ return True
+
+ def GeneratesResourceMapEntry(self, output_all_resource_defines,
+ is_active_descendant):
+ # includes always generate resource entries.
+ if output_all_resource_defines:
+ return True
+ return is_active_descendant
+
@staticmethod
def Construct(parent, name, type, file, translateable=True,
filenameonly=False, mkoutput=False, relativepath=False):
diff --git a/grit/node/message.py b/grit/node/message.py
index ca80f41..48cd1c7 100644
--- a/grit/node/message.py
+++ b/grit/node/message.py
@@ -224,6 +224,13 @@
message = self.ws_at_start + self.Translate(lang) + self.ws_at_end
return id, util.Encode(message, encoding)
+ def IsResourceMapSource(self):
+ return True
+
+ def GeneratesResourceMapEntry(self, output_all_resource_defines,
+ is_active_descendant):
+ return is_active_descendant
+
@staticmethod
def Construct(parent, message, name, desc='', meaning='', translateable=True):
'''Constructs a new message node that is a child of 'parent', with the
diff --git a/grit/node/structure.py b/grit/node/structure.py
index 48968f6..7ccd2fb 100644
--- a/grit/node/structure.py
+++ b/grit/node/structure.py
@@ -332,6 +332,15 @@
return filename
+ def IsResourceMapSource(self):
+ return True
+
+ def GeneratesResourceMapEntry(self, output_all_resource_defines,
+ is_active_descendant):
+ if output_all_resource_defines:
+ return True
+ return is_active_descendant
+
@staticmethod
def Construct(parent, name, type, file, encoding='cp1252'):
'''Creates a new node which is a child of 'parent', with attributes set
diff --git a/grit/tool/build.py b/grit/tool/build.py
index 87ee412..537e2c6 100644
--- a/grit/tool/build.py
+++ b/grit/tool/build.py
@@ -63,6 +63,20 @@
Options:
+ -a FILE Assert that the given file is an output. There can be
+ multiple "-a" flags listed for multiple outputs. If a "-a"
+ or "--assert-file-list" argument is present, then the list
+ of asserted files must match the output files or the tool
+ will fail. The use-case is for the build system to maintain
+ separate lists of output files and to catch errors if the
+ build system's list and the grit list are out-of-sync.
+
+ --assert-file-list Provide a file listing multiple asserted output files.
+ There is one file name per line. This acts like specifying
+ each file with "-a" on the command line, but without the
+ possibility of running into OS line-length limits for very
+ long lists.
+
-o OUTPUTDIR Specify what directory output paths are relative to.
Defaults to the current directory.
@@ -104,13 +118,20 @@
self.output_directory = '.'
first_ids_file = None
whitelist_filenames = []
+ assert_output_files = []
target_platform = None
depfile = None
depdir = None
rc_header_format = None
- (own_opts, args) = getopt.getopt(args, 'o:D:E:f:w:t:h:', ('depdir=','depfile='))
+ (own_opts, args) = getopt.getopt(args, 'a:o:D:E:f:w:t:h:',
+ ('depdir=','depfile=','assert-file-list='))
for (key, val) in own_opts:
- if key == '-o':
+ if key == '-a':
+ assert_output_files.append(val)
+ elif key == '--assert-file-list':
+ with open(val) as f:
+ assert_output_files += f.read().splitlines()
+ elif key == '-o':
self.output_directory = val
elif key == '-D':
name, val = util.ParseDefine(val)
@@ -166,8 +187,12 @@
self.res.RunGatherers()
self.Process()
+ if assert_output_files:
+ if not self.CheckAssertedOutputFiles(assert_output_files):
+ return 2
+
if depfile and depdir:
- self.GenerateDepfile(opts.input, depfile, depdir)
+ self.GenerateDepfile(depfile, depdir)
return 0
@@ -324,7 +349,31 @@
print self.res.UberClique().missing_translations_
sys.exit(-1)
- def GenerateDepfile(self, input_filename, depfile, depdir):
+
+ def CheckAssertedOutputFiles(self, assert_output_files):
+ '''Checks that the asserted output files are specified in the given list.
+
+ Returns true if the asserted files are present. If they are not, returns
+ False and prints the failure.
+ '''
+ # Compare the absolute path names, sorted.
+ asserted = sorted([os.path.abspath(i) for i in assert_output_files])
+ actual = sorted([
+ os.path.abspath(os.path.join(self.output_directory, i.GetFilename()))
+ for i in self.res.GetOutputFiles()])
+
+ if asserted != actual:
+ print '''Asserted file list does not match.
+
+Expected output files: %s
+
+Actual output files: %s
+''' % (asserted, actual)
+ return False
+ return True
+
+
+ def GenerateDepfile(self, depfile, depdir):
'''Generate a depfile that contains the imlicit dependencies of the input
grd. The depfile will be in the same format as a makefile, and will contain
references to files relative to |depdir|. It will be put in |depfile|.
@@ -343,19 +392,27 @@
from the directory src/ we will generate a depfile ../out/gen/blah.grd.d
that has the contents
- gen/blah.grd.d: ../src/input1.xtb ../src/input2.xtb
+ gen/blah.h: ../src/input1.xtb ../src/input2.xtb
+
+ Where "gen/blah.h" is the first output (Ninja expects the .d file to list
+ the first output in cases where there is more than one).
Note that all paths in the depfile are relative to ../out, the depdir.
'''
depfile = os.path.abspath(depfile)
depdir = os.path.abspath(depdir)
+ infiles = self.res.GetInputFiles()
+
+ # Get the first output file relative to the depdir.
+ outputs = self.res.GetOutputFiles()
+ output_file = os.path.relpath(os.path.join(
+ self.output_directory, outputs[0].GetFilename()), depdir)
+
# The path prefix to prepend to dependencies in the depfile.
prefix = os.path.relpath(os.getcwd(), depdir)
- # The path that the depfile refers to itself by.
- self_ref_depfile = os.path.relpath(depfile, depdir)
- infiles = self.res.GetInputFiles()
deps_text = ' '.join([os.path.join(prefix, i) for i in infiles])
- depfile_contents = self_ref_depfile + ': ' + deps_text
+
+ depfile_contents = output_file + ': ' + deps_text
self.MakeDirectoriesTo(depfile)
outfile = self.fo_create(depfile, 'wb')
outfile.writelines(depfile_contents)
diff --git a/grit/tool/build_unittest.py b/grit/tool/build_unittest.py
index fd640f7..debe4d4 100644
--- a/grit/tool/build_unittest.py
+++ b/grit/tool/build_unittest.py
@@ -49,15 +49,41 @@
self.failUnless(os.path.isfile(expected_dep_file))
with open(expected_dep_file) as f:
line = f.readline()
- (dep_file_name, deps_string) = line.split(': ')
+ (dep_output_file, deps_string) = line.split(': ')
deps = deps_string.split(' ')
- self.failUnlessEqual(os.path.abspath(expected_dep_file),
- os.path.abspath(os.path.join(output_dir, dep_file_name)),
- "depfile should refer to itself as the depended upon file")
+
+ self.failUnlessEqual("resource.h", dep_output_file)
self.failUnlessEqual(1, len(deps))
self.failUnlessEqual(deps[0],
util.PathFromRoot('grit/testdata/substitute.xmb'))
+ def testAssertOutputs(self):
+ output_dir = tempfile.mkdtemp()
+ class DummyOpts(object):
+ def __init__(self):
+ self.input = util.PathFromRoot('grit/testdata/substitute.grd')
+ self.verbose = False
+ self.extra_verbose = False
+
+ # Incomplete output file list should fail.
+ builder_fail = build.RcBuilder()
+ self.failUnlessEqual(2,
+ builder_fail.Run(DummyOpts(), [
+ '-o', output_dir,
+ '-a', os.path.abspath(
+ os.path.join(output_dir, 'en_generated_resources.rc'))]))
+
+ # Complete output file list should succeed.
+ builder_ok = build.RcBuilder()
+ self.failUnlessEqual(0,
+ builder_ok.Run(DummyOpts(), [
+ '-o', output_dir,
+ '-a', os.path.abspath(
+ os.path.join(output_dir, 'en_generated_resources.rc')),
+ '-a', os.path.abspath(
+ os.path.join(output_dir, 'sv_generated_resources.rc')),
+ '-a', os.path.abspath(
+ os.path.join(output_dir, 'resource.h'))]))
if __name__ == '__main__':
unittest.main()