Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / common / extensions / docs / server2 / manifest_data_source.py
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
3 # found in the LICENSE file.
4
5 from copy import deepcopy
6 import json
7
8 from data_source import DataSource
9 from future import Future
10 from manifest_features import ConvertDottedKeysToNested
11 from platform_util import GetPlatforms, PluralToSingular
12
13
14 def _ListifyAndSortDocs(features, app_name):
15   '''Convert a |feautres| dictionary, and all 'children' dictionaries, into
16   lists recursively. Sort lists first by 'level' then by name.
17   '''
18   def sort_key(item):
19     '''Key function to sort items primarily by level (according to index into
20     levels) then subsort by name.
21     '''
22     levels = ('required', 'recommended', 'only_one', 'optional')
23
24     return (levels.index(item.get('level', 'optional')), item['name'])
25
26   def coerce_example_to_feature(feature):
27     '''To display json in examples more clearly, convert the example of
28     |feature| into the feature format, with a name and children, to be rendered
29     by the templates. Only applicable to examples that are dictionaries.
30     '''
31     if not isinstance(feature.get('example'), dict):
32       if 'example' in feature:
33         feature['example'] = json.dumps(feature['example'])
34       return
35     # Add any keys/value pairs in the dict as children
36     for key, value in feature['example'].iteritems():
37       if not 'children' in feature:
38         feature['children'] = {}
39       feature['children'][key] = { 'name': key, 'example': value }
40     del feature['example']
41     del feature['has_example']
42
43   def convert_and_sort(features):
44     for key, value in features.items():
45       if 'example' in value:
46         value['has_example'] = True
47         example = json.dumps(value['example'])
48         if example == '{}':
49           value['example'] = '{...}'
50         elif example == '[]':
51           value['example'] = '[...]'
52         elif example == '[{}]':
53           value['example'] = '[{...}]'
54         else:
55           coerce_example_to_feature(value)
56       if 'children' in value:
57         features[key]['children'] = convert_and_sort(value['children'])
58     return sorted(features.values(), key=sort_key)
59
60   # Replace {{platform}} in the 'name' manifest property example with
61   # |app_name|, the convention that the normal template rendering uses.
62   # TODO(kalman): Make the example a template and pass this through there.
63   if 'name' in features:
64     name = features['name']
65     name['example'] = name['example'].replace('{{platform}}', app_name)
66
67   features = convert_and_sort(features)
68
69   return features
70
71 def _AddLevelAnnotations(features):
72   '''Add level annotations to |features|. |features| and children lists must be
73   sorted by 'level'. Annotations are added to the first item in a group of
74   features of the same 'level'.
75
76   The last item in a list has 'is_last' set to True.
77   '''
78   annotations = {
79     'required': 'Required',
80     'recommended': 'Recommended',
81     'only_one': 'Pick one (or none)',
82     'optional': 'Optional'
83   }
84
85   def add_annotation(item, annotation):
86     if not 'annotations' in item:
87       item['annotations'] = []
88     item['annotations'].insert(0, annotation)
89
90   def annotate(parent_level, features):
91     current_level = parent_level
92     for item in features:
93       level = item.get('level', 'optional')
94       if level != current_level:
95         add_annotation(item, annotations[level])
96         current_level = level
97       if 'children' in item:
98         annotate(level, item['children'])
99     if features:
100       features[-1]['is_last'] = True
101
102   annotate('required', features)
103   return features
104
105 class ManifestDataSource(DataSource):
106   '''Provides access to the properties in manifest features.
107   '''
108   def __init__(self, server_instance, _):
109     self._platform_bundle = server_instance.platform_bundle
110     self._object_store = server_instance.object_store_creator.Create(
111         ManifestDataSource)
112
113   def _CreateManifestDataForPlatform(self, platform):
114     future_manifest_features = self._platform_bundle.GetFeaturesBundle(
115         platform).GetManifestFeatures()
116     def resolve():
117       manifest_features = future_manifest_features.Get()
118       return _AddLevelAnnotations(_ListifyAndSortDocs(
119           ConvertDottedKeysToNested(deepcopy(manifest_features)),
120           app_name=PluralToSingular(platform).capitalize()))
121     return Future(callback=resolve)
122
123   def _CreateManifestData(self):
124     manifest_data_futures = dict((p, self._CreateManifestDataForPlatform(p))
125                                  for p in GetPlatforms())
126     def resolve():
127       return dict((platform, future.Get())
128                   for platform, future in manifest_data_futures.iteritems())
129     return Future(callback=resolve)
130
131   def _GetCachedManifestData(self):
132     data = self._object_store.Get('manifest_data').Get()
133     if data is None:
134       data = self._CreateManifestData().Get()
135       self._object_store.Set('manifest_data', data)
136     return data
137
138   def Cron(self):
139     return self._CreateManifestData()
140
141   def get(self, key):
142     return self._GetCachedManifestData().get(key)