api_models.py revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 os 6import posixpath 7 8from compiled_file_system import SingleFile, Unicode 9from extensions_paths import API 10from file_system import FileNotFoundError 11from future import Gettable, Future 12from schema_util import ProcessSchema 13from third_party.json_schema_compiler.model import Namespace, UnixName 14 15 16@SingleFile 17@Unicode 18def _CreateAPIModel(path, data): 19 schema = ProcessSchema(path, data)[0] 20 if not schema: return None 21 return Namespace(schema, schema['namespace']) 22 23 24class APIModels(object): 25 '''Tracks APIs and their Models. 26 ''' 27 28 def __init__(self, features_bundle, compiled_fs_factory, file_system): 29 self._features_bundle = features_bundle 30 self._model_cache = compiled_fs_factory.Create( 31 file_system, _CreateAPIModel, APIModels) 32 33 def GetNames(self): 34 # API names appear alongside some of their methods/events/etc in the 35 # features file. APIs are those which either implicitly or explicitly have 36 # no parent feature (e.g. app, app.window, and devtools.inspectedWindow are 37 # APIs; runtime.onConnectNative is not). 38 api_features = self._features_bundle.GetAPIFeatures().Get() 39 return [name for name, feature in api_features.iteritems() 40 if ('.' not in name or 41 name.rsplit('.', 1)[0] not in api_features or 42 feature.get('noparent'))] 43 44 def GetModel(self, api_name): 45 # Callers sometimes specify a filename which includes .json or .idl - if 46 # so, believe them. They may even include the 'api/' prefix. 47 if os.path.splitext(api_name)[1] in ('.json', '.idl'): 48 if not api_name.startswith(API): 49 api_name = posixpath.join(API, api_name) 50 return self._model_cache.GetFromFile(api_name) 51 52 assert not api_name.startswith(API) 53 54 # API names are given as declarativeContent and app.window but file names 55 # will be declarative_content and app_window. 56 file_name = UnixName(api_name).replace('.', '_') 57 # Devtools APIs are in API/devtools/ not API/, and have their 58 # "devtools" names removed from the file names. 59 basename = posixpath.basename(file_name) 60 if 'devtools_' in basename: 61 file_name = posixpath.join( 62 'devtools', file_name.replace(basename, 63 basename.replace('devtools_' , ''))) 64 65 futures = [self._model_cache.GetFromFile( 66 posixpath.join(API, '%s.%s' % (file_name, ext))) 67 for ext in ('json', 'idl')] 68 def resolve(): 69 for future in futures: 70 try: 71 return future.Get() 72 except FileNotFoundError: pass 73 # Propagate the first FileNotFoundError if neither were found. 74 futures[0].Get() 75 return Future(delegate=Gettable(resolve)) 76 77 def IterModels(self): 78 future_models = [(name, self.GetModel(name)) for name in self.GetNames()] 79 for name, future_model in future_models: 80 try: 81 model = future_model.Get() 82 except FileNotFoundError: 83 continue 84 if model: 85 yield name, model 86