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.
7 from compiled_file_system
import SingleFile
, Unicode
8 from extensions_paths
import API_PATHS
, JSON_TEMPLATES
9 import features_utility
10 from file_system
import FileNotFoundError
11 from future
import Future
12 from third_party
.json_schema_compiler
.json_parse
import Parse
15 _API_FEATURES
= '_api_features.json'
16 _MANIFEST_FEATURES
= '_manifest_features.json'
17 _PERMISSION_FEATURES
= '_permission_features.json'
20 def _GetFeaturePaths(feature_file
, *extra_paths
):
21 paths
= [posixpath
.join(api_path
, feature_file
) for api_path
in API_PATHS
]
22 paths
.extend(extra_paths
)
26 def _AddPlatformsFromDependencies(feature
,
32 'manifest': manifest_features
,
33 'permission': permission_features
,
35 dependencies
= feature
.get('dependencies')
36 if dependencies
is None:
37 return ['apps', 'extensions']
39 for dependency
in dependencies
:
40 dep_type
, dep_name
= dependency
.split(':')
41 dependency_features
= features_map
[dep_type
]
42 dependency_feature
= dependency_features
.get(dep_name
)
43 # If the dependency can't be resolved, it is inaccessible and therefore
45 if dependency_feature
is None:
47 platforms
= platforms
.union(dependency_feature
['platforms'])
48 feature
['platforms'] = list(platforms
)
51 class _FeaturesCache(object):
52 def __init__(self
, file_system
, compiled_fs_factory
, json_paths
):
53 populate
= self
._CreateCache
54 if len(json_paths
) == 1:
55 populate
= SingleFile(populate
)
57 self
._cache
= compiled_fs_factory
.Create(file_system
, populate
, type(self
))
58 self
._text
_cache
= compiled_fs_factory
.ForUnicode(file_system
)
59 self
._json
_path
= json_paths
[0]
60 self
._extra
_paths
= json_paths
[1:]
63 def _CreateCache(self
, _
, features_json
):
64 extra_path_futures
= [self
._text
_cache
.GetFromFile(path
)
65 for path
in self
._extra
_paths
]
66 features
= features_utility
.Parse(Parse(features_json
))
67 for path_future
in extra_path_futures
:
69 extra_json
= path_future
.Get()
70 except FileNotFoundError
:
71 # Not all file system configurations have the extra files.
73 features
= features_utility
.MergedWith(
74 features_utility
.Parse(Parse(extra_json
)), features
)
77 def GetFeatures(self
):
78 if self
._json
_path
is None:
79 return Future(value
={})
80 return self
._cache
.GetFromFile(self
._json
_path
)
83 class FeaturesBundle(object):
84 '''Provides access to properties of API, Manifest, and Permission features.
86 def __init__(self
, file_system
, compiled_fs_factory
, object_store_creator
):
87 self
._api
_cache
= _FeaturesCache(
90 _GetFeaturePaths(_API_FEATURES
))
91 self
._manifest
_cache
= _FeaturesCache(
94 _GetFeaturePaths(_MANIFEST_FEATURES
,
95 posixpath
.join(JSON_TEMPLATES
, 'manifest.json')))
96 self
._permission
_cache
= _FeaturesCache(
99 _GetFeaturePaths(_PERMISSION_FEATURES
,
100 posixpath
.join(JSON_TEMPLATES
, 'permissions.json')))
101 # Namespace the object store by the file system ID because this class is
102 # used by the availability finder cross-channel.
103 # TODO(kalman): Configure this at the ObjectStore level.
104 self
._object
_store
= object_store_creator
.Create(
105 _FeaturesCache
, category
=file_system
.GetIdentity())
107 def GetPermissionFeatures(self
):
108 return self
._permission
_cache
.GetFeatures()
110 def GetManifestFeatures(self
):
111 return self
._manifest
_cache
.GetFeatures()
113 def GetAPIFeatures(self
):
114 api_features
= self
._object
_store
.Get('api_features').Get()
115 if api_features
is not None:
116 return Future(value
=api_features
)
118 api_features_future
= self
._api
_cache
.GetFeatures()
119 manifest_features_future
= self
._manifest
_cache
.GetFeatures()
120 permission_features_future
= self
._permission
_cache
.GetFeatures()
122 api_features
= api_features_future
.Get()
123 manifest_features
= manifest_features_future
.Get()
124 permission_features
= permission_features_future
.Get()
125 # TODO(rockot): Handle inter-API dependencies more gracefully.
126 # Not yet a problem because there is only one such case (windows -> tabs).
127 # If we don't store this value before annotating platforms, inter-API
128 # dependencies will lead to infinite recursion.
129 for feature
in api_features
.itervalues():
130 _AddPlatformsFromDependencies(
131 feature
, api_features
, manifest_features
, permission_features
)
132 self
._object
_store
.Set('api_features', api_features
)
134 return Future(callback
=resolve
)