| Index: chrome/common/extensions/docs/server2/api_data_source.py
|
| diff --git a/chrome/common/extensions/docs/server2/api_data_source.py b/chrome/common/extensions/docs/server2/api_data_source.py
|
| index 3fdd37587de23c6e4c8eab94d7958da966880ae4..e098dd988035a4cf80b0a3e73f8cda9b0f9bf0a4 100644
|
| --- a/chrome/common/extensions/docs/server2/api_data_source.py
|
| +++ b/chrome/common/extensions/docs/server2/api_data_source.py
|
| @@ -7,6 +7,9 @@ import logging
|
| import os
|
| from collections import defaultdict, Mapping
|
|
|
| +from branch_utility import BranchUtility
|
| +import svn_constants
|
| +from third_party.handlebar import Handlebar
|
| import third_party.json_schema_compiler.json_parse as json_parse
|
| import third_party.json_schema_compiler.model as model
|
| import third_party.json_schema_compiler.idl_schema as idl_schema
|
| @@ -103,9 +106,20 @@ class _JSCModel(object):
|
| """Uses a Model from the JSON Schema Compiler and generates a dict that
|
| a Handlebar template can use for a data source.
|
| """
|
| - def __init__(self, json, ref_resolver, disable_refs, idl=False):
|
| + def __init__(self,
|
| + json,
|
| + ref_resolver,
|
| + disable_refs,
|
| + availability_finder,
|
| + intro_cache,
|
| + template_data_source,
|
| + idl=False):
|
| self._ref_resolver = ref_resolver
|
| self._disable_refs = disable_refs
|
| + self._availability_finder = availability_finder
|
| + self._intro_tables = intro_cache.GetFromFile(
|
| + '%s/intro_tables.json' % svn_constants.JSON_PATH)
|
| + self._template_data_source = template_data_source
|
| clean_json = copy.deepcopy(json)
|
| if _RemoveNoDocs(clean_json):
|
| self._namespace = None
|
| @@ -132,13 +146,83 @@ class _JSCModel(object):
|
| return {}
|
| return {
|
| 'name': self._namespace.name,
|
| - 'description': self._namespace.description,
|
| 'types': self._GenerateTypes(self._namespace.types.values()),
|
| 'functions': self._GenerateFunctions(self._namespace.functions),
|
| 'events': self._GenerateEvents(self._namespace.events),
|
| - 'properties': self._GenerateProperties(self._namespace.properties)
|
| + 'properties': self._GenerateProperties(self._namespace.properties),
|
| + 'intro_list': self._GetIntroTableList(),
|
| + 'channel_warning': self._GetChannelWarning()
|
| }
|
|
|
| + def _GetIntroTableList(self):
|
| + """Create a generic data structure that can be traversed by the templates
|
| + to create an API intro table.
|
| + """
|
| + intro_list = [{
|
| + 'title': 'Description',
|
| + 'content': [
|
| + { 'text': self._FormatDescription(self._namespace.description) }
|
| + ]
|
| + }]
|
| +
|
| + if self._IsExperimental():
|
| + status = 'experimental'
|
| + version = None
|
| + else:
|
| + availability = self._GetApiAvailability()
|
| + status = availability.channel
|
| + version = availability.version
|
| + intro_list.append({
|
| + 'title': 'Availability',
|
| + 'content': [
|
| + {
|
| + 'partial': self._template_data_source.get(
|
| + 'intro_tables/%s_message.html' % status),
|
| + 'version': version
|
| + }
|
| + ]
|
| + })
|
| +
|
| + # Look up the API name in intro_tables.json, which is structured similarly
|
| + # to the data structure being created. If the name is found, loop through
|
| + # the attributes and add them to this structure.
|
| + table_info = self._intro_tables.get(self._namespace.name)
|
| + if table_info is None:
|
| + return intro_list
|
| +
|
| + # The intro tables have a specific ordering that needs to be followed.
|
| + ordering = ('Permissions', 'Samples', 'Learn More')
|
| +
|
| + for category in ordering:
|
| + if category not in table_info.keys():
|
| + continue
|
| + # Transform the 'partial' argument from the partial name to the
|
| + # template itself.
|
| + content = table_info[category]
|
| + for node in content:
|
| + # If there is a 'partial' argument and it hasn't already been
|
| + # converted to a Handlebar object, transform it to a template.
|
| + # TODO(epeterson/kalman): figure out why this check is necessary
|
| + # since it should be caching.
|
| + if 'partial' in node and not isinstance(node['partial'], Handlebar):
|
| + node['partial'] = self._template_data_source.get(node['partial'])
|
| + intro_list.append({
|
| + 'title': category,
|
| + 'content': content
|
| + })
|
| + return intro_list
|
| +
|
| + def _GetApiAvailability(self):
|
| + return self._availability_finder.GetApiAvailability(self._namespace.name)
|
| +
|
| + def _GetChannelWarning(self):
|
| + if not self._IsExperimental():
|
| + return { self._GetApiAvailability().channel: True }
|
| + return None
|
| +
|
| + def _IsExperimental(self):
|
| + return self._namespace.name.startswith('experimental')
|
| +
|
| def _GenerateTypes(self, types):
|
| return [self._GenerateType(t) for t in types]
|
|
|
| @@ -325,13 +409,13 @@ class APIDataSource(object):
|
| |compiled_fs_factory|, so the APIs can be plugged into templates.
|
| """
|
| class Factory(object):
|
| - def __init__(self, compiled_fs_factory, base_path):
|
| + def __init__(self,
|
| + compiled_fs_factory,
|
| + base_path,
|
| + availability_finder_factory):
|
| def create_compiled_fs(fn, category):
|
| return compiled_fs_factory.Create(fn, APIDataSource, category=category)
|
|
|
| - self._permissions_cache = create_compiled_fs(self._LoadPermissions,
|
| - 'permissions')
|
| -
|
| self._json_cache = create_compiled_fs(
|
| lambda api_name, api: self._LoadJsonAPI(api, False),
|
| 'json')
|
| @@ -353,7 +437,10 @@ class APIDataSource(object):
|
| self._names_cache = create_compiled_fs(self._GetAllNames, 'names')
|
|
|
| self._base_path = base_path
|
| -
|
| + self._availability_finder = availability_finder_factory.Create()
|
| + self._intro_cache = create_compiled_fs(
|
| + lambda _, json: json_parse.Parse(json),
|
| + 'intro-cache')
|
| # These must be set later via the SetFooDataSourceFactory methods.
|
| self._ref_resolver_factory = None
|
| self._samples_data_source_factory = None
|
| @@ -364,6 +451,10 @@ class APIDataSource(object):
|
| def SetReferenceResolverFactory(self, ref_resolver_factory):
|
| self._ref_resolver_factory = ref_resolver_factory
|
|
|
| + def SetTemplateDataSource(self, template_data_source_factory):
|
| + # This TemplateDataSource is only being used for fetching template data.
|
| + self._template_data_source = template_data_source_factory.Create(None, '')
|
| +
|
| def Create(self, request, disable_refs=False):
|
| """Create an APIDataSource. |disable_refs| specifies whether $ref's in
|
| APIs being processed by the |ToDict| method of _JSCModel follows $ref's
|
| @@ -381,8 +472,7 @@ class APIDataSource(object):
|
| if not disable_refs and self._ref_resolver_factory is None:
|
| logging.error('ReferenceResolver.Factory was never set in '
|
| 'APIDataSource.Factory.')
|
| - return APIDataSource(self._permissions_cache,
|
| - self._json_cache,
|
| + return APIDataSource(self._json_cache,
|
| self._idl_cache,
|
| self._json_cache_no_refs,
|
| self._idl_cache_no_refs,
|
| @@ -392,14 +482,14 @@ class APIDataSource(object):
|
| samples,
|
| disable_refs)
|
|
|
| - def _LoadPermissions(self, file_name, json_str):
|
| - return json_parse.Parse(json_str)
|
| -
|
| def _LoadJsonAPI(self, api, disable_refs):
|
| return _JSCModel(
|
| json_parse.Parse(api)[0],
|
| self._ref_resolver_factory.Create() if not disable_refs else None,
|
| - disable_refs).ToDict()
|
| + disable_refs,
|
| + self._availability_finder,
|
| + self._intro_cache,
|
| + self._template_data_source).ToDict()
|
|
|
| def _LoadIdlAPI(self, api, disable_refs):
|
| idl = idl_parser.IDLParser().ParseData(api)
|
| @@ -407,6 +497,9 @@ class APIDataSource(object):
|
| idl_schema.IDLSchema(idl).process()[0],
|
| self._ref_resolver_factory.Create() if not disable_refs else None,
|
| disable_refs,
|
| + self._availability_finder,
|
| + self._intro_cache,
|
| + self._template_data_source,
|
| idl=True).ToDict()
|
|
|
| def _GetIDLNames(self, base_dir, apis):
|
| @@ -420,7 +513,6 @@ class APIDataSource(object):
|
| if os.path.splitext(api)[1][1:] in exts]
|
|
|
| def __init__(self,
|
| - permissions_cache,
|
| json_cache,
|
| idl_cache,
|
| json_cache_no_refs,
|
| @@ -431,7 +523,6 @@ class APIDataSource(object):
|
| samples,
|
| disable_refs):
|
| self._base_path = base_path
|
| - self._permissions_cache = permissions_cache
|
| self._json_cache = json_cache
|
| self._idl_cache = idl_cache
|
| self._json_cache_no_refs = json_cache_no_refs
|
| @@ -441,51 +532,17 @@ class APIDataSource(object):
|
| self._samples = samples
|
| self._disable_refs = disable_refs
|
|
|
| - def _GetFeatureFile(self, filename):
|
| - perms = self._permissions_cache.GetFromFile('%s/%s' %
|
| - (self._base_path, filename))
|
| - return dict((model.UnixName(k), v) for k, v in perms.iteritems())
|
| -
|
| - def _GetFeatureData(self, path):
|
| - # Remove 'experimental_' from path name to match the keys in
|
| - # _permissions_features.json.
|
| - path = model.UnixName(path.replace('experimental_', ''))
|
| -
|
| - for filename in ['_permission_features.json', '_manifest_features.json']:
|
| - feature_data = self._GetFeatureFile(filename).get(path, None)
|
| - if feature_data is not None:
|
| - break
|
| -
|
| - # There are specific cases in which the feature is actually a list of
|
| - # features where only one needs to match; but currently these are only
|
| - # used to whitelist features for specific extension IDs. Filter those out.
|
| - if isinstance(feature_data, list):
|
| - feature_list = feature_data
|
| - feature_data = None
|
| - for single_feature in feature_list:
|
| - if 'whitelist' in single_feature:
|
| - continue
|
| - if feature_data is not None:
|
| - # Note: if you are seeing the exception below, add more heuristics as
|
| - # required to form a single feature.
|
| - raise ValueError('Multiple potential features match %s. I can\'t '
|
| - 'decide which one to use. Please help!' % path)
|
| - feature_data = single_feature
|
| -
|
| - if feature_data and feature_data['channel'] in ('trunk', 'dev', 'beta'):
|
| - feature_data[feature_data['channel']] = True
|
| - return feature_data
|
| -
|
| def _GenerateHandlebarContext(self, handlebar_dict, path):
|
| - handlebar_dict['permissions'] = self._GetFeatureData(path)
|
| handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples)
|
| return handlebar_dict
|
|
|
| def _GetAsSubdirectory(self, name):
|
| if name.startswith('experimental_'):
|
| parts = name[len('experimental_'):].split('_', 1)
|
| - parts[1] = 'experimental_%s' % parts[1]
|
| - return '/'.join(parts)
|
| + if len(parts) > 1:
|
| + parts[1] = 'experimental_%s' % parts[1]
|
| + return '/'.join(parts)
|
| + return '%s/%s' % (parts[0], name)
|
| return name.replace('_', '/', 1)
|
|
|
| def get(self, key):
|
|
|