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
5from copy import deepcopy
6from operator import itemgetter
7
8from third_party.json_schema_compiler.json_parse import OrderedDict, Parse
9
10class ManifestDataSource(object):
11  '''Provides a template with access to manifest properties specific to apps or
12  extensions.
13  '''
14  def __init__(self,
15               compiled_fs_factory,
16               file_system,
17               manifest_path,
18               features_path):
19    self._manifest_path = manifest_path
20    self._features_path = features_path
21    self._file_system = file_system
22    self._cache = compiled_fs_factory.Create(
23        self._CreateManifestData, ManifestDataSource)
24
25  def _ApplyAppsTransformations(self, manifest):
26    manifest['required'][0]['example'] = 'Application'
27    manifest['optional'][-1]['is_last'] = True
28
29  def _ApplyExtensionsTransformations(self, manifest):
30    manifest['optional'][-1]['is_last'] = True
31
32  def _CreateManifestData(self, _, content):
33    '''Take the contents of |_manifest_path| and create apps and extensions
34    versions of a manifest example based on the contents of |_features_path|.
35    '''
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
42    apps = create_manifest_dict()
43    extensions = create_manifest_dict()
44
45    manifest_json = Parse(content)
46    features_json = Parse(self._file_system.ReadSingle(
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
88  def get(self, key):
89    return self._cache.GetFromFile(self._manifest_path)[key]
90