features_bundle.py revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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 5import features_utility 6import svn_constants 7from third_party.json_schema_compiler.json_parse import Parse 8 9 10def _AddPlatformsFromDependencies(feature, features_bundle): 11 features_map = { 12 'api': features_bundle.GetAPIFeatures(), 13 'manifest': features_bundle.GetManifestFeatures(), 14 'permission': features_bundle.GetPermissionFeatures() 15 } 16 dependencies = feature.get('dependencies') 17 if dependencies is None: 18 return ['apps', 'extensions'] 19 platforms = set() 20 for dependency in dependencies: 21 dep_type, dep_name = dependency.split(':') 22 dependency_features = features_map[dep_type] 23 dependency_feature = dependency_features.get(dep_name) 24 # If the dependency can't be resolved, it is inaccessible and therefore 25 # so is this feature. 26 if dependency_feature is None: 27 return [] 28 platforms = platforms.union(dependency_feature['platforms']) 29 feature['platforms'] = list(platforms) 30 31 32class _FeaturesCache(object): 33 def __init__(self, file_system, compiled_fs_factory, *json_paths): 34 self._file_system = file_system 35 self._cache = compiled_fs_factory.Create( 36 file_system, self._CreateCache, type(self)) 37 self._json_path = json_paths[0] 38 self._extra_paths = json_paths[1:] 39 40 def _CreateCache(self, _, features_json): 41 features = features_utility.Parse(Parse(features_json)) 42 for path in self._extra_paths: 43 extra_json = self._file_system.ReadSingle(path).Get() 44 features = features_utility.MergedWith( 45 features_utility.Parse(Parse(extra_json)), features) 46 return features 47 48 def GetFeatures(self): 49 if self._json_path is None: 50 return {} 51 return self._cache.GetFromFile(self._json_path).Get() 52 53 54class FeaturesBundle(object): 55 '''Provides access to properties of API, Manifest, and Permission features. 56 ''' 57 def __init__(self, file_system, compiled_fs_factory, object_store_creator): 58 self._api_cache = _FeaturesCache( 59 file_system, 60 compiled_fs_factory, 61 svn_constants.API_FEATURES_PATH) 62 self._manifest_cache = _FeaturesCache( 63 file_system, 64 compiled_fs_factory, 65 svn_constants.MANIFEST_FEATURES_PATH, 66 svn_constants.MANIFEST_JSON_PATH) 67 self._permission_cache = _FeaturesCache( 68 file_system, 69 compiled_fs_factory, 70 svn_constants.PERMISSION_FEATURES_PATH, 71 svn_constants.PERMISSIONS_JSON_PATH) 72 self._object_store = object_store_creator.Create(_FeaturesCache, 'features') 73 74 def GetPermissionFeatures(self): 75 return self._permission_cache.GetFeatures() 76 77 def GetManifestFeatures(self): 78 return self._manifest_cache.GetFeatures() 79 80 def GetAPIFeatures(self): 81 api_features = self._object_store.Get('api_features').Get() 82 if api_features is None: 83 api_features = self._api_cache.GetFeatures() 84 # TODO(rockot): Handle inter-API dependencies more gracefully. 85 # Not yet a problem because there is only one such case (windows -> tabs). 86 # If we don't store this value before annotating platforms, inter-API 87 # dependencies will lead to infinite recursion. 88 self._object_store.Set('api_features', api_features) 89 for feature in api_features.itervalues(): 90 _AddPlatformsFromDependencies(feature, self) 91 self._object_store.Set('api_features', api_features) 92 return api_features 93