OLD | NEW |
---|---|
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 ''' | 5 ''' |
6 Provides a Manifest Feature abstraction, similar to but more strict than the | 6 Provides a Manifest Feature abstraction, similar to but more strict than the |
7 Feature schema (see feature_utility.py). | 7 Feature schema (see feature_utility.py). |
8 | 8 |
9 Each Manifest Feature has a 'level' in addition to the keys defined in a | 9 Each Manifest Feature has a 'level' in addition to the keys defined in a |
10 Feature. 'level' can be 'required', 'only_one', 'recommended', or 'optional', | 10 Feature. 'level' can be 'required', 'only_one', 'recommended', or 'optional', |
11 indicating how an app or extension should define a manifest property. If 'level' | 11 indicating how an app or extension should define a manifest property. If 'level' |
12 is missing, 'optional' is assumed. | 12 is missing, 'optional' is assumed. |
13 ''' | 13 ''' |
14 | 14 |
15 import json | |
16 | |
17 from features import Features | |
15 import features_utility | 18 import features_utility |
19 from third_party.json_schema_compiler.json_parse import Parse | |
16 | 20 |
17 def CreateManifestFeatures(features_json, manifest_json, filter_platform=None): | 21 def CreateManifestFeatures(features_json, manifest_json, filter_platform=None): |
18 '''Create a manifest features dictionary by normalizing |features_json| and | 22 '''Create a manifest features dictionary by normalizing |features_json| and |
19 merging it with |manifest_json|. If filter_platform is 'app' or 'extension' | 23 merging it with |manifest_json|. If filter_platform is 'app' or 'extension' |
20 then irrelevant features will be removed. | 24 then irrelevant features will be removed. |
21 ''' | 25 ''' |
22 assert filter_platform in ['app', 'extension', None] | 26 assert filter_platform in ['app', 'extension', None] |
23 manifest_features = features_utility.MergedWith( | 27 manifest_features = features_utility.MergedWith( |
24 features_utility.Parse(features_json), manifest_json) | 28 features_utility.Parse(features_json), manifest_json) |
25 | 29 |
(...skipping 27 matching lines...) Expand all Loading... | |
53 value = features.pop(name) | 57 value = features.pop(name) |
54 parent, child_name = name.split('.', 1) | 58 parent, child_name = name.split('.', 1) |
55 add_child(features, parent, child_name, value) | 59 add_child(features, parent, child_name, value) |
56 | 60 |
57 for value in features.values(): | 61 for value in features.values(): |
58 if 'children' in value: | 62 if 'children' in value: |
59 insert_children(value['children']) | 63 insert_children(value['children']) |
60 | 64 |
61 insert_children(features) | 65 insert_children(features) |
62 return features | 66 return features |
67 | |
68 def _ListifyAndSortDocs(features, app_name): | |
not at google - send to devlin
2013/09/23 18:31:30
most of this code is specifically for passing to t
| |
69 '''Convert a |features| dictionary, and all 'children' dictionaries, into | |
70 lists recursively. Sort lists first by 'level' then by name. | |
71 ''' | |
72 def sort_key(item): | |
73 '''Key function to sort items primarily by level (according to index into | |
74 levels) then subsort by name. | |
75 ''' | |
76 levels = ('required', 'recommended', 'only_one', 'optional') | |
77 | |
78 return (levels.index(item.get('level', 'optional')), item['name']) | |
79 | |
80 def coerce_example_to_feature(feature): | |
81 '''To display json in examples more clearly, convert the example of | |
82 |feature| into the feature format, with a name and children, to be rendered | |
83 by the templates. Only applicable to examples that are dictionaries. | |
84 ''' | |
85 if not isinstance(feature.get('example'), dict): | |
86 if 'example' in feature: | |
87 feature['example'] = json.dumps(feature['example']) | |
88 return | |
89 # Add any keys/value pairs in the dict as children | |
90 for key, value in feature['example'].iteritems(): | |
91 if not 'children' in feature: | |
92 feature['children'] = {} | |
93 feature['children'][key] = { 'name': key, 'example': value } | |
94 del feature['example'] | |
95 del feature['has_example'] | |
96 | |
97 def convert_and_sort(features): | |
98 for key, value in features.items(): | |
99 if 'example' in value: | |
100 value['has_example'] = True | |
101 example = json.dumps(value['example']) | |
102 if example == '{}': | |
103 value['example'] = '{...}' | |
104 elif example == '[]': | |
105 value['example'] = '[...]' | |
106 else: | |
107 coerce_example_to_feature(value) | |
108 if 'children' in value: | |
109 features[key]['children'] = convert_and_sort(value['children']) | |
110 return sorted(features.values(), key=sort_key) | |
111 | |
112 # Replace {{title}} in the 'name' manifest property example with |app_name| | |
113 if 'name' in features: | |
114 name = features['name'] | |
115 name['example'] = name['example'].replace('{{title}}', app_name) | |
116 | |
117 features = convert_and_sort(features) | |
118 | |
119 return features | |
120 | |
121 def _AddLevelAnnotations(features): | |
122 '''Add level annotations to |features|. |features| and children lists must be | |
123 sorted by 'level'. Annotations are added to the first item in a group of | |
124 features of the same 'level'. | |
125 | |
126 The last item in a list has 'is_last' set to True. | |
127 ''' | |
128 annotations = { | |
129 'required': 'Required', | |
130 'recommended': 'Recommended', | |
131 'only_one': 'Pick one (or none)', | |
132 'optional': 'Optional' | |
133 } | |
134 | |
135 def add_annotation(item, annotation): | |
136 if not 'annotations' in item: | |
137 item['annotations'] = [] | |
138 item['annotations'].insert(0, annotation) | |
139 | |
140 def annotate(parent_level, features): | |
141 current_level = parent_level | |
142 for item in features: | |
143 level = item.get('level', 'optional') | |
144 if level != current_level: | |
145 add_annotation(item, annotations[level]) | |
146 current_level = level | |
147 if 'children' in item: | |
148 annotate(level, item['children']) | |
149 if features: | |
150 features[-1]['is_last'] = True | |
151 | |
152 annotate('required', features) | |
153 return features | |
154 | |
155 class ManifestFeatures(Features): | |
156 '''Subclass of Features to provide special annotation and ordering as well as | |
157 the merging of _manifest_features.json data with manifest.json. | |
158 ''' | |
159 def __init__(self, | |
160 compiled_fs_factory, | |
161 manifest_features_path, | |
162 file_system, | |
163 manifest_json_path): | |
164 self._file_system = file_system | |
165 self._manifest_json_path = manifest_json_path | |
166 super(ManifestFeatures, self).__init__(compiled_fs_factory, | |
167 manifest_features_path) | |
168 | |
169 def Parse(self, features_json): | |
170 manifest_json = Parse( | |
171 self._file_system.ReadSingle(self._manifest_json_path)) | |
172 return CreateManifestFeatures(features_json, manifest_json) | |
173 | |
174 def FilterByPlatform(self, features, platform): | |
175 features = super(ManifestFeatures, self).FilterByPlatform(features, | |
176 platform) | |
177 return _AddLevelAnnotations( | |
178 _ListifyAndSortDocs(ConvertDottedKeysToNested(features), | |
179 app_name=platform.capitalize())) | |
OLD | NEW |