blob: 3b94f52e3a409a62b1fdc68aacc7bb4a600fef94 [file] [log] [blame]
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from copy import deepcopy
import json
from data_source import DataSource
from future import Future
from manifest_features import ConvertDottedKeysToNested
from platform_util import GetPlatforms, PluralToSingular
def _ListifyAndSortDocs(features, app_name):
'''Convert a |feautres| dictionary, and all 'children' dictionaries, into
lists recursively. Sort lists first by 'level' then by name.
'''
def sort_key(item):
'''Key function to sort items primarily by level (according to index into
levels) then subsort by name.
'''
levels = ('required', 'recommended', 'only_one', 'optional')
return (levels.index(item.get('level', 'optional')), item['name'])
def coerce_example_to_feature(feature):
'''To display json in examples more clearly, convert the example of
|feature| into the feature format, with a name and children, to be rendered
by the templates. Only applicable to examples that are dictionaries.
'''
if not isinstance(feature.get('example'), dict):
if 'example' in feature:
feature['example'] = json.dumps(feature['example'])
return
# Add any keys/value pairs in the dict as children
for key, value in feature['example'].iteritems():
if not 'children' in feature:
feature['children'] = {}
feature['children'][key] = { 'name': key, 'example': value }
del feature['example']
del feature['has_example']
def convert_and_sort(features):
for key, value in features.items():
if 'example' in value:
value['has_example'] = True
example = json.dumps(value['example'])
if example == '{}':
value['example'] = '{...}'
elif example == '[]':
value['example'] = '[...]'
elif example == '[{}]':
value['example'] = '[{...}]'
else:
coerce_example_to_feature(value)
if 'children' in value:
features[key]['children'] = convert_and_sort(value['children'])
return sorted(features.values(), key=sort_key)
# Replace {{platform}} in the 'name' manifest property example with
# |app_name|, the convention that the normal template rendering uses.
# TODO(kalman): Make the example a template and pass this through there.
if 'name' in features:
name = features['name']
name['example'] = name['example'].replace('{{platform}}', app_name)
features = convert_and_sort(features)
return features
def _AddLevelAnnotations(features):
'''Add level annotations to |features|. |features| and children lists must be
sorted by 'level'. Annotations are added to the first item in a group of
features of the same 'level'.
The last item in a list has 'is_last' set to True.
'''
annotations = {
'required': 'Required',
'recommended': 'Recommended',
'only_one': 'Pick one (or none)',
'optional': 'Optional'
}
def add_annotation(item, annotation):
if not 'annotations' in item:
item['annotations'] = []
item['annotations'].insert(0, annotation)
def annotate(parent_level, features):
current_level = parent_level
for item in features:
level = item.get('level', 'optional')
if level != current_level:
add_annotation(item, annotations[level])
current_level = level
if 'children' in item:
annotate(level, item['children'])
if features:
features[-1]['is_last'] = True
annotate('required', features)
return features
class ManifestDataSource(DataSource):
'''Provides access to the properties in manifest features.
'''
def __init__(self, server_instance, _):
self._platform_bundle = server_instance.platform_bundle
self._object_store = server_instance.object_store_creator.Create(
ManifestDataSource)
def _CreateManifestDataForPlatform(self, platform):
future_manifest_features = self._platform_bundle.GetFeaturesBundle(
platform).GetManifestFeatures()
def resolve():
manifest_features = future_manifest_features.Get()
return _AddLevelAnnotations(_ListifyAndSortDocs(
ConvertDottedKeysToNested(deepcopy(manifest_features)),
app_name=PluralToSingular(platform).capitalize()))
return Future(callback=resolve)
def _CreateManifestData(self):
manifest_data_futures = dict((p, self._CreateManifestDataForPlatform(p))
for p in GetPlatforms())
def resolve():
return dict((platform, future.Get())
for platform, future in manifest_data_futures.iteritems())
return Future(callback=resolve)
def _GetCachedManifestData(self):
data = self._object_store.Get('manifest_data').Get()
if data is None:
data = self._CreateManifestData().Get()
self._object_store.Set('manifest_data', data)
return data
def Cron(self):
return self._CreateManifestData()
def get(self, key):
return self._GetCachedManifestData().get(key)