summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-27 20:02:46 +0000
committerkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-27 20:02:46 +0000
commit206ebea228b75fd6aa0f7d2867736799f4cadc56 (patch)
tree25bc16b76c739a6e8da5ff24d4c2468ab0b240ec
parent957cd5a210873c03233236dc038277a83a6069f9 (diff)
downloadchromium_src-206ebea228b75fd6aa0f7d2867736799f4cadc56.zip
chromium_src-206ebea228b75fd6aa0f7d2867736799f4cadc56.tar.gz
chromium_src-206ebea228b75fd6aa0f7d2867736799f4cadc56.tar.bz2
Docs: Use the FeaturesBundle for all things features rather than
re-implementing similar logic in several places. This fixes a bug with the commands API too (and desktopCapture, apparently). BUG=357192 R=rockot@chromium.org NOTRY=true Review URL: https://codereview.chromium.org/212623015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@259958 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/common/extensions/docs/server2/api_data_source.py39
-rwxr-xr-xchrome/common/extensions/docs/server2/api_data_source_test.py30
-rw-r--r--chrome/common/extensions/docs/server2/app.yaml2
-rw-r--r--chrome/common/extensions/docs/server2/availability_finder.py77
-rw-r--r--chrome/common/extensions/docs/server2/cron.yaml2
-rw-r--r--chrome/common/extensions/docs/server2/features_bundle.py13
-rw-r--r--chrome/common/extensions/docs/server2/server_instance.py1
-rw-r--r--chrome/common/extensions/docs/server2/test_data/api_data_source/canned_trunk_fs.py4
-rw-r--r--chrome/common/extensions/docs/server2/test_data/canned_data.py13
-rw-r--r--chrome/common/extensions/docs/templates/intros/commands.html4
10 files changed, 94 insertions, 91 deletions
diff --git a/chrome/common/extensions/docs/server2/api_data_source.py b/chrome/common/extensions/docs/server2/api_data_source.py
index b4d7358..ebb0c24 100644
--- a/chrome/common/extensions/docs/server2/api_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_data_source.py
@@ -8,8 +8,7 @@ import os
import posixpath
from environment import IsPreviewServer
-from extensions_paths import (
- API_FEATURES, JSON_TEMPLATES, PRIVATE_TEMPLATES)
+from extensions_paths import JSON_TEMPLATES, PRIVATE_TEMPLATES
import third_party.json_schema_compiler.json_parse as json_parse
import third_party.json_schema_compiler.model as model
from environment import IsPreviewServer
@@ -74,6 +73,7 @@ class _JSCModel(object):
availability_finder,
json_cache,
template_cache,
+ features_bundle,
event_byname_function):
self._ref_resolver = ref_resolver
self._disable_refs = disable_refs
@@ -82,7 +82,7 @@ class _JSCModel(object):
posixpath.join(JSON_TEMPLATES, 'api_availabilities.json'))
self._intro_tables = json_cache.GetFromFile(
posixpath.join(JSON_TEMPLATES, 'intro_tables.json'))
- self._api_features = json_cache.GetFromFile(API_FEATURES)
+ self._api_features = features_bundle.GetAPIFeatures()
self._template_cache = template_cache
self._event_byname_function = event_byname_function
self._namespace = api_models.GetModel(api_name).Get()
@@ -386,28 +386,20 @@ class _JSCModel(object):
# Devtools aren't in _api_features. If we're dealing with devtools, bail.
if 'devtools' in self._namespace.name:
return []
- feature = self._api_features.Get().get(self._namespace.name)
- assert feature, ('"%s" not found in _api_features.json.'
- % self._namespace.name)
-
- # TODO(tbarzic, kalman): Move this logic into features_utility.
- if isinstance(feature, list):
- dependencies_set = set()
- for subfeature in feature:
- dependencies_set.update(subfeature.get('dependencies', ()))
- dependencies = list(dependencies_set)
- else:
- dependencies = feature.get('dependencies')
- if dependencies is None:
- return []
- def make_code_node(text):
- return { 'class': 'code', 'text': text }
+ api_feature = self._api_features.Get().get(self._namespace.name)
+ if not api_feature:
+ logging.error('"%s" not found in _api_features.json' %
+ self._namespace.name)
+ return []
permissions_content = []
manifest_content = []
def categorize_dependency(dependency):
+ def make_code_node(text):
+ return { 'class': 'code', 'text': text }
+
context, name = dependency.split(':', 1)
if context == 'permission':
permissions_content.append(make_code_node('"%s"' % name))
@@ -419,10 +411,10 @@ class _JSCModel(object):
for transitive_dependency in transitive_dependencies:
categorize_dependency(transitive_dependency)
else:
- raise ValueError('Unrecognized dependency for %s: %s' % (
- self._namespace.name, context))
+ logging.error('Unrecognized dependency for %s: %s' %
+ (self._namespace.name, context))
- for dependency in dependencies:
+ for dependency in api_feature.get('dependencies', ()):
categorize_dependency(dependency)
dependency_rows = []
@@ -494,11 +486,13 @@ class APIDataSource(object):
file_system,
availability_finder,
api_models,
+ features_bundle,
object_store_creator):
self._json_cache = compiled_fs_factory.ForJson(file_system)
self._template_cache = compiled_fs_factory.ForTemplates(file_system)
self._availability_finder = availability_finder
self._api_models = api_models
+ self._features_bundle = features_bundle
self._model_cache_refs = object_store_creator.Create(
APIDataSource, 'model-cache-refs')
self._model_cache_no_refs = object_store_creator.Create(
@@ -558,6 +552,7 @@ class APIDataSource(object):
self._availability_finder,
self._json_cache,
self._template_cache,
+ self._features_bundle,
self._LoadEventByName).ToDict()
self._GetModelCache(disable_refs).Set(api_name, jsc_model)
diff --git a/chrome/common/extensions/docs/server2/api_data_source_test.py b/chrome/common/extensions/docs/server2/api_data_source_test.py
index 47c4992b..e842576 100755
--- a/chrome/common/extensions/docs/server2/api_data_source_test.py
+++ b/chrome/common/extensions/docs/server2/api_data_source_test.py
@@ -13,6 +13,8 @@ from api_data_source import (_JSCModel,
_GetEventByNameFromEvents)
from branch_utility import ChannelInfo
from extensions_paths import CHROME_EXTENSIONS
+from fake_host_file_system_provider import FakeHostFileSystemProvider
+from features_bundle import FeaturesBundle
from file_system import FileNotFoundError
from future import Future
from object_store_creator import ObjectStoreCreator
@@ -41,19 +43,6 @@ class _FakeAvailabilityFinder(object):
return ChannelInfo('stable', '396', 5)
-class _FakeHostFileSystemProvider(object):
-
- def __init__(self, file_system_data):
- self._file_system_data = file_system_data
-
- def GetTrunk(self):
- return self.GetBranch('trunk')
-
- @memoize
- def GetBranch(self, branch):
- return TestFileSystem(self._file_system_data[str(branch)])
-
-
class _FakeSamplesDataSource(object):
def Create(self, request):
@@ -97,13 +86,16 @@ class APIDataSourceTest(unittest.TestCase):
server_instance = ServerInstance.ForTest(
TestFileSystem(CANNED_TRUNK_FS_DATA, relative_to=CHROME_EXTENSIONS))
- self._json_cache = server_instance.compiled_fs_factory.ForJson(
- server_instance.host_file_system_provider.GetTrunk())
+ file_system = server_instance.host_file_system_provider.GetTrunk()
+ self._json_cache = server_instance.compiled_fs_factory.ForJson(file_system)
+ self._features_bundle = FeaturesBundle(file_system,
+ server_instance.compiled_fs_factory,
+ server_instance.object_store_creator)
self._api_models = server_instance.api_models
# Used for testGetApiAvailability() so that valid-ish data is processed.
server_instance = ServerInstance.ForTest(
- file_system_provider=_FakeHostFileSystemProvider(
+ file_system_provider=FakeHostFileSystemProvider(
CANNED_API_FILE_SYSTEM_DATA))
self._avail_api_models = server_instance.api_models
self._avail_json_cache = server_instance.compiled_fs_factory.ForJson(
@@ -131,6 +123,7 @@ class APIDataSourceTest(unittest.TestCase):
_FakeAvailabilityFinder(),
self._json_cache,
_FakeTemplateCache(),
+ self._features_bundle,
None).ToDict()
self.assertEquals('type-TypeA', dict_['types'][0]['id'])
self.assertEquals('property-TypeA-b',
@@ -148,6 +141,7 @@ class APIDataSourceTest(unittest.TestCase):
_FakeAvailabilityFinder(),
self._json_cache,
_FakeTemplateCache(),
+ self._features_bundle,
None).ToDict()
self.assertEquals(expected_json, dict_)
@@ -164,6 +158,7 @@ class APIDataSourceTest(unittest.TestCase):
_FakeAvailabilityFinder(),
self._json_cache,
_FakeTemplateCache(),
+ self._features_bundle,
None).ToDict()
self.assertEquals(_MakeLink('ref_test.html#type-type2', 'type2'),
_GetType(dict_, 'type1')['description'])
@@ -194,6 +189,7 @@ class APIDataSourceTest(unittest.TestCase):
self._avail_finder,
self._avail_json_cache,
_FakeTemplateCache(),
+ self._features_bundle,
None)
self.assertEquals(availability, model._GetApiAvailability())
@@ -205,6 +201,7 @@ class APIDataSourceTest(unittest.TestCase):
_FakeAvailabilityFinder(),
self._json_cache,
_FakeTemplateCache(),
+ self._features_bundle,
None)
expected_list = [
{ 'title': 'Description',
@@ -277,6 +274,7 @@ class APIDataSourceTest(unittest.TestCase):
_FakeAvailabilityFinder(),
self._json_cache,
_FakeTemplateCache(),
+ self._features_bundle,
self._FakeLoadAddRulesSchema).ToDict()
# Check that the first event has the addRulesFunction defined.
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index 324f88c5..325d09d 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
application: chrome-apps-doc
-version: 3-14-5
+version: 3-15-0
runtime: python27
api_version: 1
threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/availability_finder.py b/chrome/common/extensions/docs/server2/availability_finder.py
index 138fe8a..a5bba8e 100644
--- a/chrome/common/extensions/docs/server2/availability_finder.py
+++ b/chrome/common/extensions/docs/server2/availability_finder.py
@@ -7,9 +7,9 @@ import posixpath
from api_schema_graph import APISchemaGraph
from branch_utility import BranchUtility
-from extensions_paths import (
- API, CHROME_API, JSON_TEMPLATES, API_FEATURES, MANIFEST_FEATURES,
- PERMISSION_FEATURES)
+from extensions_paths import API, CHROME_API, JSON_TEMPLATES
+from features_bundle import FeaturesBundle
+import features_utility
from file_system import FileNotFoundError
from third_party.json_schema_compiler.model import UnixName
@@ -27,34 +27,12 @@ _EXTENSION_API_MAX_VERSION = 17
_SVN_MIN_VERSION = 5
-def _GetChannelFromFeatures(api_name, json_fs, filename):
- '''Finds API channel information from the features |filename| within the the
- given |json_fs|. Returns None if channel information for the API cannot be
- located.
+def _GetChannelFromFeatures(api_name, features):
+ '''Finds API channel information for |api_name| from |features|.
+ Returns None if channel information for the API cannot be located.
'''
- feature = json_fs.GetFromFile(filename).Get().get(api_name)
- if feature is None:
- return None
- if isinstance(feature, Mapping):
- # The channel information exists as a solitary dict.
- return feature.get('channel')
- # The channel information dict is nested within a list for whitelisting
- # purposes. Take the newest channel out of all of the entries.
- return BranchUtility.NewestChannel(entry.get('channel') for entry in feature)
-
-
-def _GetChannelFromApiFeatures(api_name, json_fs):
- return _GetChannelFromFeatures(api_name, json_fs, API_FEATURES)
-
-
-def _GetChannelFromManifestFeatures(api_name, json_fs):
- # _manifest_features.json uses unix_style API names.
- api_name = UnixName(api_name)
- return _GetChannelFromFeatures(api_name, json_fs, MANIFEST_FEATURES)
-
-
-def _GetChannelFromPermissionFeatures(api_name, json_fs):
- return _GetChannelFromFeatures(api_name, json_fs, PERMISSION_FEATURES)
+ feature = features.Get().get(api_name)
+ return feature.get('channel') if feature else None
class AvailabilityFinder(object):
@@ -154,19 +132,21 @@ class AvailabilityFinder(object):
if version < _SVN_MIN_VERSION:
# SVN data isn't available below this version.
return False
+ features_bundle = self._CreateFeaturesBundle(file_system)
available_channel = None
- json_fs = self._compiled_fs_factory.ForJson(file_system)
if version >= _API_FEATURES_MIN_VERSION:
# The _api_features.json file first appears in version 28 and should be
# the most reliable for finding API availability.
- available_channel = _GetChannelFromApiFeatures(api_name, json_fs)
+ available_channel = self._GetChannelFromApiFeatures(api_name,
+ features_bundle)
if version >= _ORIGINAL_FEATURES_MIN_VERSION:
# The _permission_features.json and _manifest_features.json files are
# present in Chrome 20 and onwards. Use these if no information could be
# found using _api_features.json.
- available_channel = available_channel or (
- _GetChannelFromPermissionFeatures(api_name, json_fs)
- or _GetChannelFromManifestFeatures(api_name, json_fs))
+ available_channel = (
+ available_channel or
+ self._GetChannelFromPermissionFeatures(api_name, features_bundle) or
+ self._GetChannelFromManifestFeatures(api_name, features_bundle))
if available_channel is not None:
return available_channel == 'stable'
if version >= _SVN_MIN_VERSION:
@@ -180,10 +160,11 @@ class AvailabilityFinder(object):
back to checking the file system for API schema existence, to determine
whether or not an API is available on the given channel, |channel_info|.
'''
- json_fs = self._compiled_fs_factory.ForJson(file_system)
- available_channel = (_GetChannelFromApiFeatures(api_name, json_fs)
- or _GetChannelFromPermissionFeatures(api_name, json_fs)
- or _GetChannelFromManifestFeatures(api_name, json_fs))
+ features_bundle = self._CreateFeaturesBundle(file_system)
+ available_channel = (
+ self._GetChannelFromApiFeatures(api_name, features_bundle) or
+ self._GetChannelFromPermissionFeatures(api_name, features_bundle) or
+ self._GetChannelFromManifestFeatures(api_name, features_bundle))
if (available_channel is None and
self._HasApiSchema(api_name, file_system, channel_info.version)):
# If an API is not represented in any of the _features files, but exists
@@ -196,6 +177,24 @@ class AvailabilityFinder(object):
channel_info.channel))
return available_channel is not None and newest == channel_info.channel
+ def _CreateFeaturesBundle(self, file_system):
+ return FeaturesBundle(file_system,
+ self._compiled_fs_factory,
+ self._object_store_creator)
+
+ def _GetChannelFromApiFeatures(self, api_name, features_bundle):
+ return _GetChannelFromFeatures(api_name, features_bundle.GetAPIFeatures())
+
+ def _GetChannelFromManifestFeatures(self, api_name, features_bundle):
+ # _manifest_features.json uses unix_style API names.
+ api_name = UnixName(api_name)
+ return _GetChannelFromFeatures(api_name,
+ features_bundle.GetManifestFeatures())
+
+ def _GetChannelFromPermissionFeatures(self, api_name, features_bundle):
+ return _GetChannelFromFeatures(api_name,
+ features_bundle.GetPermissionFeatures())
+
def _CheckApiAvailability(self, api_name, file_system, channel_info):
'''Determines the availability for an API at a certain version of Chrome.
Two branches of logic are used depending on whether or not the API is
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml
index aff29da..a8feaa7 100644
--- a/chrome/common/extensions/docs/server2/cron.yaml
+++ b/chrome/common/extensions/docs/server2/cron.yaml
@@ -2,4 +2,4 @@ cron:
- description: Repopulates all cached data.
url: /_cron
schedule: every 5 minutes
- target: 3-14-5
+ target: 3-15-0
diff --git a/chrome/common/extensions/docs/server2/features_bundle.py b/chrome/common/extensions/docs/server2/features_bundle.py
index 5d76cfe..b98bdff 100644
--- a/chrome/common/extensions/docs/server2/features_bundle.py
+++ b/chrome/common/extensions/docs/server2/features_bundle.py
@@ -8,6 +8,7 @@ from compiled_file_system import Unicode
from extensions_paths import (
API_FEATURES, JSON_TEMPLATES, MANIFEST_FEATURES, PERMISSION_FEATURES)
import features_utility
+from file_system import FileNotFoundError
from future import Future
from third_party.json_schema_compiler.json_parse import Parse
@@ -51,7 +52,11 @@ class _FeaturesCache(object):
for path in self._extra_paths]
features = features_utility.Parse(Parse(features_json))
for path_future in extra_path_futures:
- extra_json = path_future.Get()
+ try:
+ extra_json = path_future.Get()
+ except FileNotFoundError:
+ # Not all file system configurations have the extra files.
+ continue
features = features_utility.MergedWith(
features_utility.Parse(Parse(extra_json)), features)
return features
@@ -80,7 +85,11 @@ class FeaturesBundle(object):
compiled_fs_factory,
PERMISSION_FEATURES,
posixpath.join(JSON_TEMPLATES, 'permissions.json'))
- self._object_store = object_store_creator.Create(_FeaturesCache, 'features')
+ # Namespace the object store by the file system ID because this class is
+ # used by the availability finder cross-channel.
+ # TODO(kalman): Configure this at the ObjectStore level.
+ self._object_store = object_store_creator.Create(
+ _FeaturesCache, category=file_system.GetIdentity())
def GetPermissionFeatures(self):
return self._permission_cache.GetFeatures()
diff --git a/chrome/common/extensions/docs/server2/server_instance.py b/chrome/common/extensions/docs/server2/server_instance.py
index 13f4f20..7894f77 100644
--- a/chrome/common/extensions/docs/server2/server_instance.py
+++ b/chrome/common/extensions/docs/server2/server_instance.py
@@ -98,6 +98,7 @@ class ServerInstance(object):
host_fs_at_trunk,
self.availability_finder,
self.api_models,
+ self.features_bundle,
self.object_store_creator)
self.ref_resolver_factory = ReferenceResolver.Factory(
diff --git a/chrome/common/extensions/docs/server2/test_data/api_data_source/canned_trunk_fs.py b/chrome/common/extensions/docs/server2/test_data/api_data_source/canned_trunk_fs.py
index e47e927..27d45f5 100644
--- a/chrome/common/extensions/docs/server2/test_data/api_data_source/canned_trunk_fs.py
+++ b/chrome/common/extensions/docs/server2/test_data/api_data_source/canned_trunk_fs.py
@@ -182,7 +182,9 @@ CANNED_TRUNK_FS_DATA = {
}
]
}
- })
+ }),
+ 'manifest.json': '{}',
+ 'permissions.json': '{}'
},
'private': {
'intro_tables': {
diff --git a/chrome/common/extensions/docs/server2/test_data/canned_data.py b/chrome/common/extensions/docs/server2/test_data/canned_data.py
index 143da00..fabbf99 100644
--- a/chrome/common/extensions/docs/server2/test_data/canned_data.py
+++ b/chrome/common/extensions/docs/server2/test_data/canned_data.py
@@ -205,9 +205,9 @@ CANNED_API_FILE_SYSTEM_DATA = MoveAllTo(CHROME_EXTENSIONS, {
{ 'channel': 'beta',
'extension_types': ['extension']
},
- # whitelist
{ 'channel': 'stable',
- 'extension_types': ['extension']
+ 'extension_types': ['extension'],
+ 'whitelist': ['aaa']
},
],
'falseBetaAPI': {
@@ -370,8 +370,7 @@ CANNED_API_FILE_SYSTEM_DATA = MoveAllTo(CHROME_EXTENSIONS, {
},
'declarativeWebRequest': [
{ 'channel': 'beta' },
- # whitelist
- { 'channel': 'stable'}
+ { 'channel': 'stable', 'whitelist': ['aaa'] }
],
'downloads': {
'channel': 'beta'
@@ -500,8 +499,7 @@ CANNED_API_FILE_SYSTEM_DATA = MoveAllTo(CHROME_EXTENSIONS, {
},
'declarativeWebRequest': [
{ 'channel': 'beta' },
- # whitelist
- { 'channel': 'stable'}
+ { 'channel': 'stable', 'whitelist': ['aaa'] }
],
'downloads': {
'channel': 'dev'
@@ -614,8 +612,7 @@ CANNED_API_FILE_SYSTEM_DATA = MoveAllTo(CHROME_EXTENSIONS, {
},
'declarativeWebRequest': [
{ 'channel': 'beta' },
- # whitelist
- { 'channel': 'stable'}
+ { 'channel': 'stable', 'whitelist': ['aaa'] }
],
'systemInfo.display': {
'channel': 'stable'
diff --git a/chrome/common/extensions/docs/templates/intros/commands.html b/chrome/common/extensions/docs/templates/intros/commands.html
index 0416a57..6d9503b 100644
--- a/chrome/common/extensions/docs/templates/intros/commands.html
+++ b/chrome/common/extensions/docs/templates/intros/commands.html
@@ -1,8 +1,10 @@
<h2 id="manifest">Manifest</h2>
<p>
-You must set manifest_version to (at least) 2 to use this API.
+You must have a <code>"manifest_version"</code> of at least <code>2</code> to use this API.
</p>
+{{?is_apps +partials.warning_dev /}}
+
<h2 id="usage">Usage</h2>
<p>The commands API allows you to define specific commands, and bind them to a
default key combination. Each command your extension accepts must be listed in