Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(929)

Side by Side Diff: chrome/common/extensions/docs/server2/manifest_data_source.py

Issue 16410002: Docserver manifest follow up (rewrite) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gen-manifest-try-2
Patch Set: revert and clean up features utility, manifest data source Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 from copy import deepcopy 5 from copy import deepcopy
6 from operator import itemgetter 6 import json
7 7
8 from third_party.json_schema_compiler.json_parse import OrderedDict, Parse 8 from features_utility import FeaturesFromJson, Filter, MergeFeatures
9 from third_party.json_schema_compiler.json_parse import Parse
10
11 def _ListifyAndSortDocs(features, app_name):
12 '''Convert a |feautres| dictionary, and all 'children' dictionaries, into
13 lists recursively. Sort lists first by 'level' then by name.
14 '''
15 def sort_key(item):
16 '''Key function to sort items primarily by level (according to index into
17 levels) then subsort by name.
18 '''
19 levels = ('required', 'recommended', 'only_one', 'optional')
20
21 return (levels.index(item.get('level', 'optional')), item['name'])
22
23 def convert_and_sort(features):
24 for key, value in features.items():
25 if 'example' in value:
26 value['has_example'] = True
27 example = json.dumps(value['example'])
28 if example == '{}':
29 value['example'] = '{...}'
30 elif example == '[]':
31 value['example'] = '[...]'
32 else:
33 value['example'] = example
34
35 if 'children' in value:
36 features[key]['children'] = convert_and_sort(value['children'])
37
38 return sorted(features.values(), key=sort_key)
39
40 name = features['name']
41 name['example'] = name['example'].replace('{{title}}', app_name)
42
43 return convert_and_sort(features)
44
45 def _AddLevelAnnotations(features):
46 '''Add level annotations to |features|. |features| and children lists must be
47 sorted by 'level'. Annotations are added to the first item in a group of
48 features of the same 'level'.
49
50 The last item in a list has 'is_last' set to True.
51 '''
52 annotations = {
53 'required': 'Required',
54 'recommended': 'Recommended',
55 'only_one': 'Pick one (or none)',
56 'optional': 'Optional'
57 }
58
59 def add_annotation(item, annotation):
60 if not 'annotations' in item:
61 item['annotations'] = []
62 item['annotations'].insert(0, annotation)
63
64 def annotate(parent_level, features):
65 current_level = parent_level
66 for item in features:
67 level = item.get('level', 'optional')
68 if level != current_level:
69 add_annotation(item, annotations[level])
70 current_level = level
71 if 'children' in item:
72 annotate(level, item['children'])
73 if features:
74 features[-1]['is_last'] = True
75
76 annotate('required', features)
77 return features
78
79 def _RestructureChildren(features):
80 '''Features whose names are of the form 'parent.child' are moved to be part
81 of the 'parent' dictionary under the key 'children'. Names are changed to
82 the 'child' section of the original name. Applied recursively so that
83 children can have children.
84 '''
85 def add_child(features, parent, child_name, value):
86 value['name'] = child_name
87 if not 'children' in features[parent]:
88 features[parent]['children'] = {}
89 features[parent]['children'][child_name] = value
90
91 def insert_children(features):
92 for name in features.keys():
93 if '.' in name:
94 value = features.pop(name)
95 parent, child_name = name.split('.', 1)
96 add_child(features, parent, child_name, value)
97
98 for value in features.values():
99 if 'children' in value:
100 insert_children(value['children'])
101
102 insert_children(features)
103 return features
9 104
10 class ManifestDataSource(object): 105 class ManifestDataSource(object):
11 '''Provides a template with access to manifest properties specific to apps or 106 '''Provides access to the properties in manifest features.
12 extensions.
13 ''' 107 '''
14 def __init__(self, 108 def __init__(self,
15 compiled_fs_factory, 109 compiled_fs_factory,
16 file_system, 110 file_system,
17 manifest_path, 111 manifest_path,
18 features_path): 112 features_path):
19 self._manifest_path = manifest_path 113 self._manifest_path = manifest_path
20 self._features_path = features_path 114 self._features_path = features_path
21 self._file_system = file_system 115 self._file_system = file_system
22 self._cache = compiled_fs_factory.Create( 116 self._cache = compiled_fs_factory.Create(
23 self._CreateManifestData, ManifestDataSource) 117 self._CreateManifestData, ManifestDataSource)
24 118
25 def _ApplyAppsTransformations(self, manifest): 119 def GetFeatures(self):
26 manifest['required'][0]['example'] = 'Application' 120 '''Returns a dictionary of the contents of |_features_path| merged with
27 manifest['optional'][-1]['is_last'] = True 121 |_manifest_path|.
122 '''
123 manifest_json = Parse(self._file_system.ReadSingle(self._manifest_path))
124 manifest_features = FeaturesModel.FromJson(
125 Parse(self._file_system.ReadSingle(self._features_path)))
28 126
29 def _ApplyExtensionsTransformations(self, manifest): 127 return manifest_features.MergeWith(manifest_json)
30 manifest['optional'][-1]['is_last'] = True 128
31 129
32 def _CreateManifestData(self, _, content): 130 def _CreateManifestData(self, _, content):
33 '''Take the contents of |_manifest_path| and create apps and extensions 131 '''Combine the contents of |_manifest_path| and |_features_path| and filter
34 versions of a manifest example based on the contents of |_features_path|. 132 the results into lists specific to apps or extensions for templates. Marks
133 up features with annotations.
35 ''' 134 '''
36 def create_manifest_dict(): 135 def for_templates(manifest_features, platform):
37 manifest_dict = OrderedDict() 136 return _AddLevelAnnotations(
38 for category in ('required', 'only_one', 'recommended', 'optional'): 137 _ListifyAndSortDocs(
39 manifest_dict[category] = [] 138 _RestructureChildren(Filter(manifest_features, platform)),
40 return manifest_dict 139 app_name=platform.capitalize()))
41 140
42 apps = create_manifest_dict() 141 manifest_json = Parse(self._file_system.ReadSingle(self._manifest_path))
43 extensions = create_manifest_dict() 142 manifest_features = MergeFeatures(
143 FeaturesFromJson(Parse(content)), manifest_json)
44 144
45 manifest_json = Parse(content) 145 return {
46 features_json = Parse(self._file_system.ReadSingle( 146 'apps': for_templates(deepcopy(manifest_features), 'app'),
47 self._features_path)) 147 'extensions': for_templates(manifest_features, 'extension')
48 148 }
49 def add_property(feature, manifest_key, category):
50 '''If |feature|, from features_json, has the correct extension_types, add
51 |manifest_key| to either apps or extensions.
52 '''
53 added = False
54 extension_types = feature['extension_types']
55 if extension_types == 'all' or 'platform_app' in extension_types:
56 apps[category].append(deepcopy(manifest_key))
57 added = True
58 if extension_types == 'all' or 'extension' in extension_types:
59 extensions[category].append(deepcopy(manifest_key))
60 added = True
61 return added
62
63 # Property types are: required, only_one, recommended, and optional.
64 for category in manifest_json:
65 for manifest_key in manifest_json[category]:
66 # If a property is in manifest.json but not _manifest_features, this
67 # will cause an error.
68 feature = features_json[manifest_key['name']]
69 if add_property(feature, manifest_key, category):
70 del features_json[manifest_key['name']]
71
72 # All of the properties left in features_json are assumed to be optional.
73 for feature in features_json.keys():
74 item = features_json[feature]
75 # Handles instances where a features entry is a union with a whitelist.
76 if isinstance(item, list):
77 item = item[0]
78 add_property(item, {'name': feature}, 'optional')
79
80 apps['optional'].sort(key=itemgetter('name'))
81 extensions['optional'].sort(key=itemgetter('name'))
82
83 self._ApplyAppsTransformations(apps)
84 self._ApplyExtensionsTransformations(extensions)
85
86 return {'apps': apps, 'extensions': extensions}
87 149
88 def get(self, key): 150 def get(self, key):
89 return self._cache.GetFromFile(self._manifest_path)[key] 151 return self._cache.GetFromFile(self._features_path)[key]
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698