11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# found in the LICENSE file. 41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import os 61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import posixpath 71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)from compiled_file_system import SingleFile, Unicode 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)from extensions_paths import API 101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from file_system import FileNotFoundError 111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from future import Gettable, Future 121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from schema_util import ProcessSchema 131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from third_party.json_schema_compiler.model import Namespace, UnixName 141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)@SingleFile 17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)@Unicode 181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def _CreateAPIModel(path, data): 19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) schema = ProcessSchema(path, data)[0] 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if not schema: return None 211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return Namespace(schema, schema['namespace']) 221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class APIModels(object): 251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) '''Tracks APIs and their Models. 261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ''' 271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) def __init__(self, features_bundle, compiled_fs_factory, file_system): 291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self._features_bundle = features_bundle 301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self._model_cache = compiled_fs_factory.Create( 311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) file_system, _CreateAPIModel, APIModels) 321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) def GetNames(self): 340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) # API names appear alongside some of their methods/events/etc in the 350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) # features file. APIs are those which either implicitly or explicitly have 360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) # no parent feature (e.g. app, app.window, and devtools.inspectedWindow are 370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) # APIs; runtime.onConnectNative is not). 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) api_features = self._features_bundle.GetAPIFeatures().Get() 390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return [name for name, feature in api_features.iteritems() 400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if ('.' not in name or 410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) name.rsplit('.', 1)[0] not in api_features or 420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) feature.get('noparent'))] 431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) def GetModel(self, api_name): 451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # Callers sometimes specify a filename which includes .json or .idl - if 461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # so, believe them. They may even include the 'api/' prefix. 471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if os.path.splitext(api_name)[1] in ('.json', '.idl'): 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if not api_name.startswith(API + '/'): 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) api_name = posixpath.join(API, api_name) 501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return self._model_cache.GetFromFile(api_name) 511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) assert not api_name.startswith(API) 531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # API names are given as declarativeContent and app.window but file names 551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # will be declarative_content and app_window. 561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) file_name = UnixName(api_name).replace('.', '_') 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) # Devtools APIs are in API/devtools/ not API/, and have their 581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # "devtools" names removed from the file names. 591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) basename = posixpath.basename(file_name) 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if 'devtools_' in basename: 611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) file_name = posixpath.join( 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 'devtools', file_name.replace(basename, 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) basename.replace('devtools_' , ''))) 641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) futures = [self._model_cache.GetFromFile('%s/%s.%s' % (API, file_name, ext)) 661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for ext in ('json', 'idl')] 671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) def resolve(): 681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for future in futures: 691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) try: 701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return future.Get() 711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) except FileNotFoundError: pass 721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # Propagate the first FileNotFoundError if neither were found. 731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) futures[0].Get() 741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return Future(delegate=Gettable(resolve)) 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def IterModels(self): 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) future_models = [(name, self.GetModel(name)) for name in self.GetNames()] 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for name, future_model in future_models: 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) try: 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) model = future_model.Get() 81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) except FileNotFoundError: 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) continue 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if model: 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) yield name, model 85