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

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: more idiomatic/less explicit copying 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 import json
6 from operator import itemgetter
7 6
8 from third_party.json_schema_compiler.json_parse import OrderedDict, Parse 7 import features_utility as features
8 from third_party.json_schema_compiler.json_parse import Parse
9
10 def _ListifyAndSortDocs(features, app_name):
11 '''Convert a |feautres| dictionary, and all 'children' dictionaries, into
12 lists recursively. Sort lists first by 'level' then by name.
13 '''
14 def sort_key(item):
15 '''Key function to sort items primarily by level (according to index into
16 levels) then subsort by name.
17 '''
18 levels = ('required', 'recommended', 'only_one', 'optional')
19
20 return (levels.index(item.get('level', 'optional')), item['name'])
21
22 def convert_and_sort(features):
23 for key, value in features.items():
24 if 'example' in value:
25 value['has_example'] = True
26 example = json.dumps(value['example'])
27 if example == '{}':
28 value['example'] = '{...}'
29 elif example == '[]':
30 value['example'] = '[...]'
31 else:
32 value['example'] = example
33
34 if 'children' in value:
35 features[key]['children'] = convert_and_sort(value['children'])
36
37 return sorted(features.values(), key=sort_key)
38
39 name = features['name']
40 name['example'] = name['example'].replace('{{title}}', app_name)
41
42 return convert_and_sort(features)
43
44 def _AddLevelAnnotations(features):
45 '''Add level annotations to |features|. |features| and children lists must be
46 sorted by 'level'. Annotations are added to the first item in a group of
47 features of the same 'level'.
48
49 The last item in a list has 'is_last' set to True.
50 '''
51 annotations = {
52 'required': 'Required',
53 'recommended': 'Recommended',
54 'only_one': 'Pick one (or none)',
55 'optional': 'Optional'
56 }
57
58 def add_annotation(item, annotation):
59 if not 'annotations' in item:
60 item['annotations'] = []
61 item['annotations'].insert(0, annotation)
62
63 def annotate(parent_level, features):
64 current_level = parent_level
65 for item in features:
66 level = item.get('level', 'optional')
67 if level != current_level:
68 add_annotation(item, annotations[level])
69 current_level = level
70 if 'children' in item:
71 annotate(level, item['children'])
72 if features:
73 features[-1]['is_last'] = True
74
75 annotate('required', features)
76 return features
77
78 def _RestructureChildren(features):
79 '''Features whose names are of the form 'parent.child' are moved to be part
80 of the 'parent' dictionary under the key 'children'. Names are changed to
81 the 'child' section of the original name. Applied recursively so that
82 children can have children.
83 '''
84 def add_child(features, parent, child_name, value):
85 value['name'] = child_name
86 if not 'children' in features[parent]:
87 features[parent]['children'] = {}
88 features[parent]['children'][child_name] = value
89
90 def insert_children(features):
91 for name in features.keys():
92 if '.' in name:
93 value = features.pop(name)
94 parent, child_name = name.split('.', 1)
95 add_child(features, parent, child_name, value)
96
97 for value in features.values():
98 if 'children' in value:
99 insert_children(value['children'])
100
101 insert_children(features)
102 return features
9 103
10 class ManifestDataSource(object): 104 class ManifestDataSource(object):
11 '''Provides a template with access to manifest properties specific to apps or 105 '''Provides access to the properties in manifest features.
12 extensions.
13 ''' 106 '''
14 def __init__(self, 107 def __init__(self,
15 compiled_fs_factory, 108 compiled_fs_factory,
16 file_system, 109 file_system,
17 manifest_path, 110 manifest_path,
18 features_path): 111 features_path):
19 self._manifest_path = manifest_path 112 self._manifest_path = manifest_path
20 self._features_path = features_path 113 self._features_path = features_path
21 self._file_system = file_system 114 self._file_system = file_system
22 self._cache = compiled_fs_factory.Create( 115 self._cache = compiled_fs_factory.Create(
23 self._CreateManifestData, ManifestDataSource) 116 self._CreateManifestData, ManifestDataSource)
24 117
25 def _ApplyAppsTransformations(self, manifest): 118 def GetFeatures(self):
26 manifest['required'][0]['example'] = 'Application' 119 '''Returns a dictionary of the contents of |_features_path| merged with
27 manifest['optional'][-1]['is_last'] = True 120 |_manifest_path|.
121 '''
122 manifest_json = Parse(self._file_system.ReadSingle(self._manifest_path))
123 manifest_features = FeaturesModel.FromJson(
124 Parse(self._file_system.ReadSingle(self._features_path)))
28 125
29 def _ApplyExtensionsTransformations(self, manifest): 126 return manifest_features.MergeWith(manifest_json)
30 manifest['optional'][-1]['is_last'] = True 127
31 128
32 def _CreateManifestData(self, _, content): 129 def _CreateManifestData(self, _, content):
33 '''Take the contents of |_manifest_path| and create apps and extensions 130 '''Combine the contents of |_manifest_path| and |_features_path| and filter
34 versions of a manifest example based on the contents of |_features_path|. 131 the results into lists specific to apps or extensions for templates. Marks
132 up features with annotations.
35 ''' 133 '''
36 def create_manifest_dict(): 134 def for_templates(manifest_features, platform):
37 manifest_dict = OrderedDict() 135 return _AddLevelAnnotations(
38 for category in ('required', 'only_one', 'recommended', 'optional'): 136 _ListifyAndSortDocs(
39 manifest_dict[category] = [] 137 _RestructureChildren(
40 return manifest_dict 138 features.Filtered(manifest_features, platform)),
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 = features.MergedWith(
143 features.Parse(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(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