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