Chromium Code Reviews| 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 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_model import FeaturesModel |
| 9 from third_party.json_schema_compiler.json_parse import Parse | |
| 10 | |
| 11 def _ConvertAndSortDocs(properties, platform): | |
| 12 '''Convert docs and children into lists and sort them, first by level, then | |
| 13 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(properties): | |
| 24 for key, value in properties.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 properties[key]['children'] = convert_and_sort(value['children']) | |
| 37 | |
| 38 return sorted(properties.values(), key=sort_key) | |
| 39 | |
| 40 name = properties['name'] | |
| 41 name['example'] = name['example'].replace('{{title}}', platform.capitalize()) | |
| 42 | |
| 43 return convert_and_sort(properties) | |
| 44 | |
| 45 def _Annotate(properties): | |
| 46 '''Add level annotations to level groups in a manifest property list and | |
| 47 child lists. Requeries a list of properties sorted by level, with children | |
| 48 in sorted lists as well. | |
| 49 ''' | |
| 50 annotations = { | |
| 51 'required': 'Required', | |
| 52 'recommended': 'Recommended', | |
| 53 'only_one': 'Pick one (or none)', | |
| 54 'optional': 'Optional' | |
| 55 } | |
| 56 | |
| 57 def add_annotation(item, annotation): | |
| 58 if not 'annotations' in item: | |
| 59 item['annotations'] = [] | |
| 60 item['annotations'].insert(0, annotation) | |
| 61 | |
| 62 def annotate(parent_level, properties): | |
| 63 current_level = parent_level | |
| 64 for item in properties: | |
| 65 level = item.get('level', 'optional') | |
| 66 if level != current_level: | |
| 67 add_annotation(item, annotations[level]) | |
| 68 current_level = level | |
| 69 if 'children' in item: | |
| 70 annotate(level, item['children']) | |
| 71 if properties: | |
| 72 properties[-1]['is_last'] = True | |
| 73 | |
| 74 annotate('required', properties) | |
| 75 return properties | |
| 9 | 76 |
| 10 class ManifestDataSource(object): | 77 class ManifestDataSource(object): |
| 11 '''Provides a template with access to manifest properties specific to apps or | 78 '''Provides a template with access to manifest properties specific to apps or |
| 12 extensions. | 79 extensions. |
| 13 ''' | 80 ''' |
| 14 def __init__(self, | 81 def __init__(self, |
| 15 compiled_fs_factory, | 82 compiled_fs_factory, |
| 16 file_system, | 83 file_system, |
| 17 manifest_path, | 84 manifest_path, |
| 18 features_path): | 85 features_path): |
| 19 self._manifest_path = manifest_path | 86 self._manifest_path = manifest_path |
| 20 self._features_path = features_path | 87 self._features_path = features_path |
| 21 self._file_system = file_system | 88 self._file_system = file_system |
| 22 self._cache = compiled_fs_factory.Create( | 89 self._cache = compiled_fs_factory.Create( |
| 23 self._CreateManifestData, ManifestDataSource) | 90 self._CreateManifestData, ManifestDataSource) |
| 24 | 91 |
| 25 def _ApplyAppsTransformations(self, manifest): | 92 def _CreateManifestData(self, _, content): |
| 26 manifest['required'][0]['example'] = 'Application' | 93 '''Combine the contents of |_manifest_path| and |_features_path| into a |
| 27 manifest['optional'][-1]['is_last'] = True | 94 master dictionary then create filtered lists to be used by templates. |
| 95 ''' | |
| 96 manifest_json = Parse(content) | |
| 97 manifest_features = FeaturesModel().LoadFeaturesJson( | |
| 98 Parse(self._file_system.ReadSingle(self._features_path))) | |
| 99 manifest_features = manifest_features.MergeWith(manifest_json) | |
| 28 | 100 |
| 29 def _ApplyExtensionsTransformations(self, manifest): | 101 apps_features = ( |
| 30 manifest['optional'][-1]['is_last'] = True | 102 manifest_features.Filter(platform='app').RestructureChildren()) |
| 103 apps_features = _Annotate(_ConvertAndSortDocs(apps_features, 'app')) | |
| 31 | 104 |
| 32 def _CreateManifestData(self, _, content): | 105 extensions_features = ( |
| 33 '''Take the contents of |_manifest_path| and create apps and extensions | 106 manifest_features.Filter(platform='extension').RestructureChildren()) |
| 34 versions of a manifest example based on the contents of |_features_path|. | 107 extensions_features = _Annotate( |
| 35 ''' | 108 _ConvertAndSortDocs(extensions_features, 'extension')) |
|
not at google - send to devlin
2013/07/31 00:36:39
So we should probably be doing the RestructureChil
jshumway
2013/07/31 18:10:28
Done.
| |
| 36 def create_manifest_dict(): | |
| 37 manifest_dict = OrderedDict() | |
| 38 for category in ('required', 'only_one', 'recommended', 'optional'): | |
| 39 manifest_dict[category] = [] | |
| 40 return manifest_dict | |
| 41 | 109 |
| 42 apps = create_manifest_dict() | 110 return { |
| 43 extensions = create_manifest_dict() | 111 'apps': apps_features, |
| 44 | 112 'extensions': extensions_features, |
| 45 manifest_json = Parse(content) | 113 'all_features': manifest_features |
|
not at google - send to devlin
2013/07/31 00:36:39
similar to comment above, I don't think this all f
jshumway
2013/07/31 18:10:28
Done.
| |
| 46 features_json = Parse(self._file_system.ReadSingle( | 114 } |
| 47 self._features_path)) | |
| 48 | |
| 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 | 115 |
| 88 def get(self, key): | 116 def get(self, key): |
| 89 return self._cache.GetFromFile(self._manifest_path)[key] | 117 return self._cache.GetFromFile(self._manifest_path)[key] |
| OLD | NEW |