blob: b5686a10dec94d95ef2a8d3a9c4986aa4efc7a66 [file] [log] [blame]
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import posixpath
from compiled_file_system import SingleFile, Unicode
from extensions_paths import API
from file_system import FileNotFoundError
from future import Gettable, Future
from schema_util import ProcessSchema
from third_party.json_schema_compiler.model import Namespace, UnixName
@SingleFile
@Unicode
def _CreateAPIModel(path, data):
schema = ProcessSchema(path, data)[0]
if not schema: return None
return Namespace(schema, schema['namespace'])
class APIModels(object):
'''Tracks APIs and their Models.
'''
def __init__(self, features_bundle, compiled_fs_factory, file_system):
self._features_bundle = features_bundle
self._model_cache = compiled_fs_factory.Create(
file_system, _CreateAPIModel, APIModels)
def GetNames(self):
# API names appear alongside some of their methods/events/etc in the
# features file. APIs are those which either implicitly or explicitly have
# no parent feature (e.g. app, app.window, and devtools.inspectedWindow are
# APIs; runtime.onConnectNative is not).
api_features = self._features_bundle.GetAPIFeatures().Get()
return [name for name, feature in api_features.iteritems()
if ('.' not in name or
name.rsplit('.', 1)[0] not in api_features or
feature.get('noparent'))]
def GetModel(self, api_name):
# Callers sometimes specify a filename which includes .json or .idl - if
# so, believe them. They may even include the 'api/' prefix.
if os.path.splitext(api_name)[1] in ('.json', '.idl'):
if not api_name.startswith(API + '/'):
api_name = posixpath.join(API, api_name)
return self._model_cache.GetFromFile(api_name)
assert not api_name.startswith(API)
# API names are given as declarativeContent and app.window but file names
# will be declarative_content and app_window.
file_name = UnixName(api_name).replace('.', '_')
# Devtools APIs are in API/devtools/ not API/, and have their
# "devtools" names removed from the file names.
basename = posixpath.basename(file_name)
if 'devtools_' in basename:
file_name = posixpath.join(
'devtools', file_name.replace(basename,
basename.replace('devtools_' , '')))
futures = [self._model_cache.GetFromFile('%s/%s.%s' % (API, file_name, ext))
for ext in ('json', 'idl')]
def resolve():
for future in futures:
try:
return future.Get()
except FileNotFoundError: pass
# Propagate the first FileNotFoundError if neither were found.
futures[0].Get()
return Future(delegate=Gettable(resolve))
def IterModels(self):
future_models = [(name, self.GetModel(name)) for name in self.GetNames()]
for name, future_model in future_models:
try:
model = future_model.Get()
except FileNotFoundError:
continue
if model:
yield name, model